@@ -2,20 +2,33 @@ package suite
2
2
3
3
import (
4
4
"context"
5
+ "errors"
5
6
"net/http"
6
7
"os/exec"
8
+ "strings"
7
9
"time"
8
10
9
11
. "github.com/onsi/ginkgo/v2"
10
12
. "github.com/onsi/gomega"
11
13
core "k8s.io/api/core/v1"
12
14
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13
15
"k8s.io/apimachinery/pkg/types"
16
+ "k8s.io/apimachinery/pkg/util/wait"
14
17
"sigs.k8s.io/controller-runtime/pkg/client"
15
18
16
19
"github.com/nginxinc/nginx-gateway-fabric/tests/framework"
17
20
)
18
21
22
+ const (
23
+ // FIXME(bjee19): Find an automated way to keep the version updated here similar to dependabot.
24
+ // https://github.com/nginxinc/nginx-gateway-fabric/issues/1665
25
+ debugImage = "busybox:1.28"
26
+ teaURL = "https://cafe.example.com/tea"
27
+ coffeeURL = "http://cafe.example.com/coffee"
28
+ nginxContainerName = "nginx"
29
+ ngfContainerName = "nginx-gateway"
30
+ )
31
+
19
32
var _ = Describe ("Graceful Recovery test" , Ordered , Label ("nfr" , "graceful-recovery" ), func () {
20
33
files := []string {
21
34
"graceful-recovery/cafe.yaml" ,
@@ -29,11 +42,6 @@ var _ = Describe("Graceful Recovery test", Ordered, Label("nfr", "graceful-recov
29
42
},
30
43
}
31
44
32
- nginxContainerName := "nginx"
33
- ngfContainerName := "nginx-gateway"
34
- teaURL := "https://cafe.example.com/tea"
35
- coffeeURL := "http://cafe.example.com/coffee"
36
-
37
45
BeforeAll (func () {
38
46
cfg := getDefaultSetupCfg ()
39
47
cfg .nfr = true
@@ -44,10 +52,9 @@ var _ = Describe("Graceful Recovery test", Ordered, Label("nfr", "graceful-recov
44
52
Expect (resourceManager .Apply ([]client.Object {ns })).To (Succeed ())
45
53
Expect (resourceManager .ApplyFromFiles (files , ns .Name )).To (Succeed ())
46
54
Expect (resourceManager .WaitForAppsToBeReady (ns .Name )).To (Succeed ())
47
- // Sometimes the traffic would error with code 502, after implementing this sleep it stopped.
48
- time .Sleep (2 * time .Second )
49
55
50
- expectWorkingTraffic (teaURL , coffeeURL )
56
+ err := waitForWorkingTraffic ()
57
+ Expect (err ).ToNot (HaveOccurred ())
51
58
})
52
59
53
60
AfterAll (func () {
@@ -63,21 +70,22 @@ var _ = Describe("Graceful Recovery test", Ordered, Label("nfr", "graceful-recov
63
70
output , err := restartNGFProcess (ngfContainerName )
64
71
Expect (err ).ToNot (HaveOccurred (), string (output ))
65
72
66
- expectWorkingTraffic (teaURL , coffeeURL )
67
-
68
73
checkContainerLogsForErrors (podNames [0 ])
69
74
75
+ err = waitForWorkingTraffic ()
76
+ Expect (err ).ToNot (HaveOccurred ())
77
+
70
78
// I tried just deleting the routes and ran into a bunch of issues, deleting all the files was better
71
79
Expect (resourceManager .DeleteFromFiles (files , ns .Name )).To (Succeed ())
72
- // Wait for files to be deleted.
73
- time .Sleep (2 * time .Second )
74
80
75
- expectFailingTraffic (teaURL , coffeeURL )
81
+ err = waitForFailingTraffic ()
82
+ Expect (err ).ToNot (HaveOccurred ())
76
83
77
84
Expect (resourceManager .ApplyFromFiles (files , ns .Name )).To (Succeed ())
78
85
Expect (resourceManager .WaitForAppsToBeReady (ns .Name )).To (Succeed ())
79
86
80
- expectWorkingTraffic (teaURL , coffeeURL )
87
+ err = waitForWorkingTraffic ()
88
+ Expect (err ).ToNot (HaveOccurred ())
81
89
})
82
90
83
91
It ("recovers when nginx container is restarted" , func () {
@@ -90,16 +98,19 @@ var _ = Describe("Graceful Recovery test", Ordered, Label("nfr", "graceful-recov
90
98
91
99
checkContainerLogsForErrors (podNames [0 ])
92
100
101
+ err = waitForWorkingTraffic ()
102
+ Expect (err ).ToNot (HaveOccurred ())
103
+
93
104
Expect (resourceManager .DeleteFromFiles (files , ns .Name )).To (Succeed ())
94
- // Wait for files to be deleted.
95
- time .Sleep (2 * time .Second )
96
105
97
- expectFailingTraffic (teaURL , coffeeURL )
106
+ err = waitForFailingTraffic ()
107
+ Expect (err ).ToNot (HaveOccurred ())
98
108
99
109
Expect (resourceManager .ApplyFromFiles (files , ns .Name )).To (Succeed ())
100
110
Expect (resourceManager .WaitForAppsToBeReady (ns .Name )).To (Succeed ())
101
111
102
- expectWorkingTraffic (teaURL , coffeeURL )
112
+ err = waitForWorkingTraffic ()
113
+ Expect (err ).ToNot (HaveOccurred ())
103
114
})
104
115
})
105
116
@@ -138,17 +149,9 @@ func restartNginxContainer(nginxContainerName string) ([]byte, error) {
138
149
return output , err
139
150
}
140
151
141
- // Wait for NGF to restart.
142
- time .Sleep (2 * time .Second )
143
-
144
- err = k8sClient .Get (ctx , types.NamespacedName {Namespace : ngfNamespace , Name : podNames [0 ]}, & ngfPod )
152
+ err = waitForContainerRestart (podNames [0 ], nginxContainerName , restartCount )
145
153
Expect (err ).ToNot (HaveOccurred ())
146
154
147
- for _ , containerStatus := range ngfPod .Status .ContainerStatuses {
148
- if containerStatus .Name == nginxContainerName {
149
- Expect (int (containerStatus .RestartCount )).To (Equal (restartCount + 1 ))
150
- }
151
- }
152
155
return nil , nil
153
156
}
154
157
@@ -177,7 +180,7 @@ func restartNGFProcess(ngfContainerName string) ([]byte, error) {
177
180
"-n" ,
178
181
ngfNamespace ,
179
182
podNames [0 ],
180
- "--image=busybox:1.28" ,
183
+ "--image=" + debugImage ,
181
184
"--target=nginx-gateway" ,
182
185
"--" ,
183
186
"sh" ,
@@ -187,58 +190,109 @@ func restartNGFProcess(ngfContainerName string) ([]byte, error) {
187
190
return output , err
188
191
}
189
192
190
- // Wait for NGF to restart.
191
- time .Sleep (6 * time .Second )
192
-
193
- err = k8sClient .Get (ctx , types.NamespacedName {Namespace : ngfNamespace , Name : podNames [0 ]}, & ngfPod )
193
+ err = waitForContainerRestart (podNames [0 ], ngfContainerName , restartCount )
194
194
Expect (err ).ToNot (HaveOccurred ())
195
195
196
- for _ , containerStatus := range ngfPod .Status .ContainerStatuses {
197
- if containerStatus .Name == ngfContainerName {
198
- Expect (int (containerStatus .RestartCount )).To (Equal (restartCount + 1 ))
199
- }
200
- }
201
196
return nil , nil
202
197
}
203
198
204
- func expectWorkingTraffic (teaURL , coffeeURL string ) {
205
- status , body , err := framework .Get (teaURL , address , timeoutConfig .RequestTimeout )
206
- Expect (err ).ToNot (HaveOccurred ())
207
- Expect (status ).To (Equal (http .StatusOK ))
208
- Expect (body ).To (ContainSubstring ("URI: /tea" ))
199
+ func waitForContainerRestart (ngfPodName string , containerName string , currentRestartCount int ) error {
200
+ ctx , cancel := context .WithTimeout (context .Background (), timeoutConfig .RequestTimeout )
201
+ defer cancel ()
209
202
210
- status , body , err = framework .Get (coffeeURL , address , timeoutConfig .RequestTimeout )
211
- Expect (err ).ToNot (HaveOccurred ())
212
- Expect (status ).To (Equal (http .StatusOK ), coffeeURL + " " + address )
213
- Expect (body ).To (ContainSubstring ("URI: /coffee" ))
203
+ //nolint:nilerr
204
+ return wait .PollUntilContextCancel (
205
+ ctx ,
206
+ 500 * time .Millisecond ,
207
+ true , /* poll immediately */
208
+ func (ctx context.Context ) (bool , error ) {
209
+ var ngfPod core.Pod
210
+ if err := k8sClient .Get (ctx , types.NamespacedName {Namespace : ngfNamespace , Name : ngfPodName }, & ngfPod ); err != nil {
211
+ return false , nil
212
+ }
213
+
214
+ for _ , containerStatus := range ngfPod .Status .ContainerStatuses {
215
+ if containerStatus .Name == containerName {
216
+ return int (containerStatus .RestartCount ) == currentRestartCount + 1 , nil
217
+ }
218
+ }
219
+ return false , nil
220
+ },
221
+ )
222
+ }
223
+
224
+ func waitForWorkingTraffic () error {
225
+ ctx , cancel := context .WithTimeout (context .Background (), timeoutConfig .RequestTimeout )
226
+ defer cancel ()
227
+
228
+ //nolint:nilerr
229
+ return wait .PollUntilContextCancel (
230
+ ctx ,
231
+ 500 * time .Millisecond ,
232
+ true , /* poll immediately */
233
+ func (_ context.Context ) (bool , error ) {
234
+ if err := expectRequest (teaURL , address , http .StatusOK , "URI: /tea" ); err != nil {
235
+ return false , nil
236
+ }
237
+ if err := expectRequest (coffeeURL , address , http .StatusOK , "URI: /coffee" ); err != nil {
238
+ return false , nil
239
+ }
240
+ return true , nil
241
+ },
242
+ )
214
243
}
215
244
216
- func expectFailingTraffic (teaURL , coffeeURL string ) {
217
- status , body , err := framework .Get (teaURL , address , timeoutConfig .RequestTimeout )
218
- Expect (err ).To (HaveOccurred ())
219
- Expect (status ).ToNot (Equal (http .StatusOK ))
220
- Expect (body ).ToNot (ContainSubstring ("URI: /tea" ))
245
+ func waitForFailingTraffic () error {
246
+ ctx , cancel := context .WithTimeout (context .Background (), timeoutConfig .RequestTimeout )
247
+ defer cancel ()
221
248
222
- status , body , err = framework .Get (coffeeURL , address , timeoutConfig .RequestTimeout )
223
- Expect (err ).To (HaveOccurred ())
224
- Expect (status ).ToNot (Equal (http .StatusOK ))
225
- Expect (body ).ToNot (ContainSubstring ("URI: /coffee" ))
249
+ return wait .PollUntilContextCancel (
250
+ ctx ,
251
+ 500 * time .Millisecond ,
252
+ true , /* poll immediately */
253
+ func (_ context.Context ) (bool , error ) {
254
+ if err := expectRequest (teaURL , address , 0 , "URI: /tea" ); err == nil {
255
+ return false , nil
256
+ }
257
+ if err := expectRequest (coffeeURL , address , 0 , "URI: /coffee" ); err == nil {
258
+ return false , nil
259
+ }
260
+ return true , nil
261
+ },
262
+ )
263
+ }
264
+
265
+ func expectRequest (appURL string , address string , httpStatus int , responseBodyMessage string ) error {
266
+ status , body , err := framework .Get (appURL , address , timeoutConfig .RequestTimeout )
267
+ if status != httpStatus {
268
+ return errors .New ("http statuses were not equal" )
269
+ }
270
+ if httpStatus == http .StatusOK {
271
+ if ! strings .Contains (body , responseBodyMessage ) {
272
+ return errors .New ("expected response body to contain body message" )
273
+ }
274
+ } else {
275
+ if strings .Contains (body , responseBodyMessage ) {
276
+ return errors .New ("expected response body to not contain body message" )
277
+ }
278
+ }
279
+ return err
226
280
}
227
281
228
282
func checkContainerLogsForErrors (ngfPodName string ) {
229
283
sinceSeconds := int64 (15 )
230
284
logs , err := resourceManager .GetPodLogs (
231
285
ngfNamespace ,
232
286
ngfPodName ,
233
- & core.PodLogOptions {Container : "nginx" , SinceSeconds : & sinceSeconds },
287
+ & core.PodLogOptions {Container : nginxContainerName , SinceSeconds : & sinceSeconds },
234
288
)
235
289
Expect (err ).ToNot (HaveOccurred ())
236
290
Expect (logs ).ToNot (ContainSubstring ("emerg" ), logs )
237
291
238
292
logs , err = resourceManager .GetPodLogs (
239
293
ngfNamespace ,
240
294
ngfPodName ,
241
- & core.PodLogOptions {Container : "nginx-gateway" , SinceSeconds : & sinceSeconds },
295
+ & core.PodLogOptions {Container : ngfContainerName , SinceSeconds : & sinceSeconds },
242
296
)
243
297
Expect (err ).ToNot (HaveOccurred ())
244
298
Expect (logs ).ToNot (ContainSubstring ("error" ), logs )
0 commit comments