diff --git a/internal/controller/nginx/conf/nginx-plus.conf b/internal/controller/nginx/conf/nginx-plus.conf index 84be2a6691..f2b0ec0dc8 100644 --- a/internal/controller/nginx/conf/nginx-plus.conf +++ b/internal/controller/nginx/conf/nginx-plus.conf @@ -5,6 +5,10 @@ worker_processes auto; pid /var/run/nginx/nginx.pid; +events { + include /etc/nginx/events-includes/*.conf; +} + http { include /etc/nginx/conf.d/*.conf; include /etc/nginx/mime.types; diff --git a/internal/controller/nginx/conf/nginx.conf b/internal/controller/nginx/conf/nginx.conf index f98d7eaa6e..791994fdf8 100644 --- a/internal/controller/nginx/conf/nginx.conf +++ b/internal/controller/nginx/conf/nginx.conf @@ -5,6 +5,10 @@ worker_processes auto; pid /var/run/nginx/nginx.pid; +events { + include /etc/nginx/events-includes/*.conf; +} + http { include /etc/nginx/conf.d/*.conf; include /etc/nginx/mime.types; diff --git a/internal/controller/nginx/config/generator.go b/internal/controller/nginx/config/generator.go index 290185c315..6fa7602c04 100644 --- a/internal/controller/nginx/config/generator.go +++ b/internal/controller/nginx/config/generator.go @@ -38,6 +38,9 @@ const ( // For example, these files include load_module directives and snippets that target the main context. mainIncludesFolder = configFolder + "/main-includes" + // eventsIncludesFolder is the folder where NGINX events context configuration files are stored. + eventsIncludesFolder = configFolder + "/events-includes" + // secretsFolder is the folder where secrets (like TLS certs/keys) are stored. secretsFolder = configFolder + "/secrets" @@ -56,6 +59,9 @@ const ( // mainIncludesConfigFile is the path to the file containing NGINX configuration in the main context. mainIncludesConfigFile = mainIncludesFolder + "/main.conf" + // eventsIncludesConfigFile is the path to the file containing NGINX events configuration. + eventsIncludesConfigFile = eventsIncludesFolder + "/events.conf" + // mgmtIncludesFile is the path to the file containing the NGINX Plus mgmt config. mgmtIncludesFile = mainIncludesFolder + "/mgmt.conf" @@ -196,6 +202,7 @@ func (g GeneratorImpl) getExecuteFuncs( ) []executeFunc { return []executeFunc{ executeMainConfig, + executeEventsConfig, executeBaseHTTPConfig, g.newExecuteServersFunc(generator, keepAliveCheck), newExecuteUpstreamsFunc(upstreams), diff --git a/internal/controller/nginx/config/generator_test.go b/internal/controller/nginx/config/generator_test.go index 1340834d03..c77b22cb99 100644 --- a/internal/controller/nginx/config/generator_test.go +++ b/internal/controller/nginx/config/generator_test.go @@ -147,7 +147,7 @@ func TestGenerate(t *testing.T) { files := generator.Generate(conf) - g.Expect(files).To(HaveLen(17)) + g.Expect(files).To(HaveLen(18)) arrange := func(i, j int) bool { return files[i].Meta.Name < files[j].Meta.Name } @@ -158,6 +158,7 @@ func TestGenerate(t *testing.T) { /etc/nginx/conf.d/http.conf /etc/nginx/conf.d/matches.json /etc/nginx/conf.d/plus-api.conf + /etc/nginx/events-includes/events.conf /etc/nginx/includes/http_snippet1.conf /etc/nginx/includes/http_snippet2.conf /etc/nginx/includes/main_snippet1.conf @@ -211,28 +212,32 @@ func TestGenerate(t *testing.T) { g.Expect(httpCfg).To(ContainSubstring("deny all;")) g.Expect(httpCfg).To(ContainSubstring("location = /dashboard.html {}")) + // events config file + g.Expect(files[3].Meta.Name).To(Equal("/etc/nginx/events-includes/events.conf")) + g.Expect(string(files[3].Contents)).To(ContainSubstring("worker_connections")) + // snippet include files // content is not checked in this test. - g.Expect(files[3].Meta.Name).To(Equal("/etc/nginx/includes/http_snippet1.conf")) - g.Expect(files[4].Meta.Name).To(Equal("/etc/nginx/includes/http_snippet2.conf")) - g.Expect(files[5].Meta.Name).To(Equal("/etc/nginx/includes/main_snippet1.conf")) - g.Expect(files[6].Meta.Name).To(Equal("/etc/nginx/includes/main_snippet2.conf")) + g.Expect(files[4].Meta.Name).To(Equal("/etc/nginx/includes/http_snippet1.conf")) + g.Expect(files[5].Meta.Name).To(Equal("/etc/nginx/includes/http_snippet2.conf")) + g.Expect(files[6].Meta.Name).To(Equal("/etc/nginx/includes/main_snippet1.conf")) + g.Expect(files[7].Meta.Name).To(Equal("/etc/nginx/includes/main_snippet2.conf")) - g.Expect(files[7].Meta.Name).To(Equal("/etc/nginx/main-includes/deployment_ctx.json")) - deploymentCtx := string(files[7].Contents) + g.Expect(files[8].Meta.Name).To(Equal("/etc/nginx/main-includes/deployment_ctx.json")) + deploymentCtx := string(files[8].Contents) g.Expect(deploymentCtx).To(ContainSubstring("\"integration\":\"ngf\"")) g.Expect(deploymentCtx).To(ContainSubstring("\"cluster_id\":\"test-uid\"")) g.Expect(deploymentCtx).To(ContainSubstring("\"installation_id\":\"test-uid-replicaSet\"")) g.Expect(deploymentCtx).To(ContainSubstring("\"cluster_node_count\":1")) - g.Expect(files[8].Meta.Name).To(Equal("/etc/nginx/main-includes/main.conf")) - mainConfStr := string(files[8].Contents) + g.Expect(files[9].Meta.Name).To(Equal("/etc/nginx/main-includes/main.conf")) + mainConfStr := string(files[9].Contents) g.Expect(mainConfStr).To(ContainSubstring("load_module modules/ngx_otel_module.so;")) g.Expect(mainConfStr).To(ContainSubstring("include /etc/nginx/includes/main_snippet1.conf;")) g.Expect(mainConfStr).To(ContainSubstring("include /etc/nginx/includes/main_snippet2.conf;")) - g.Expect(files[9].Meta.Name).To(Equal("/etc/nginx/main-includes/mgmt.conf")) - mgmtConf := string(files[9].Contents) + g.Expect(files[10].Meta.Name).To(Equal("/etc/nginx/main-includes/mgmt.conf")) + mgmtConf := string(files[10].Contents) g.Expect(mgmtConf).To(ContainSubstring("usage_report endpoint=test-endpoint")) g.Expect(mgmtConf).To(ContainSubstring("license_token /etc/nginx/secrets/license.jwt")) g.Expect(mgmtConf).To(ContainSubstring("deployment_context /etc/nginx/main-includes/deployment_ctx.json")) @@ -240,23 +245,23 @@ func TestGenerate(t *testing.T) { g.Expect(mgmtConf).To(ContainSubstring("ssl_certificate /etc/nginx/secrets/mgmt-tls.crt")) g.Expect(mgmtConf).To(ContainSubstring("ssl_certificate_key /etc/nginx/secrets/mgmt-tls.key")) - g.Expect(files[10].Meta.Name).To(Equal("/etc/nginx/secrets/license.jwt")) - g.Expect(string(files[10].Contents)).To(Equal("license")) + g.Expect(files[11].Meta.Name).To(Equal("/etc/nginx/secrets/license.jwt")) + g.Expect(string(files[11].Contents)).To(Equal("license")) - g.Expect(files[11].Meta.Name).To(Equal("/etc/nginx/secrets/mgmt-ca.crt")) - g.Expect(string(files[11].Contents)).To(Equal("ca")) + g.Expect(files[12].Meta.Name).To(Equal("/etc/nginx/secrets/mgmt-ca.crt")) + g.Expect(string(files[12].Contents)).To(Equal("ca")) - g.Expect(files[12].Meta.Name).To(Equal("/etc/nginx/secrets/mgmt-tls.crt")) - g.Expect(string(files[12].Contents)).To(Equal("cert")) + g.Expect(files[13].Meta.Name).To(Equal("/etc/nginx/secrets/mgmt-tls.crt")) + g.Expect(string(files[13].Contents)).To(Equal("cert")) - g.Expect(files[13].Meta.Name).To(Equal("/etc/nginx/secrets/mgmt-tls.key")) - g.Expect(string(files[13].Contents)).To(Equal("key")) + g.Expect(files[14].Meta.Name).To(Equal("/etc/nginx/secrets/mgmt-tls.key")) + g.Expect(string(files[14].Contents)).To(Equal("key")) - g.Expect(files[14].Meta.Name).To(Equal("/etc/nginx/secrets/test-certbundle.crt")) - certBundle := string(files[14].Contents) + g.Expect(files[15].Meta.Name).To(Equal("/etc/nginx/secrets/test-certbundle.crt")) + certBundle := string(files[15].Contents) g.Expect(certBundle).To(Equal("test-cert")) - g.Expect(files[15]).To(Equal(agent.File{ + g.Expect(files[16]).To(Equal(agent.File{ Meta: &pb.FileMeta{ Name: "/etc/nginx/secrets/test-keypair.pem", Hash: filesHelper.GenerateHash([]byte("test-cert\ntest-key")), @@ -266,9 +271,9 @@ func TestGenerate(t *testing.T) { Contents: []byte("test-cert\ntest-key"), })) - g.Expect(files[16].Meta.Name).To(Equal("/etc/nginx/stream-conf.d/stream.conf")) - g.Expect(files[16].Meta.Permissions).To(Equal(file.RegularFileMode)) - streamCfg := string(files[16].Contents) + g.Expect(files[17].Meta.Name).To(Equal("/etc/nginx/stream-conf.d/stream.conf")) + g.Expect(files[17].Meta.Permissions).To(Equal(file.RegularFileMode)) + streamCfg := string(files[17].Contents) g.Expect(streamCfg).To(ContainSubstring("listen unix:/var/run/nginx/app.example.com-443.sock")) g.Expect(streamCfg).To(ContainSubstring("listen 443")) g.Expect(streamCfg).To(ContainSubstring("app.example.com unix:/var/run/nginx/app.example.com-443.sock")) diff --git a/internal/controller/nginx/config/main_config.go b/internal/controller/nginx/config/main_config.go index fa10606f22..1fb7991225 100644 --- a/internal/controller/nginx/config/main_config.go +++ b/internal/controller/nginx/config/main_config.go @@ -15,8 +15,9 @@ import ( ) var ( - mainConfigTemplate = gotemplate.Must(gotemplate.New("main").Parse(mainConfigTemplateText)) - mgmtConfigTemplate = gotemplate.Must(gotemplate.New("mgmt").Parse(mgmtConfigTemplateText)) + mainConfigTemplate = gotemplate.Must(gotemplate.New("main").Parse(mainConfigTemplateText)) + mgmtConfigTemplate = gotemplate.Must(gotemplate.New("mgmt").Parse(mgmtConfigTemplateText)) + eventsConfigTemplate = gotemplate.Must(gotemplate.New("events").Parse(eventsConfigTemplateText)) ) type mainConfig struct { @@ -42,6 +43,17 @@ func executeMainConfig(conf dataplane.Configuration) []executeResult { return results } +func executeEventsConfig(conf dataplane.Configuration) []executeResult { + eventsData := helpers.MustExecuteTemplate(eventsConfigTemplate, conf) + + return []executeResult{ + { + dest: eventsIncludesConfigFile, + data: eventsData, + }, + } +} + type mgmtConf struct { Endpoint string Resolver string diff --git a/internal/controller/nginx/config/main_config_template.go b/internal/controller/nginx/config/main_config_template.go index 103aa3fc14..ae668431a8 100644 --- a/internal/controller/nginx/config/main_config_template.go +++ b/internal/controller/nginx/config/main_config_template.go @@ -7,15 +7,16 @@ load_module modules/ngx_otel_module.so; error_log stderr {{ .Conf.Logging.ErrorLevel }}; -events { - worker_connections {{ .Conf.WorkerConnections }}; -} {{ range $i := .Includes -}} include {{ $i.Name }}; {{ end -}} ` +const eventsConfigTemplateText = ` +worker_connections {{ .WorkerConnections }}; +` + const mgmtConfigTemplateText = ` mgmt { {{- if .Endpoint }} diff --git a/internal/controller/nginx/config/main_config_test.go b/internal/controller/nginx/config/main_config_test.go index dc8861da15..132084afa7 100644 --- a/internal/controller/nginx/config/main_config_test.go +++ b/internal/controller/nginx/config/main_config_test.go @@ -173,8 +173,44 @@ func TestExecuteMainConfig_WorkerConnections(t *testing.T) { res := executeMainConfig(test.conf) g.Expect(res).To(HaveLen(1)) g.Expect(res[0].dest).To(Equal(mainIncludesConfigFile)) + g.Expect(string(res[0].data)).To(ContainSubstring("error_log stderr")) + }) + } +} + +func TestExecuteEventsConfig_WorkerConnections(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + expWorkerConnections string + conf dataplane.Configuration + }{ + { + name: "custom worker connections", + conf: dataplane.Configuration{ + WorkerConnections: 2048, + }, + expWorkerConnections: "worker_connections 2048;", + }, + { + name: "default worker connections", + conf: dataplane.Configuration{ + WorkerConnections: dataplane.DefaultWorkerConnections, + }, + expWorkerConnections: "worker_connections 1024;", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + res := executeEventsConfig(test.conf) + g.Expect(res).To(HaveLen(1)) + g.Expect(res[0].dest).To(Equal(eventsIncludesConfigFile)) g.Expect(string(res[0].data)).To(ContainSubstring(test.expWorkerConnections)) - g.Expect(string(res[0].data)).To(ContainSubstring("events {")) }) } } diff --git a/internal/controller/provisioner/objects.go b/internal/controller/provisioner/objects.go index 86908a7dc1..6abe6f230c 100644 --- a/internal/controller/provisioner/objects.go +++ b/internal/controller/provisioner/objects.go @@ -396,6 +396,11 @@ func (p *NginxProvisioner) buildNginxConfigMaps( "WorkerConnections": workerConnections, } + // Create events ConfigMap data using template + eventsFields := map[string]interface{}{ + "WorkerConnections": workerConnections, + } + bootstrapCM := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: ngxIncludesConfigMapName, @@ -404,7 +409,8 @@ func (p *NginxProvisioner) buildNginxConfigMaps( Annotations: objectMeta.Annotations, }, Data: map[string]string{ - "main.conf": string(helpers.MustExecuteTemplate(mainTemplate, mainFields)), + "main.conf": string(helpers.MustExecuteTemplate(mainTemplate, mainFields)), + "events.conf": string(helpers.MustExecuteTemplate(eventsTemplate, eventsFields)), }, } @@ -826,6 +832,7 @@ func (p *NginxProvisioner) buildNginxPodTemplateSpec( {MountPath: "/etc/nginx/conf.d", Name: "nginx-conf"}, {MountPath: "/etc/nginx/stream-conf.d", Name: "nginx-stream-conf"}, {MountPath: "/etc/nginx/main-includes", Name: "nginx-main-includes"}, + {MountPath: "/etc/nginx/events-includes", Name: "nginx-events-includes"}, {MountPath: "/etc/nginx/secrets", Name: "nginx-secrets"}, {MountPath: "/var/run/nginx", Name: "nginx-run"}, {MountPath: "/var/cache/nginx", Name: "nginx-cache"}, @@ -845,6 +852,8 @@ func (p *NginxProvisioner) buildNginxPodTemplateSpec( "--destination", "/etc/nginx-agent", "--source", "/includes/main.conf", "--destination", "/etc/nginx/main-includes", + "--source", "/includes/events.conf", + "--destination", "/etc/nginx/events-includes", }, Env: []corev1.EnvVar{ { @@ -861,6 +870,7 @@ func (p *NginxProvisioner) buildNginxPodTemplateSpec( {MountPath: "/etc/nginx-agent", Name: "nginx-agent"}, {MountPath: "/includes", Name: "nginx-includes-bootstrap"}, {MountPath: "/etc/nginx/main-includes", Name: "nginx-main-includes"}, + {MountPath: "/etc/nginx/events-includes", Name: "nginx-events-includes"}, }, SecurityContext: &corev1.SecurityContext{ Capabilities: &corev1.Capabilities{ @@ -927,6 +937,7 @@ func (p *NginxProvisioner) buildNginxPodTemplateSpec( {Name: "nginx-conf", VolumeSource: emptyDirVolumeSource}, {Name: "nginx-stream-conf", VolumeSource: emptyDirVolumeSource}, {Name: "nginx-main-includes", VolumeSource: emptyDirVolumeSource}, + {Name: "nginx-events-includes", VolumeSource: emptyDirVolumeSource}, {Name: "nginx-secrets", VolumeSource: emptyDirVolumeSource}, {Name: "nginx-run", VolumeSource: emptyDirVolumeSource}, {Name: "nginx-cache", VolumeSource: emptyDirVolumeSource}, diff --git a/internal/controller/provisioner/objects_test.go b/internal/controller/provisioner/objects_test.go index 08f6f629ec..600ff5d87f 100644 --- a/internal/controller/provisioner/objects_test.go +++ b/internal/controller/provisioner/objects_test.go @@ -1275,7 +1275,7 @@ func TestBuildNginxConfigMaps_WorkerConnections(t *testing.T) { bootstrapCM, ok := configMaps[0].(*corev1.ConfigMap) g.Expect(ok).To(BeTrue()) - g.Expect(bootstrapCM.Data["main.conf"]).To(ContainSubstring("worker_connections 1024;")) + g.Expect(bootstrapCM.Data["events.conf"]).To(ContainSubstring("worker_connections 1024;")) // Test with default worker connections (empty NginxProxy config) nProxyCfgEmpty := &graph.EffectiveNginxProxy{} @@ -1284,7 +1284,7 @@ func TestBuildNginxConfigMaps_WorkerConnections(t *testing.T) { bootstrapCM, ok = configMaps[0].(*corev1.ConfigMap) g.Expect(ok).To(BeTrue()) - g.Expect(bootstrapCM.Data["main.conf"]).To(ContainSubstring("worker_connections 1024;")) + g.Expect(bootstrapCM.Data["events.conf"]).To(ContainSubstring("worker_connections 1024;")) // Test with custom worker connections nProxyCfg := &graph.EffectiveNginxProxy{ @@ -1296,7 +1296,7 @@ func TestBuildNginxConfigMaps_WorkerConnections(t *testing.T) { bootstrapCM, ok = configMaps[0].(*corev1.ConfigMap) g.Expect(ok).To(BeTrue()) - g.Expect(bootstrapCM.Data["main.conf"]).To(ContainSubstring("worker_connections 2048;")) + g.Expect(bootstrapCM.Data["events.conf"]).To(ContainSubstring("worker_connections 2048;")) } func TestBuildNginxConfigMaps_AgentFields(t *testing.T) { diff --git a/internal/controller/provisioner/templates.go b/internal/controller/provisioner/templates.go index c6eb828377..78945d53f7 100644 --- a/internal/controller/provisioner/templates.go +++ b/internal/controller/provisioner/templates.go @@ -3,17 +3,17 @@ package provisioner import gotemplate "text/template" var ( - mainTemplate = gotemplate.Must(gotemplate.New("main").Parse(mainTemplateText)) - mgmtTemplate = gotemplate.Must(gotemplate.New("mgmt").Parse(mgmtTemplateText)) - agentTemplate = gotemplate.Must(gotemplate.New("agent").Parse(agentTemplateText)) + mainTemplate = gotemplate.Must(gotemplate.New("main").Parse(mainTemplateText)) + mgmtTemplate = gotemplate.Must(gotemplate.New("mgmt").Parse(mgmtTemplateText)) + agentTemplate = gotemplate.Must(gotemplate.New("agent").Parse(agentTemplateText)) + eventsTemplate = gotemplate.Must(gotemplate.New("events").Parse(eventsTemplateText)) ) const mainTemplateText = ` -error_log stderr {{ .ErrorLevel }}; +error_log stderr {{ .ErrorLevel }};` -events { - worker_connections {{ .WorkerConnections }}; -}` +const eventsTemplateText = ` +worker_connections {{ .WorkerConnections }};` const mgmtTemplateText = `mgmt { {{- if .UsageEndpoint }}