@@ -20,8 +20,10 @@ import (
2020 "fmt"
2121 "io"
2222 "strings"
23+ "time"
2324
2425 "github.com/argoproj-labs/argocd-autopilot/pkg/kube"
26+ "github.com/codefresh-io/cli-v2/pkg/log"
2527 "github.com/codefresh-io/cli-v2/pkg/store"
2628 authv1 "k8s.io/api/authorization/v1"
2729 batchv1 "k8s.io/api/batch/v1"
5759 }
5860)
5961
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 {
6163 requirementsValidationErrorMessage := "cluster does not meet minimum requirements"
6264 var specificErrorMessages []string
6365
@@ -169,6 +171,123 @@ func EnsureClusterRequirements(ctx context.Context, kubeFactory kube.Factory, na
169171 return fmt .Errorf ("%s: %v" , requirementsValidationErrorMessage , specificErrorMessages )
170172 }
171173
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+
172291 return nil
173292}
174293
@@ -229,7 +348,7 @@ func testNode(n v1.Node, req validationRequest) []string {
229348 return result
230349}
231350
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 ) {
233352 jobSpec := & batchv1.Job {
234353 ObjectMeta : metav1.ObjectMeta {
235354 Name : * opts .JobName ,
@@ -255,7 +374,7 @@ func LaunchJob(ctx context.Context, client kubernetes.Interface, opts LaunchJobO
255374 return client .BatchV1 ().Jobs (opts .Namespace ).Create (ctx , jobSpec , metav1.CreateOptions {})
256375}
257376
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 {
259378 err := client .BatchV1 ().Jobs (job .Namespace ).Delete (ctx , job .Name , metav1.DeleteOptions {})
260379 if err != nil {
261380 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
271390 return nil
272391}
273392
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 ) {
275394 pods , err := client .CoreV1 ().Pods (store .Get ().DefaultNamespace ).List (ctx , metav1.ListOptions {
276395 LabelSelector : "controller-uid=" + job .GetLabels ()["controller-uid" ],
277396 })
@@ -286,18 +405,18 @@ func GetPodByJob(ctx context.Context, client kubernetes.Interface, job *batchv1.
286405 return & pods .Items [0 ], nil
287406}
288407
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 ) {
290409 req := client .CoreV1 ().Pods (namespace ).GetLogs (name , & v1.PodLogOptions {})
291410 podLogs , err := req .Stream (ctx )
292411 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 )
294413 }
295414 defer podLogs .Close ()
296415
297416 logsBuf := new (bytes.Buffer )
298417 _ , err = io .Copy (logsBuf , podLogs )
299418 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 )
301420 }
302421
303422 return strings .Trim (logsBuf .String (), "\n " ), nil
0 commit comments