@@ -20,8 +20,10 @@ import (
20
20
"fmt"
21
21
"io"
22
22
"strings"
23
+ "time"
23
24
24
25
"github.com/argoproj-labs/argocd-autopilot/pkg/kube"
26
+ "github.com/codefresh-io/cli-v2/pkg/log"
25
27
"github.com/codefresh-io/cli-v2/pkg/store"
26
28
authv1 "k8s.io/api/authorization/v1"
27
29
batchv1 "k8s.io/api/batch/v1"
57
59
}
58
60
)
59
61
60
- func EnsureClusterRequirements (ctx context.Context , kubeFactory kube.Factory , namespace string ) error {
62
+ func EnsureClusterRequirements (ctx context.Context , kubeFactory kube.Factory , namespace string , contextUrl string ) error {
61
63
requirementsValidationErrorMessage := "cluster does not meet minimum requirements"
62
64
var specificErrorMessages []string
63
65
@@ -169,6 +171,123 @@ func EnsureClusterRequirements(ctx context.Context, kubeFactory kube.Factory, na
169
171
return fmt .Errorf ("%s: %v" , requirementsValidationErrorMessage , specificErrorMessages )
170
172
}
171
173
174
+ err = runNetworkTest (ctx , kubeFactory , contextUrl )
175
+ if err != nil {
176
+ return fmt .Errorf ("cluster network tests failed: %w " , err )
177
+ }
178
+
179
+ log .G (ctx ).Info ("Network test finished successfully" )
180
+
181
+ return nil
182
+ }
183
+
184
+ func runNetworkTest (ctx context.Context , kubeFactory kube.Factory , urls ... string ) error {
185
+ const networkTestsTimeout = 120 * time .Second
186
+
187
+ envVars := map [string ]string {
188
+ "URLS" : strings .Join (urls , "," ),
189
+ "IN_CLUSTER" : "1" ,
190
+ }
191
+ env := prepareEnvVars (envVars )
192
+
193
+ client , err := kubeFactory .KubernetesClientSet ()
194
+ if err != nil {
195
+ return fmt .Errorf ("failed to create kubernetes client: %w" , err )
196
+ }
197
+
198
+ job , err := launchJob (ctx , client , LaunchJobOptions {
199
+ Namespace : store .Get ().DefaultNamespace ,
200
+ JobName : & store .Get ().NetworkTesterName ,
201
+ Image : & store .Get ().NetworkTesterImage ,
202
+ Env : env ,
203
+ RestartPolicy : v1 .RestartPolicyNever ,
204
+ BackOffLimit : 0 ,
205
+ })
206
+ if err != nil {
207
+ return err
208
+ }
209
+
210
+ defer func () {
211
+ err := deleteJob (ctx , client , job )
212
+ if err != nil {
213
+ log .G (ctx ).Errorf ("fail to delete tester pod: %s" , err .Error ())
214
+ }
215
+ }()
216
+
217
+ log .G (ctx ).Info ("Running network test..." )
218
+ ticker := time .NewTicker (5 * time .Second )
219
+ defer ticker .Stop ()
220
+ var podLastState * v1.Pod
221
+ timeoutChan := time .After (networkTestsTimeout )
222
+
223
+ Loop:
224
+ for {
225
+ select {
226
+ case <- ticker .C :
227
+ log .G (ctx ).Debug ("Waiting for network tester to finish" )
228
+ currentPod , err := getPodByJob (ctx , client , job )
229
+ if err != nil {
230
+ return err
231
+ }
232
+
233
+ if currentPod == nil {
234
+ log .G (ctx ).Debug ("Network tester pod: waiting for pod" )
235
+ continue
236
+ }
237
+
238
+ if len (currentPod .Status .ContainerStatuses ) == 0 {
239
+ log .G (ctx ).Debug ("Network tester pod: creating container" )
240
+ continue
241
+ }
242
+
243
+ state := currentPod .Status .ContainerStatuses [0 ].State
244
+ if state .Running != nil {
245
+ log .G (ctx ).Debug ("Network tester pod: running" )
246
+ }
247
+
248
+ if state .Waiting != nil {
249
+ log .G (ctx ).Debug ("Network tester pod: waiting" )
250
+ }
251
+
252
+ if state .Terminated != nil {
253
+ log .G (ctx ).Debug ("Network tester pod: terminated" )
254
+ podLastState = currentPod
255
+ break Loop
256
+ }
257
+ case <- timeoutChan :
258
+ return fmt .Errorf ("network test timeout reached!" )
259
+ }
260
+ }
261
+
262
+ return checkPodLastState (ctx , client , podLastState )
263
+ }
264
+
265
+ func prepareEnvVars (vars map [string ]string ) []v1.EnvVar {
266
+ var env []v1.EnvVar
267
+ for key , value := range vars {
268
+ env = append (env , v1.EnvVar {
269
+ Name : key ,
270
+ Value : value ,
271
+ })
272
+ }
273
+
274
+ return env
275
+ }
276
+
277
+ func checkPodLastState (ctx context.Context , client kubernetes.Interface , pod * v1.Pod ) error {
278
+ terminated := pod .Status .ContainerStatuses [0 ].State .Terminated
279
+ if terminated .ExitCode != 0 {
280
+ logs , err := getPodLogs (ctx , client , pod .Namespace , pod .Name )
281
+ if err != nil {
282
+ log .G (ctx ).Errorf ("Failed getting logs from network-tester pod: $s" , err .Error ())
283
+ } else {
284
+ log .G (ctx ).Error (logs )
285
+ }
286
+
287
+ terminationMessage := strings .Trim (terminated .Message , "\n " )
288
+ return fmt .Errorf ("Network test failed with: %s" , terminationMessage )
289
+ }
290
+
172
291
return nil
173
292
}
174
293
@@ -229,7 +348,7 @@ func testNode(n v1.Node, req validationRequest) []string {
229
348
return result
230
349
}
231
350
232
- func LaunchJob (ctx context.Context , client kubernetes.Interface , opts LaunchJobOptions ) (* batchv1.Job , error ) {
351
+ func launchJob (ctx context.Context , client kubernetes.Interface , opts LaunchJobOptions ) (* batchv1.Job , error ) {
233
352
jobSpec := & batchv1.Job {
234
353
ObjectMeta : metav1.ObjectMeta {
235
354
Name : * opts .JobName ,
@@ -255,7 +374,7 @@ func LaunchJob(ctx context.Context, client kubernetes.Interface, opts LaunchJobO
255
374
return client .BatchV1 ().Jobs (opts .Namespace ).Create (ctx , jobSpec , metav1.CreateOptions {})
256
375
}
257
376
258
- func DeleteJob (ctx context.Context , client kubernetes.Interface , job * batchv1.Job ) error {
377
+ func deleteJob (ctx context.Context , client kubernetes.Interface , job * batchv1.Job ) error {
259
378
err := client .BatchV1 ().Jobs (job .Namespace ).Delete (ctx , job .Name , metav1.DeleteOptions {})
260
379
if err != nil {
261
380
return fmt .Errorf ("fail to delete job resource \" %s\" : %s" , job .Name , err .Error ())
@@ -271,7 +390,7 @@ func DeleteJob(ctx context.Context, client kubernetes.Interface, job *batchv1.Jo
271
390
return nil
272
391
}
273
392
274
- func GetPodByJob (ctx context.Context , client kubernetes.Interface , job * batchv1.Job ) (* v1.Pod , error ) {
393
+ func getPodByJob (ctx context.Context , client kubernetes.Interface , job * batchv1.Job ) (* v1.Pod , error ) {
275
394
pods , err := client .CoreV1 ().Pods (store .Get ().DefaultNamespace ).List (ctx , metav1.ListOptions {
276
395
LabelSelector : "controller-uid=" + job .GetLabels ()["controller-uid" ],
277
396
})
@@ -286,18 +405,18 @@ func GetPodByJob(ctx context.Context, client kubernetes.Interface, job *batchv1.
286
405
return & pods .Items [0 ], nil
287
406
}
288
407
289
- func GetPodLogs (ctx context.Context , client kubernetes.Interface , namespace , name string ) (string , error ) {
408
+ func getPodLogs (ctx context.Context , client kubernetes.Interface , namespace , name string ) (string , error ) {
290
409
req := client .CoreV1 ().Pods (namespace ).GetLogs (name , & v1.PodLogOptions {})
291
410
podLogs , err := req .Stream (ctx )
292
411
if err != nil {
293
- return "" , fmt .Errorf ("Failed to get network-tester pod logs: %w" , err )
412
+ return "" , fmt .Errorf ("failed to get network-tester pod logs: %w" , err )
294
413
}
295
414
defer podLogs .Close ()
296
415
297
416
logsBuf := new (bytes.Buffer )
298
417
_ , err = io .Copy (logsBuf , podLogs )
299
418
if err != nil {
300
- return "" , fmt .Errorf ("Failed to read network-tester pod logs: %w" , err )
419
+ return "" , fmt .Errorf ("failed to read network-tester pod logs: %w" , err )
301
420
}
302
421
303
422
return strings .Trim (logsBuf .String (), "\n " ), nil
0 commit comments