Skip to content

Commit c3f2207

Browse files
committed
fix: Fix reload errors due long matching conditions (nginx#1829)
Add `js_preload_directive` to read http match conditions Problem: A large number of match conditions for a single hostname/path cause reload errors with NGINX about being parameter being too long Solution: The solution is to use js_preload_objects to store the http_matches and then parse them through NGINX using NJS to map the correct match condition.
1 parent 379158e commit c3f2207

14 files changed

+350
-213
lines changed

internal/mode/static/nginx/config/generator.go

+27-10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ const (
2323

2424
// configVersionFile is the path to the config version configuration file.
2525
configVersionFile = httpFolder + "/config-version.conf"
26+
27+
// httpMatchVarsFile is the path to the http_match pairs configuration file.
28+
httpMatchVarsFile = httpFolder + "/matches.json"
2629
)
2730

2831
// ConfigFolders is a list of folders where NGINX configuration files are stored.
@@ -52,8 +55,13 @@ func NewGeneratorImpl(plus bool) GeneratorImpl {
5255
return GeneratorImpl{plus: plus}
5356
}
5457

58+
type executeResult struct {
59+
dest string
60+
data []byte
61+
}
62+
5563
// executeFunc is a function that generates NGINX configuration from internal representation.
56-
type executeFunc func(configuration dataplane.Configuration) []byte
64+
type executeFunc func(configuration dataplane.Configuration) []executeResult
5765

5866
// Generate generates NGINX configuration files from internal representation.
5967
// It is the responsibility of the caller to validate the configuration before calling this function.
@@ -66,7 +74,7 @@ func (g GeneratorImpl) Generate(conf dataplane.Configuration) []file.File {
6674
files = append(files, generatePEM(id, pair.Cert, pair.Key))
6775
}
6876

69-
files = append(files, g.generateHTTPConfig(conf))
77+
files = append(files, g.generateHTTPConfig(conf)...)
7078

7179
files = append(files, generateConfigVersion(conf.Version))
7280

@@ -106,24 +114,33 @@ func generateCertBundleFileName(id dataplane.CertBundleID) string {
106114
return filepath.Join(secretsFolder, string(id)+".crt")
107115
}
108116

109-
func (g GeneratorImpl) generateHTTPConfig(conf dataplane.Configuration) file.File {
110-
var c []byte
117+
func (g GeneratorImpl) generateHTTPConfig(conf dataplane.Configuration) []file.File {
118+
fileBytes := make(map[string][]byte)
119+
111120
for _, execute := range g.getExecuteFuncs() {
112-
c = append(c, execute(conf)...)
121+
results := execute(conf)
122+
for _, res := range results {
123+
fileBytes[res.dest] = append(fileBytes[res.dest], res.data...)
124+
}
113125
}
114126

115-
return file.File{
116-
Content: c,
117-
Path: httpConfigFile,
118-
Type: file.TypeRegular,
127+
files := make([]file.File, 0, len(fileBytes))
128+
for filepath, bytes := range fileBytes {
129+
files = append(files, file.File{
130+
Path: filepath,
131+
Content: bytes,
132+
Type: file.TypeRegular,
133+
})
119134
}
135+
136+
return files
120137
}
121138

122139
func (g GeneratorImpl) getExecuteFuncs() []executeFunc {
123140
return []executeFunc{
141+
executeServers,
124142
g.executeUpstreams,
125143
executeSplitClients,
126-
executeServers,
127144
executeMaps,
128145
}
129146
}

internal/mode/static/nginx/config/generator_test.go

+19-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package config_test
22

33
import (
44
"fmt"
5+
"sort"
56
"testing"
67

78
. "github.com/onsi/gomega"
@@ -70,13 +71,16 @@ func TestGenerate(t *testing.T) {
7071

7172
files := generator.Generate(conf)
7273

73-
g.Expect(files).To(HaveLen(4))
74+
g.Expect(files).To(HaveLen(5))
75+
arrange := func(i, j int) bool {
76+
return files[i].Path < files[j].Path
77+
}
78+
sort.Slice(files, arrange)
7479

75-
g.Expect(files[0]).To(Equal(file.File{
76-
Type: file.TypeSecret,
77-
Path: "/etc/nginx/secrets/test-keypair.pem",
78-
Content: []byte("test-cert\ntest-key"),
79-
}))
80+
g.Expect(files[0].Type).To(Equal(file.TypeRegular))
81+
g.Expect(files[0].Path).To(Equal("/etc/nginx/conf.d/config-version.conf"))
82+
configVersion := string(files[0].Content)
83+
g.Expect(configVersion).To(ContainSubstring(fmt.Sprintf("return 200 %d", conf.Version)))
8084

8185
g.Expect(files[1].Type).To(Equal(file.TypeRegular))
8286
g.Expect(files[1].Path).To(Equal("/etc/nginx/conf.d/http.conf"))
@@ -88,12 +92,18 @@ func TestGenerate(t *testing.T) {
8892
g.Expect(httpCfg).To(ContainSubstring("upstream"))
8993
g.Expect(httpCfg).To(ContainSubstring("split_clients"))
9094

95+
g.Expect(files[2].Path).To(Equal("/etc/nginx/conf.d/matches.json"))
9196
g.Expect(files[2].Type).To(Equal(file.TypeRegular))
92-
g.Expect(files[2].Path).To(Equal("/etc/nginx/conf.d/config-version.conf"))
93-
configVersion := string(files[2].Content)
94-
g.Expect(configVersion).To(ContainSubstring(fmt.Sprintf("return 200 %d", conf.Version)))
97+
expString := "{}"
98+
g.Expect(string(files[2].Content)).To(Equal(expString))
9599

96100
g.Expect(files[3].Path).To(Equal("/etc/nginx/secrets/test-certbundle.crt"))
97101
certBundle := string(files[3].Content)
98102
g.Expect(certBundle).To(Equal("test-cert"))
103+
104+
g.Expect(files[4]).To(Equal(file.File{
105+
Type: file.TypeSecret,
106+
Path: "/etc/nginx/secrets/test-keypair.pem",
107+
Content: []byte("test-cert\ntest-key"),
108+
}))
99109
}

internal/mode/static/nginx/config/http/config.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ type Server struct {
1212

1313
// Location holds all configuration for an HTTP location.
1414
type Location struct {
15-
Return *Return
16-
ProxySSLVerify *ProxySSLVerify
1715
Path string
1816
ProxyPass string
19-
HTTPMatchVar string
20-
Rewrites []string
17+
HTTPMatchKey string
2118
ProxySetHeaders []Header
19+
ProxySSLVerify *ProxySSLVerify
20+
Return *Return
21+
Rewrites []string
2222
}
2323

2424
// Header defines a HTTP header to be passed to the proxied server.

internal/mode/static/nginx/config/maps.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ import (
1010

1111
var mapsTemplate = gotemplate.Must(gotemplate.New("maps").Parse(mapsTemplateText))
1212

13-
func executeMaps(conf dataplane.Configuration) []byte {
13+
func executeMaps(conf dataplane.Configuration) []executeResult {
1414
maps := buildAddHeaderMaps(append(conf.HTTPServers, conf.SSLServers...))
15-
return execute(mapsTemplate, maps)
15+
result := executeResult{
16+
dest: httpConfigFile,
17+
data: execute(mapsTemplate, maps),
18+
}
19+
return []executeResult{result}
1620
}
1721

1822
func buildAddHeaderMaps(servers []dataplane.VirtualServer) []http.Map {

internal/mode/static/nginx/config/maps_test.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ func TestExecuteMaps(t *testing.T) {
8888
"map $http_upgrade $connection_upgrade {": 1,
8989
}
9090

91-
maps := string(executeMaps(conf))
91+
mapResult := executeMaps(conf)
92+
g.Expect(mapResult).To(HaveLen(1))
93+
maps := string(mapResult[0].data)
94+
g.Expect(mapResult[0].dest).To(Equal(httpConfigFile))
9295
for expSubStr, expCount := range expSubStrings {
9396
g.Expect(expCount).To(Equal(strings.Count(maps, expSubStr)))
9497
}

0 commit comments

Comments
 (0)