diff --git a/internal/mode/static/nginx/config/generator.go b/internal/mode/static/nginx/config/generator.go index 3d229c3e1c..be2877bf29 100644 --- a/internal/mode/static/nginx/config/generator.go +++ b/internal/mode/static/nginx/config/generator.go @@ -169,12 +169,12 @@ func (g GeneratorImpl) generateHTTPConfig( func (g GeneratorImpl) getExecuteFuncs(generator policies.Generator) []executeFunc { return []executeFunc{ executeBaseHTTPConfig, - newExecuteServersFunc(generator), + g.newExecuteServersFunc(generator), g.executeUpstreams, executeSplitClients, executeMaps, executeTelemetry, - executeStreamServers, + g.executeStreamServers, g.executeStreamUpstreams, executeStreamMaps, } diff --git a/internal/mode/static/nginx/config/http/config.go b/internal/mode/static/nginx/config/http/config.go index f2fb813d6d..4e26604196 100644 --- a/internal/mode/static/nginx/config/http/config.go +++ b/internal/mode/static/nginx/config/http/config.go @@ -111,6 +111,7 @@ type ProxySSLVerify struct { type ServerConfig struct { Servers []Server IPFamily shared.IPFamily + Plus bool } // Include defines a file that's included via the include directive. diff --git a/internal/mode/static/nginx/config/servers.go b/internal/mode/static/nginx/config/servers.go index 6fd3d4610f..4ced814bd0 100644 --- a/internal/mode/static/nginx/config/servers.go +++ b/internal/mode/static/nginx/config/servers.go @@ -59,18 +59,19 @@ var grpcBaseHeaders = []http.Header{ }, } -func newExecuteServersFunc(generator policies.Generator) executeFunc { +func (g GeneratorImpl) newExecuteServersFunc(generator policies.Generator) executeFunc { return func(configuration dataplane.Configuration) []executeResult { - return executeServers(configuration, generator) + return g.executeServers(configuration, generator) } } -func executeServers(conf dataplane.Configuration, generator policies.Generator) []executeResult { +func (g GeneratorImpl) executeServers(conf dataplane.Configuration, generator policies.Generator) []executeResult { servers, httpMatchPairs := createServers(conf.HTTPServers, conf.SSLServers, conf.TLSPassthroughServers, generator) serverConfig := http.ServerConfig{ Servers: servers, IPFamily: getIPFamily(conf.BaseHTTPConfig), + Plus: g.plus, } serverResult := executeResult{ diff --git a/internal/mode/static/nginx/config/servers_template.go b/internal/mode/static/nginx/config/servers_template.go index 80be670045..02b8fae97f 100644 --- a/internal/mode/static/nginx/config/servers_template.go +++ b/internal/mode/static/nginx/config/servers_template.go @@ -2,7 +2,7 @@ package config const serversTemplateText = ` js_preload_object matches from /etc/nginx/conf.d/matches.json; -{{- range $s := .Servers -}} +{{ range $s := .Servers -}} {{ if $s.IsDefaultSSL -}} server { {{- if or ($.IPFamily.IPv4) ($s.IsSocket) }} @@ -52,9 +52,13 @@ server { server_name {{ $s.ServerName }}; + {{- if $.Plus }} + status_zone {{ $s.ServerName }}; + {{- end }} + {{- range $i := $s.Includes }} include {{ $i.Name }}; - {{ end -}} + {{- end }} {{ range $l := $s.Locations }} location {{ $l.Path }} { @@ -85,6 +89,7 @@ server { include /etc/nginx/grpc-error-pages.conf; {{- end }} + proxy_http_version 1.1; {{- if $l.ProxyPass -}} {{ range $h := $l.ProxySetHeaders }} {{ $proxyOrGRPC }}_set_header {{ $h.Name }} "{{ $h.Value }}"; @@ -100,7 +105,6 @@ server { {{ range $h := $l.ResponseHeaders.Remove }} proxy_hide_header {{ $h }}; {{- end }} - proxy_http_version 1.1; {{- if $l.ProxySSLVerify }} {{ $proxyOrGRPC }}_ssl_server_name on; {{ $proxyOrGRPC }}_ssl_verify on; diff --git a/internal/mode/static/nginx/config/servers_test.go b/internal/mode/static/nginx/config/servers_test.go index 2ef832ea09..a912e6f2bc 100644 --- a/internal/mode/static/nginx/config/servers_test.go +++ b/internal/mode/static/nginx/config/servers_test.go @@ -97,6 +97,7 @@ func TestExecuteServers(t *testing.T) { "ssl_certificate /etc/nginx/secrets/test-keypair.pem;": 2, "ssl_certificate_key /etc/nginx/secrets/test-keypair.pem;": 2, "proxy_ssl_server_name on;": 1, + "status_zone": 0, } type assertion func(g *WithT, data string) @@ -131,7 +132,8 @@ func TestExecuteServers(t *testing.T) { }, }) - results := executeServers(conf, fakeGenerator) + gen := GeneratorImpl{} + results := gen.executeServers(conf, fakeGenerator) g.Expect(results).To(HaveLen(len(expectedResults))) for _, res := range results { @@ -142,7 +144,7 @@ func TestExecuteServers(t *testing.T) { } } -func TestExecuteServersForIPFamily(t *testing.T) { +func TestExecuteServers_IPFamily(t *testing.T) { httpServers := []dataplane.VirtualServer{ { IsDefault: true, @@ -256,6 +258,7 @@ func TestExecuteServersForIPFamily(t *testing.T) { "listen [::]:8080;": 1, "listen [::]:8443 ssl default_server;": 1, "listen [::]:8443 ssl;": 1, + "status_zone": 0, }, }, } @@ -263,7 +266,9 @@ func TestExecuteServersForIPFamily(t *testing.T) { for _, test := range tests { t.Run(test.msg, func(t *testing.T) { g := NewWithT(t) - results := executeServers(test.config, &policiesfakes.FakeGenerator{}) + + gen := GeneratorImpl{} + results := gen.executeServers(test.config, &policiesfakes.FakeGenerator{}) g.Expect(results).To(HaveLen(2)) serverConf := string(results[0].data) httpMatchConf := string(results[1].data) @@ -276,6 +281,44 @@ func TestExecuteServersForIPFamily(t *testing.T) { } } +func TestExecuteServers_Plus(t *testing.T) { + config := dataplane.Configuration{ + HTTPServers: []dataplane.VirtualServer{ + { + Hostname: "example.com", + }, + { + Hostname: "example2.com", + }, + }, + SSLServers: []dataplane.VirtualServer{ + { + Hostname: "example.com", + SSL: &dataplane.SSL{ + KeyPairID: "test-keypair", + }, + }, + }, + } + + expectedHTTPConfig := map[string]int{ + "status_zone example.com;": 2, + "status_zone example2.com;": 1, + } + + g := NewWithT(t) + + gen := GeneratorImpl{plus: true} + results := gen.executeServers(config, &policiesfakes.FakeGenerator{}) + g.Expect(results).To(HaveLen(2)) + + serverConf := string(results[0].data) + + for expSubStr, expCount := range expectedHTTPConfig { + g.Expect(strings.Count(serverConf, expSubStr)).To(Equal(expCount)) + } +} + func TestExecuteForDefaultServers(t *testing.T) { testcases := []struct { msg string @@ -347,7 +390,8 @@ func TestExecuteForDefaultServers(t *testing.T) { t.Run(tc.msg, func(t *testing.T) { g := NewWithT(t) - serverResults := executeServers(tc.conf, &policiesfakes.FakeGenerator{}) + gen := GeneratorImpl{} + serverResults := gen.executeServers(tc.conf, &policiesfakes.FakeGenerator{}) g.Expect(serverResults).To(HaveLen(2)) serverConf := string(serverResults[0].data) httpMatchConf := string(serverResults[1].data) diff --git a/internal/mode/static/nginx/config/stream/config.go b/internal/mode/static/nginx/config/stream/config.go index 19a1ae7994..6a3687306c 100644 --- a/internal/mode/static/nginx/config/stream/config.go +++ b/internal/mode/static/nginx/config/stream/config.go @@ -5,6 +5,7 @@ import "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/conf // Server holds all configuration for a stream server. type Server struct { Listen string + StatusZone string ProxyPass string Pass string SSLPreread bool @@ -27,4 +28,5 @@ type UpstreamServer struct { type ServerConfig struct { Servers []Server IPFamily shared.IPFamily + Plus bool } diff --git a/internal/mode/static/nginx/config/stream_servers.go b/internal/mode/static/nginx/config/stream_servers.go index 6c33f5a609..b655818698 100644 --- a/internal/mode/static/nginx/config/stream_servers.go +++ b/internal/mode/static/nginx/config/stream_servers.go @@ -11,12 +11,13 @@ import ( var streamServersTemplate = gotemplate.Must(gotemplate.New("streamServers").Parse(streamServersTemplateText)) -func executeStreamServers(conf dataplane.Configuration) []executeResult { +func (g GeneratorImpl) executeStreamServers(conf dataplane.Configuration) []executeResult { streamServers := createStreamServers(conf) streamServerConfig := stream.ServerConfig{ Servers: streamServers, IPFamily: getIPFamily(conf.BaseHTTPConfig), + Plus: g.plus, } streamServerResult := executeResult{ @@ -46,9 +47,10 @@ func createStreamServers(conf dataplane.Configuration) []stream.Server { if u, ok := upstreams[server.UpstreamName]; ok && server.UpstreamName != "" { if server.Hostname != "" && len(u.Endpoints) > 0 { streamServers = append(streamServers, stream.Server{ - Listen: getSocketNameTLS(server.Port, server.Hostname), - ProxyPass: server.UpstreamName, - IsSocket: true, + Listen: getSocketNameTLS(server.Port, server.Hostname), + StatusZone: server.Hostname, + ProxyPass: server.UpstreamName, + IsSocket: true, }) } } @@ -60,6 +62,7 @@ func createStreamServers(conf dataplane.Configuration) []stream.Server { portSet[server.Port] = struct{}{} streamServers = append(streamServers, stream.Server{ Listen: fmt.Sprint(server.Port), + StatusZone: server.Hostname, Pass: getTLSPassthroughVarName(server.Port), SSLPreread: true, }) diff --git a/internal/mode/static/nginx/config/stream_servers_template.go b/internal/mode/static/nginx/config/stream_servers_template.go index 66f12f5858..4b619a9e0e 100644 --- a/internal/mode/static/nginx/config/stream_servers_template.go +++ b/internal/mode/static/nginx/config/stream_servers_template.go @@ -9,6 +9,11 @@ server { {{- if and ($.IPFamily.IPv6) (not $s.IsSocket) }} listen [::]:{{ $s.Listen }}; {{- end }} + + {{- if $.Plus }} + status_zone {{ $s.StatusZone }}; + {{- end }} + {{- if $s.ProxyPass }} proxy_pass {{ $s.ProxyPass }}; {{- end }} diff --git a/internal/mode/static/nginx/config/stream_servers_test.go b/internal/mode/static/nginx/config/stream_servers_test.go index 20f1c201d6..1e08874c8f 100644 --- a/internal/mode/static/nginx/config/stream_servers_test.go +++ b/internal/mode/static/nginx/config/stream_servers_test.go @@ -58,10 +58,12 @@ func TestExecuteStreamServers(t *testing.T) { "pass $dest8080;": 1, "ssl_preread on;": 2, "proxy_pass": 3, + "status_zone": 0, } g := NewWithT(t) - results := executeStreamServers(conf) + gen := GeneratorImpl{} + results := gen.executeStreamServers(conf) g.Expect(results).To(HaveLen(1)) result := results[0] @@ -71,6 +73,44 @@ func TestExecuteStreamServers(t *testing.T) { } } +func TestExecuteStreamServers_Plus(t *testing.T) { + config := dataplane.Configuration{ + TLSPassthroughServers: []dataplane.Layer4VirtualServer{ + { + Hostname: "example.com", + Port: 8081, + UpstreamName: "backend1", + }, + { + Hostname: "example.com", + Port: 8080, + UpstreamName: "backend1", + }, + { + Hostname: "cafe.example.com", + Port: 8082, + UpstreamName: "backend2", + }, + }, + } + expectedHTTPConfig := map[string]int{ + "status_zone example.com;": 2, + "status_zone cafe.example.com;": 1, + } + + g := NewWithT(t) + + gen := GeneratorImpl{plus: true} + results := gen.executeStreamServers(config) + g.Expect(results).To(HaveLen(1)) + + serverConf := string(results[0].data) + + for expSubStr, expCount := range expectedHTTPConfig { + g.Expect(strings.Count(serverConf, expSubStr)).To(Equal(expCount)) + } +} + func TestCreateStreamServers(t *testing.T) { conf := dataplane.Configuration{ TLSPassthroughServers: []dataplane.Layer4VirtualServer{ @@ -139,29 +179,34 @@ func TestCreateStreamServers(t *testing.T) { { Listen: getSocketNameTLS(conf.TLSPassthroughServers[0].Port, conf.TLSPassthroughServers[0].Hostname), ProxyPass: conf.TLSPassthroughServers[0].UpstreamName, + StatusZone: conf.TLSPassthroughServers[0].Hostname, SSLPreread: false, IsSocket: true, }, { Listen: getSocketNameTLS(conf.TLSPassthroughServers[1].Port, conf.TLSPassthroughServers[1].Hostname), ProxyPass: conf.TLSPassthroughServers[1].UpstreamName, + StatusZone: conf.TLSPassthroughServers[1].Hostname, SSLPreread: false, IsSocket: true, }, { Listen: getSocketNameTLS(conf.TLSPassthroughServers[2].Port, conf.TLSPassthroughServers[2].Hostname), ProxyPass: conf.TLSPassthroughServers[2].UpstreamName, + StatusZone: conf.TLSPassthroughServers[2].Hostname, SSLPreread: false, IsSocket: true, }, { Listen: fmt.Sprint(8081), Pass: getTLSPassthroughVarName(8081), + StatusZone: "example.com", SSLPreread: true, }, { Listen: fmt.Sprint(8080), Pass: getTLSPassthroughVarName(8080), + StatusZone: "example.com", SSLPreread: true, }, } @@ -239,7 +284,9 @@ func TestExecuteStreamServersForIPFamily(t *testing.T) { for _, test := range tests { t.Run(test.msg, func(t *testing.T) { g := NewWithT(t) - results := executeStreamServers(test.config) + + gen := GeneratorImpl{} + results := gen.executeStreamServers(test.config) g.Expect(results).To(HaveLen(1)) serverConf := string(results[0].data)