Skip to content

Commit dae5fac

Browse files
authored
Ensure NGINX reload occurs (#1033)
* Ensure reload occurs
1 parent 8a9a405 commit dae5fac

File tree

19 files changed

+438
-60
lines changed

19 files changed

+438
-60
lines changed

docs/architecture.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ API to update the handled resources' statuses and emit events.
106106
- Read: *NKG* reads the PID file `nginx.pid` from the `nginx-run` volume, located at `/var/run/nginx`. *NKG*
107107
extracts the PID of the nginx process from this file in order to send reload signals to *NGINX master*.
108108
4. (File I/O) *NKG* writes logs to its *stdout* and *stderr*, which are collected by the container runtime.
109-
5. (HTTP) *NKG* fetches the NGINX metrics via the unix:/var/lib/nginx/nginx-status.sock UNIX socket and converts it to
109+
5. (HTTP) *NKG* fetches the NGINX metrics via the unix:/var/run/nginx/nginx-status.sock UNIX socket and converts it to
110110
*Prometheus* format used in #2.
111111
6. (Signal) To reload NGINX, *NKG* sends the [reload signal][reload] to the **NGINX master**.
112112
7. (File I/O)
@@ -124,9 +124,12 @@ API to update the handled resources' statuses and emit events.
124124
9. (File I/O) The *NGINX master* sends logs to its *stdout* and *stderr*, which are collected by the container runtime.
125125
10. (File I/O) An *NGINX worker* writes logs to its *stdout* and *stderr*, which are collected by the container runtime.
126126
11. (Signal) The *NGINX master* controls the [lifecycle of *NGINX workers*][lifecycle] it creates workers with the new
127-
configuration and shutdowns workers with the old configuration.
128-
12. (HTTP,HTTPS) A *client* sends traffic to and receives traffic from any of the *NGINX workers* on ports 80 and 443.
129-
13. (HTTP,HTTPS) An *NGINX worker* sends traffic to and receives traffic from the *backends*.
127+
configuration and shutdowns workers with the old configuration.
128+
12. (HTTP) To consider a configuration reload a success, *NKG* ensures that at least one NGINX worker has the new
129+
configuration. To do that, *NKG* checks a particular endpoint via the unix:/var/run/nginx/nginx-config-version.sock
130+
UNIX socket.
131+
13. (HTTP,HTTPS) A *client* sends traffic to and receives traffic from any of the *NGINX workers* on ports 80 and 443.
132+
14. (HTTP,HTTPS) An *NGINX worker* sends traffic to and receives traffic from the *backends*.
130133

131134
[controller]: https://kubernetes.io/docs/concepts/architecture/controller/
132135

docs/images/nkg-pod.png

6.15 KB
Loading

internal/mode/static/handler.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ type eventHandlerConfig struct {
4545
logger logr.Logger
4646
// controlConfigNSName is the NamespacedName of the NginxGateway config for this controller.
4747
controlConfigNSName types.NamespacedName
48+
// version is the current version number of the nginx config.
49+
version int
4850
}
4951

5052
// eventHandlerImpl implements EventHandler.
@@ -90,7 +92,11 @@ func (h *eventHandlerImpl) HandleEventBatch(ctx context.Context, batch events.Ev
9092
}
9193

9294
var nginxReloadRes nginxReloadResult
93-
if err := h.updateNginx(ctx, dataplane.BuildConfiguration(ctx, graph, h.cfg.serviceResolver)); err != nil {
95+
h.cfg.version++
96+
if err := h.updateNginx(
97+
ctx,
98+
dataplane.BuildConfiguration(ctx, graph, h.cfg.serviceResolver, h.cfg.version),
99+
); err != nil {
94100
h.cfg.logger.Error(err, "Failed to update NGINX configuration")
95101
nginxReloadRes.error = err
96102
} else {
@@ -107,7 +113,7 @@ func (h *eventHandlerImpl) updateNginx(ctx context.Context, conf dataplane.Confi
107113
return fmt.Errorf("failed to replace NGINX configuration files: %w", err)
108114
}
109115

110-
if err := h.cfg.nginxRuntimeMgr.Reload(ctx); err != nil {
116+
if err := h.cfg.nginxRuntimeMgr.Reload(ctx, conf.Version); err != nil {
111117
return fmt.Errorf("failed to reload NGINX: %w", err)
112118
}
113119

internal/mode/static/handler_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ var _ = Describe("eventHandler", func() {
111111
handler.HandleEventBatch(context.Background(), batch)
112112

113113
checkUpsertEventExpectations(e)
114-
expectReconfig(dataplane.Configuration{}, fakeCfgFiles)
114+
expectReconfig(dataplane.Configuration{Version: 1}, fakeCfgFiles)
115115
})
116116

117117
It("should process Delete", func() {
@@ -124,7 +124,7 @@ var _ = Describe("eventHandler", func() {
124124
handler.HandleEventBatch(context.Background(), batch)
125125

126126
checkDeleteEventExpectations(e)
127-
expectReconfig(dataplane.Configuration{}, fakeCfgFiles)
127+
expectReconfig(dataplane.Configuration{Version: 1}, fakeCfgFiles)
128128
})
129129
})
130130

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ const (
2020

2121
// httpConfigFile is the path to the configuration file with HTTP configuration.
2222
httpConfigFile = httpFolder + "/http.conf"
23+
24+
// configVersionFile is the path to the config version configuration file.
25+
configVersionFile = httpFolder + "/config-version.conf"
2326
)
2427

2528
// ConfigFolders is a list of folders where NGINX configuration files are stored.
@@ -63,6 +66,8 @@ func (g GeneratorImpl) Generate(conf dataplane.Configuration) []file.File {
6366

6467
files = append(files, generateHTTPConfig(conf))
6568

69+
files = append(files, generateConfigVersion(conf.Version))
70+
6671
return files
6772
}
6873

@@ -104,3 +109,14 @@ func getExecuteFuncs() []executeFunc {
104109
executeMaps,
105110
}
106111
}
112+
113+
// generateConfigVersion writes the config version file.
114+
func generateConfigVersion(configVersion int) file.File {
115+
c := executeVersion(configVersion)
116+
117+
return file.File{
118+
Content: c,
119+
Path: configVersionFile,
120+
Type: file.TypeRegular,
121+
}
122+
}

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config_test
22

33
import (
4+
"fmt"
45
"testing"
56

67
. "github.com/onsi/gomega"
@@ -65,7 +66,7 @@ func TestGenerate(t *testing.T) {
6566

6667
files := generator.Generate(conf)
6768

68-
g.Expect(files).To(HaveLen(2))
69+
g.Expect(files).To(HaveLen(3))
6970

7071
g.Expect(files[0]).To(Equal(file.File{
7172
Type: file.TypeSecret,
@@ -82,4 +83,9 @@ func TestGenerate(t *testing.T) {
8283
g.Expect(httpCfg).To(ContainSubstring("listen 443"))
8384
g.Expect(httpCfg).To(ContainSubstring("upstream"))
8485
g.Expect(httpCfg).To(ContainSubstring("split_clients"))
86+
87+
g.Expect(files[2].Type).To(Equal(file.TypeRegular))
88+
g.Expect(files[2].Path).To(Equal("/etc/nginx/conf.d/config-version.conf"))
89+
configVersion := string(files[2].Content)
90+
g.Expect(configVersion).To(ContainSubstring(fmt.Sprintf("return 200 %d", conf.Version)))
8591
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ func TestExecuteServers(t *testing.T) {
7979
func TestExecuteForDefaultServers(t *testing.T) {
8080
testcases := []struct {
8181
msg string
82-
conf dataplane.Configuration
8382
httpPorts []int
8483
sslPorts []int
84+
conf dataplane.Configuration
8585
}{
8686
{
8787
conf: dataplane.Configuration{},
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package config
2+
3+
import (
4+
gotemplate "text/template"
5+
)
6+
7+
var versionTemplate = gotemplate.Must(gotemplate.New("version").Parse(versionTemplateText))
8+
9+
func executeVersion(version int) []byte {
10+
return execute(versionTemplate, version)
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package config
2+
3+
var versionTemplateText = `
4+
server {
5+
listen unix:/var/run/nginx/nginx-config-version.sock;
6+
access_log off;
7+
8+
location /version {
9+
return 200 {{.}};
10+
}
11+
}
12+
`
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package config
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestExecuteVersion(t *testing.T) {
11+
g := NewWithT(t)
12+
expSubStrings := map[string]int{
13+
"return 200 42;": 1,
14+
}
15+
16+
maps := string(executeVersion(42))
17+
for expSubStr, expCount := range expSubStrings {
18+
g.Expect(expCount).To(Equal(strings.Count(maps, expSubStr)))
19+
}
20+
}

0 commit comments

Comments
 (0)