github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/quickcreate/quickcreate_test.go (about) 1 // Copyright (c) 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package quickcreate 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 "github.com/pkg/errors" 13 "github.com/verrazzano/verrazzano/pkg/k8sutil" 14 "github.com/verrazzano/verrazzano/tests/e2e/backup/helpers" 15 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 16 "github.com/verrazzano/verrazzano/tests/e2e/pkg/update" 17 "go.uber.org/zap" 18 corev1 "k8s.io/api/core/v1" 19 apierrors "k8s.io/apimachinery/pkg/api/errors" 20 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 22 "k8s.io/apimachinery/pkg/runtime" 23 "k8s.io/apimachinery/pkg/runtime/schema" 24 "k8s.io/client-go/dynamic" 25 "k8s.io/client-go/kubernetes" 26 "k8s.io/client-go/rest" 27 "k8s.io/client-go/tools/clientcmd" 28 "os" 29 "sigs.k8s.io/cluster-api/api/v1beta1" 30 clipkg "sigs.k8s.io/controller-runtime/pkg/client" 31 "strings" 32 "text/tabwriter" 33 "time" 34 ) 35 36 const ( 37 minimumVersion = "1.7.0" 38 waitTimeOut = 40 * time.Minute 39 pollingInterval = 30 * time.Second 40 41 shortWaitTimeout = 15 * time.Minute 42 shortPollingInterval = 60 * time.Second 43 vzPollingInterval = 60 * time.Second 44 addonControllerPodNamespace = "verrazzano-capi" 45 nodeLabel = "node-role.kubernetes.io/node" 46 controlPlaneLabel = "node-role.kubernetes.io/control-plane" 47 addonControllerPodLabel = "cluster.x-k8s.io/provider" 48 ) 49 50 var ( 51 client clipkg.Client 52 ctx *QCContext 53 ImagePullSecret = os.Getenv("IMAGE_PULL_SECRET") 54 DockerRepo = os.Getenv("DOCKER_REPO") 55 DockerCredsUser = os.Getenv("DOCKER_CREDS_USR") 56 DockerCredsPassword = os.Getenv("DOCKER_CREDS_PSW") 57 ) 58 59 var beforeSuite = t.BeforeSuiteFunc(func() { 60 // Get Kubeconfig information and create clients 61 kubeconfigPath, err := k8sutil.GetKubeConfigLocation() 62 Expect(err).To(BeNil()) 63 cfg, err := k8sutil.GetKubeConfigGivenPath(kubeconfigPath) 64 Expect(err).To(BeNil()) 65 scheme := runtime.NewScheme() 66 _ = v1beta1.AddToScheme(scheme) 67 _ = corev1.AddToScheme(scheme) 68 c, err := clipkg.New(cfg, clipkg.Options{ 69 Scheme: scheme, 70 }) 71 Expect(err).To(BeNil()) 72 client = c 73 74 // Create test context and setup 75 ctx, err = newContext(client, clusterType) 76 Expect(err).To(BeNil()) 77 err = ctx.setup() 78 Expect(err).To(BeNil()) 79 80 t.Logs.Infof("Creating Cluster of type [%s] - parameters [%s] = namespace [%s] - clustername [%s] - clusternamespace [%s]", ctx.ClusterType, ctx.Parameters, ctx.Namespace, clusterName, clusterNamespace) 81 if err != nil { 82 t.Fail(fmt.Sprintf("Failed to get default kubeconfig path: %s", err.Error())) 83 } 84 supported, err := pkg.IsVerrazzanoMinVersion(minimumVersion, kubeconfigPath) 85 if err != nil { 86 t.Logs.Errorf("Error getting Verrazzano version: %v", err) 87 } 88 if !supported { 89 t.Logs.Infof("Skipping test because Verrazzano version is less than %s", minimumVersion) 90 //return 91 } 92 createCluster() 93 t.Logs.Infof("Wait for 30 seconds before verification") 94 time.Sleep(30 * time.Second) 95 err = CreateImagePullSecrets(clusterName, t.Logs) 96 if err != nil { 97 t.Logs.Errorf("Error creating image pull secrets") 98 } 99 }) 100 var afterSuite = t.AfterSuiteFunc(func() { 101 if ctx == nil { 102 return 103 } 104 Eventually(func() error { 105 err := ctx.cleanupCAPICluster() 106 if err != nil { 107 t.Logs.Info(err) 108 } 109 return err 110 }).WithPolling(pollingInterval).WithTimeout(waitTimeOut).ShouldNot(HaveOccurred()) 111 Eventually(func() error { 112 err := ctx.deleteObject(ctx.namespaceObject()) 113 if err != nil { 114 t.Logs.Info(err) 115 } 116 return err 117 }).WithPolling(pollingInterval).WithTimeout(waitTimeOut).ShouldNot(HaveOccurred()) 118 }) 119 var _ = BeforeSuite(beforeSuite) 120 var _ = AfterSuite(afterSuite) 121 122 func createCluster() { 123 err := ctx.applyCluster() 124 Expect(err).To(BeNil()) 125 Eventually(func() error { 126 err := ctx.isClusterReady() 127 if err != nil { 128 t.Logs.Info(err) 129 } 130 return err 131 }).WithPolling(pollingInterval).WithTimeout(waitTimeOut).ShouldNot(HaveOccurred()) 132 } 133 134 // 'It' Wrapper to only run spec if the ClusterAPI is supported on the current Verrazzano version 135 func WhenClusterAPIInstalledIt(description string, f func()) { 136 kubeconfigPath, err := k8sutil.GetKubeConfigLocation() 137 if err != nil { 138 t.It(description, func() { 139 Fail(fmt.Sprintf("Failed to get default kubeconfig path: %s", err.Error())) 140 }) 141 } 142 supported, err := pkg.IsVerrazzanoMinVersion("1.6.0", kubeconfigPath) 143 if err != nil { 144 t.It(description, func() { 145 Fail(fmt.Sprintf("Failed to check Verrazzano version 1.6.0: %s", err.Error())) 146 }) 147 } 148 if supported { 149 t.It(description, f) 150 } else { 151 t.Logs.Infof("Skipping check '%v',clusterAPI is not supported", description) 152 } 153 } 154 155 func ensureVPOPodsAreRunningOnWorkloadCluster(clusterName, namespace string, log *zap.SugaredLogger) bool { 156 k8sclient, err := getCapiClusterK8sClient(clusterName, log) 157 if err != nil { 158 t.Logs.Info("Failed to get k8s client for workload cluster") 159 return false 160 } 161 vpo, err := pkg.SpecificPodsRunningInClusterWithClient(namespace, "app=verrazzano-platform-operator", k8sclient) 162 if err != nil { 163 t.Logs.Error(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", namespace, err)) 164 } 165 vpoWebhook, err := pkg.SpecificPodsRunningInClusterWithClient(namespace, "app=verrazzano-platform-operator-webhook", k8sclient) 166 if err != nil { 167 t.Logs.Error(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", namespace, err)) 168 } 169 170 if err != nil { 171 log.Errorf("Unable to display resources from workload cluster ", zap.Error(err)) 172 return false 173 } 174 175 return vpo && vpoWebhook 176 } 177 178 func getCapiClusterKubeConfig(clusterName string, log *zap.SugaredLogger) ([]byte, error) { 179 clientset, err := k8sutil.GetKubernetesClientset() 180 if err != nil { 181 log.Errorf("Failed to get clientset with error: %v", err) 182 return nil, err 183 } 184 185 secret, err := clientset.CoreV1().Secrets(clusterNamespace).Get(context.TODO(), fmt.Sprintf("%s-kubeconfig", clusterName), metav1.GetOptions{}) 186 if err != nil { 187 log.Infof("Error fetching secret ", zap.Error(err)) 188 return nil, err 189 } 190 191 return secret.Data["value"], nil 192 } 193 194 func getCapiClusterK8sClient(clusterName string, log *zap.SugaredLogger) (client *kubernetes.Clientset, err error) { 195 capiK8sConfig, err := getCapiClusterKubeConfig(clusterName, log) 196 if err != nil { 197 return nil, err 198 } 199 k8sRestConfig, err := GetRESTConfigGivenString(capiK8sConfig) 200 if err != nil { 201 return nil, errors.Wrap(err, "Failed to get k8s rest config") 202 } 203 204 return k8sutil.GetKubernetesClientsetWithConfig(k8sRestConfig) 205 } 206 207 func GetRESTConfigGivenString(kubeconfig []byte) (*rest.Config, error) { 208 config, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig) 209 if err != nil { 210 return nil, err 211 } 212 setConfigQPSBurst(config) 213 return config, nil 214 } 215 216 func setConfigQPSBurst(config *rest.Config) { 217 config.Burst = 150 218 config.QPS = 100 219 } 220 221 func CreateImagePullSecrets(clusterName string, log *zap.SugaredLogger) error { 222 log.Infof("Creating image pull secrets on workload cluster ...") 223 224 capiK8sConfig, err := getCapiClusterKubeConfig(clusterName, log) 225 if err != nil { 226 return err 227 } 228 tmpFile, err := os.CreateTemp(os.TempDir(), clusterName) 229 if err != nil { 230 log.Error("Failed to create temporary file ", zap.Error(err)) 231 return err 232 } 233 234 if err = os.WriteFile(tmpFile.Name(), capiK8sConfig, 0600); err != nil { 235 log.Error("failed to write to destination file ", zap.Error(err)) 236 return err 237 } 238 239 var cmdArgs []string 240 var bcmd helpers.BashCommand 241 dockerSecretCommand := fmt.Sprintf("kubectl --kubeconfig %s create secret docker-registry %s --docker-server=%s --docker-username=%s --docker-password=%s", tmpFile.Name(), ImagePullSecret, DockerRepo, DockerCredsUser, DockerCredsPassword) 242 cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand) 243 bcmd.CommandArgs = cmdArgs 244 secretCreateResponse := helpers.Runner(&bcmd, log) 245 if secretCreateResponse.CommandError != nil { 246 return secretCreateResponse.CommandError 247 } 248 249 cmdArgs = []string{} 250 dockerSecretCommand = fmt.Sprintf("kubectl --kubeconfig %s create ns verrazzano-install", tmpFile.Name()) 251 cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand) 252 bcmd.CommandArgs = cmdArgs 253 secretCreateResponse = helpers.Runner(&bcmd, log) 254 if secretCreateResponse.CommandError != nil { 255 return secretCreateResponse.CommandError 256 } 257 258 cmdArgs = []string{} 259 dockerSecretCommand = fmt.Sprintf("kubectl --kubeconfig %s create secret docker-registry %s --docker-server=%s --docker-username=%s --docker-password=%s -n verrazzano-install", tmpFile.Name(), ImagePullSecret, DockerRepo, DockerCredsUser, DockerCredsPassword) 260 cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand) 261 bcmd.CommandArgs = cmdArgs 262 secretCreateResponse = helpers.Runner(&bcmd, log) 263 if secretCreateResponse.CommandError != nil { 264 return secretCreateResponse.CommandError 265 } 266 267 cmdArgs = []string{} 268 dockerSecretCommand = fmt.Sprintf("kubectl --kubeconfig %s create secret docker-registry github-packages --docker-server=%s --docker-username=%s --docker-password=%s", tmpFile.Name(), DockerRepo, DockerCredsUser, DockerCredsPassword) 269 cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand) 270 bcmd.CommandArgs = cmdArgs 271 secretCreateResponse = helpers.Runner(&bcmd, log) 272 if secretCreateResponse.CommandError != nil { 273 return secretCreateResponse.CommandError 274 } 275 276 cmdArgs = []string{} 277 dockerSecretCommand = fmt.Sprintf("kubectl --kubeconfig %s create secret docker-registry ocr --docker-server=%s --docker-username=%s --docker-password=%s", tmpFile.Name(), DockerRepo, DockerCredsUser, DockerCredsPassword) 278 cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand) 279 bcmd.CommandArgs = cmdArgs 280 secretCreateResponse = helpers.Runner(&bcmd, log) 281 if secretCreateResponse.CommandError != nil { 282 return secretCreateResponse.CommandError 283 } 284 return nil 285 } 286 287 func ensureVerrazzano(clusterName string, log *zap.SugaredLogger) error { 288 289 vzFetched, err := getVerrazzano(clusterName, "default", "verrazzano", log) 290 if err != nil { 291 log.Errorf("unable to fetch vz resource from %s due to '%v'", clusterName, zap.Error(err)) 292 return err 293 } 294 var vz Verrazzano 295 modBinaryData, err := json.Marshal(vzFetched) 296 if err != nil { 297 log.Error("json marshalling error ", zap.Error(err)) 298 return err 299 } 300 301 err = json.Unmarshal(modBinaryData, &vz) 302 if err != nil { 303 log.Error("json unmarshalling error ", zap.Error(err)) 304 return err 305 } 306 307 curState := "InstallStarted" 308 for _, cond := range vz.Status.Conditions { 309 if cond.Type == "InstallComplete" { 310 curState = cond.Type 311 } 312 } 313 314 if curState == "InstallComplete" { 315 return nil 316 } 317 return fmt.Errorf("All components are not ready: Current State = %v", curState) 318 } 319 320 func ensureVerrazzanoFleetBindingExists(clusterName string, log *zap.SugaredLogger) error { 321 log.Infof("Wait for 30 seconds before verification") 322 time.Sleep(30 * time.Second) 323 324 vfbFetched, err := getVerrazzanoFleetBinding(log) 325 if err != nil { 326 log.Errorf("unable to fetch verrazzanofleetbinding resource from %s due to '%v'", clusterName, zap.Error(err)) 327 return err 328 } 329 var vfb VerrazzanoFleetBinding 330 modBinaryData, err := json.Marshal(vfbFetched) 331 if err != nil { 332 log.Error("json marshalling error ", zap.Error(err)) 333 return err 334 } 335 336 err = json.Unmarshal(modBinaryData, &vfb) 337 if err != nil { 338 log.Error("json unmarshalling error ", zap.Error(err)) 339 return err 340 } 341 342 curState := "Ready" 343 for _, cond := range vfb.Status.Conditions { 344 if cond.Type == "Ready" { 345 curState = cond.Type 346 } 347 } 348 349 if curState == "Ready" { 350 return nil 351 } 352 return fmt.Errorf("All components are not ready: Current State = %v", curState) 353 } 354 355 func ensureVerrazzanoFleetExists(clusterName string, log *zap.SugaredLogger) error { 356 log.Infof("Wait for 30 seconds before verification") 357 time.Sleep(30 * time.Second) 358 359 vfFetched, err := getVerrazzanoFleet(log) 360 if err != nil { 361 log.Errorf("unable to fetch verrazzanofleetbinding resource from %s due to '%v'", clusterName, zap.Error(err)) 362 return err 363 } 364 var vf VerrazzanoFleet 365 modBinaryData, err := json.Marshal(vfFetched) 366 if err != nil { 367 log.Error("json marshalling error ", zap.Error(err)) 368 return err 369 } 370 371 err = json.Unmarshal(modBinaryData, &vf) 372 if err != nil { 373 log.Error("json unmarshalling error ", zap.Error(err)) 374 return err 375 } 376 377 curState := "Ready" 378 for _, cond := range vf.Status.Conditions { 379 if cond.Type == "Ready" { 380 curState = cond.Type 381 } 382 } 383 384 if curState == "Ready" { 385 return nil 386 } 387 return fmt.Errorf("VerrazzanoFleet is not ready: Current State = %v", curState) 388 } 389 390 func createFleetForUnknownCluster(clusterName string, log *zap.SugaredLogger) error { 391 dclient, err := k8sutil.GetDynamicClient() 392 if err != nil { 393 log.Errorf("unable to get workload kubeconfig ", zap.Error(err)) 394 return err 395 } 396 397 gvr := getVerrazzanoFleetGVR() 398 vfFetched, err := getVerrazzanoFleet(log) 399 if err != nil { 400 log.Errorf("unable to fetch verrazzanofleetbinding resource from %s due to '%v'", clusterName, zap.Error(err)) 401 return err 402 } 403 vfDeepCopy := vfFetched.DeepCopy() 404 vfDeepCopy.Object["spec"].(map[string]interface{})["clusterSelector"].(map[string]interface{})["name"] = "test-clustername" 405 vfDeepCopy.Object["metadata"].(map[string]interface{})["name"] = "new-fleet-name" 406 delete(vfDeepCopy.Object["metadata"].(map[string]interface{}), "resourceVersion") 407 408 _, err = dclient.Resource(gvr).Namespace(clusterNamespace).Create(context.TODO(), vfDeepCopy, metav1.CreateOptions{}) 409 if err != nil { 410 log.Errorf("Unable to create the verrazzanofleet resource", err) 411 return err 412 } 413 return nil 414 } 415 416 func updateVerrazzanoFleet(clusterName string, log *zap.SugaredLogger) error { 417 dclient, err := k8sutil.GetDynamicClient() 418 if err != nil { 419 log.Errorf("unable to get workload kubeconfig ", zap.Error(err)) 420 return err 421 } 422 423 gvr := getVerrazzanoFleetGVR() 424 vfFetched, err := getVerrazzanoFleet(log) 425 if err != nil { 426 log.Errorf("unable to fetch verrazzanofleet resource from %s due to '%v'", clusterName, zap.Error(err)) 427 return err 428 } 429 if vfFetched.Object["spec"].(map[string]interface{})["verrazzano"].(map[string]interface{})["spec"].(map[string]interface{})["components"] == nil { 430 vfFetched.Object["spec"].(map[string]interface{})["verrazzano"].(map[string]interface{})["spec"].(map[string]interface{})["components"] = make(map[string]interface{}) 431 } 432 vfFetched.Object["spec"].(map[string]interface{})["verrazzano"].(map[string]interface{})["spec"].(map[string]interface{})["components"].(map[string]interface{})["console"] = map[string]interface{}{"enabled": true} 433 434 _, err = dclient.Resource(gvr).Namespace(clusterNamespace).Update(context.TODO(), vfFetched, metav1.UpdateOptions{}) 435 if err != nil { 436 log.Errorf("Unable to update the verrazzanofleet resource", err) 437 return err 438 } 439 return nil 440 } 441 442 func createMultipleFleetForSameCluster(clusterName string, log *zap.SugaredLogger) error { 443 dclient, err := k8sutil.GetDynamicClient() 444 if err != nil { 445 log.Errorf("unable to get workload kubeconfig ", zap.Error(err)) 446 return err 447 } 448 449 gvr := getVerrazzanoFleetGVR() 450 vfFetched, err := getVerrazzanoFleet(log) 451 if err != nil { 452 log.Errorf("unable to fetch verrazzanofleetbinding resource from %s due to '%v'", clusterName, zap.Error(err)) 453 return err 454 } 455 vfDeepCopy := vfFetched.DeepCopy() 456 vfDeepCopy.Object["metadata"].(map[string]interface{})["name"] = "duplicate-fleet-name" 457 delete(vfDeepCopy.Object["metadata"].(map[string]interface{}), "resourceVersion") 458 _, err = dclient.Resource(gvr).Namespace(clusterNamespace).Create(context.TODO(), vfDeepCopy, metav1.CreateOptions{}) 459 if err != nil { 460 log.Errorf("Unable to create the verrazzanofleet resource", err) 461 return err 462 } 463 return nil 464 } 465 466 func getVerrazzano(clusterName, namespace, vzinstallname string, log *zap.SugaredLogger) (*unstructured.Unstructured, error) { 467 dclient, err := getCapiClusterDynamicClient(clusterName, log) 468 if err != nil { 469 log.Errorf("unable to get workload kubeconfig ", zap.Error(err)) 470 return nil, err 471 } 472 473 gvr := schema.GroupVersionResource{ 474 Group: "install.verrazzano.io", 475 Version: "v1beta1", 476 Resource: "verrazzanos", 477 } 478 479 return dclient.Resource(gvr).Namespace(namespace).Get(context.TODO(), vzinstallname, metav1.GetOptions{}) 480 } 481 482 // DisplayWorkloadClusterResources displays the pods of workload OCNE cluster as a formatted table. 483 func displayWorkloadClusterResources(clusterName string, log *zap.SugaredLogger) error { 484 client, err := getCapiClusterK8sClient(clusterName, log) 485 if err != nil { 486 return errors.Wrap(err, "Failed to get k8s client for workload cluster") 487 } 488 489 log.Infof("----------- Node in workload cluster ---------------------") 490 err = showNodeInfo(client, clusterName, log) 491 if err != nil { 492 return err 493 } 494 495 log.Infof("----------- Pods running on workload cluster ---------------------") 496 return showPodInfo(client, clusterName, log) 497 } 498 499 // ShowPodInfo displays the pods of workload OCNE cluster as a formatted table. 500 func showPodInfo(client *kubernetes.Clientset, clusterName string, log *zap.SugaredLogger) error { 501 nsList, err := client.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) 502 if err != nil { 503 return errors.Wrap(err, fmt.Sprintf("failed to get list of namespaces from cluster '%s'", clusterName)) 504 } 505 writer := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', tabwriter.AlignRight) 506 fmt.Fprintln(writer, "Name\tNamespace\tStatus\tIP\tNode\tAge") 507 //var dnsPod, ccmPod, calicokubePod *v1.Pod 508 for _, ns := range nsList.Items { 509 podList, err := client.CoreV1().Pods(ns.Name).List(context.TODO(), metav1.ListOptions{}) 510 if err != nil { 511 return errors.Wrap(err, fmt.Sprintf("failed to get list of pods from cluster '%s'", clusterName)) 512 } 513 for _, pod := range podList.Items { 514 podData, err := client.CoreV1().Pods(ns.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{}) 515 if err != nil { 516 if apierrors.IsNotFound(err) { 517 log.Infof("No pods in namespace '%s'", ns.Name) 518 } else { 519 return errors.Wrap(err, fmt.Sprintf("failed to get pod '%s' from cluster '%s'", pod.Name, clusterName)) 520 } 521 } 522 523 fmt.Fprintf(writer, "%v\n", fmt.Sprintf("%v\t%v\t%v\t%v\t%v\t%v", 524 podData.GetName(), podData.GetNamespace(), podData.Status.Phase, podData.Status.PodIP, podData.Spec.NodeName, 525 time.Until(podData.GetCreationTimestamp().Time).Abs())) 526 } 527 } 528 writer.Flush() 529 return nil 530 } 531 532 // ShowNodeInfo displays the nodes of workload OCNE cluster as a formatted table. 533 func showNodeInfo(client *kubernetes.Clientset, clustername string, log *zap.SugaredLogger) error { 534 writer := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', tabwriter.AlignRight) 535 fmt.Fprintln(writer, "Name\tRole\tVersion\tInternalIP\tExternalIP\tOSImage\tKernelVersion\tContainerRuntime\tAge") 536 nodeList, err := client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) 537 if err != nil { 538 return errors.Wrap(err, fmt.Sprintf("failed to get list of nodes from cluster '%s'", clustername)) 539 } 540 for _, node := range nodeList.Items { 541 labels := node.GetLabels() 542 _, nodeOK := labels[nodeLabel] 543 _, controlPlaneOK := labels[nodeLabel] 544 var role, internalIP string 545 if nodeOK { 546 role = strings.Split(nodeLabel, "/")[len(strings.Split(nodeLabel, "/"))-1] 547 } 548 if controlPlaneOK { 549 role = strings.Split(controlPlaneLabel, "/")[len(strings.Split(controlPlaneLabel, "/"))-1] 550 } 551 552 addresses := node.Status.Addresses 553 for _, address := range addresses { 554 if address.Type == "InternalIP" { 555 internalIP = address.Address 556 break 557 } 558 } 559 fmt.Fprintf(writer, "%v\n", fmt.Sprintf("%v\t%v\t%v\t%v\t%v\t%v\t%v\t%v\t%v", 560 node.GetName(), role, node.Status.NodeInfo.KubeletVersion, internalIP, "None", node.Status.NodeInfo.OSImage, node.Status.NodeInfo.KernelVersion, 561 node.Status.NodeInfo.ContainerRuntimeVersion, time.Until(node.GetCreationTimestamp().Time).Abs())) 562 } 563 writer.Flush() 564 return nil 565 } 566 567 func getVerrazzanoFleetBinding(log *zap.SugaredLogger) (*unstructured.Unstructured, error) { 568 dclient, err := k8sutil.GetDynamicClient() 569 if err != nil { 570 log.Errorf("unable to get workload kubeconfig ", zap.Error(err)) 571 return nil, err 572 } 573 574 gvr := schema.GroupVersionResource{ 575 Group: "addons.cluster.x-k8s.io", 576 Version: "v1alpha1", 577 Resource: "verrazzanofleetbindings", 578 } 579 return dclient.Resource(gvr).Namespace(clusterNamespace).Get(context.TODO(), clusterName, metav1.GetOptions{}) 580 } 581 582 func getVerrazzanoFleet(log *zap.SugaredLogger) (*unstructured.Unstructured, error) { 583 dclient, err := k8sutil.GetDynamicClient() 584 if err != nil { 585 log.Errorf("unable to get workload kubeconfig ", zap.Error(err)) 586 return nil, err 587 } 588 589 gvr := getVerrazzanoFleetGVR() 590 return dclient.Resource(gvr).Namespace(clusterNamespace).Get(context.TODO(), vzFleetName, metav1.GetOptions{}) 591 } 592 593 func getVerrazzanoFleetGVR() schema.GroupVersionResource { 594 gvr := schema.GroupVersionResource{ 595 Group: "addons.cluster.x-k8s.io", 596 Version: "v1alpha1", 597 Resource: "verrazzanofleets", 598 } 599 return gvr 600 } 601 func deleteVerrazzanoFleet(log *zap.SugaredLogger) error { 602 dclient, err := k8sutil.GetDynamicClient() 603 if err != nil { 604 log.Errorf("unable to get workload kubeconfig ", zap.Error(err)) 605 return err 606 } 607 608 gvr := getVerrazzanoFleetGVR() 609 610 return dclient.Resource(gvr).Namespace(clusterNamespace).Delete(context.TODO(), vzFleetName, metav1.DeleteOptions{}) 611 } 612 613 func getCapiClusterDynamicClient(clusterName string, log *zap.SugaredLogger) (dynamic.Interface, error) { 614 615 capiK8sConfig, err := getCapiClusterKubeConfig(clusterName, log) 616 if err != nil { 617 return nil, err 618 } 619 620 k8sRestConfig, err := GetRESTConfigGivenString(capiK8sConfig) 621 if err != nil { 622 log.Errorf("failed to obtain k8s rest config : %v", zap.Error(err)) 623 return nil, err 624 } 625 626 dclient, err := dynamic.NewForConfig(k8sRestConfig) 627 if err != nil { 628 log.Errorf("unable to create dynamic client for workload cluster %v", zap.Error(err)) 629 return nil, err 630 } 631 return dclient, nil 632 633 } 634 635 var _ = t.Describe("addon e2e tests ,", Label("f:addon-provider-verrazzano-e2e-tests"), Serial, func() { 636 WhenClusterAPIInstalledIt("Verify addon controller running", func() { 637 update.ValidatePods("verrazzano-fleet", addonControllerPodLabel, addonControllerPodNamespace, 1, false) 638 }) 639 t.Context(fmt.Sprintf("Create VerrazzanoFleet resource '%s'", clusterName), func() { 640 WhenClusterAPIInstalledIt("Create verrrazanoFleet", func() { 641 Eventually(func() error { 642 return ctx.applyVerrazzanoFleet() 643 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred(), "Create verrazzanoFleet resource") 644 }) 645 WhenClusterAPIInstalledIt("Verify if VerrazzanoFleetBinding resource created", func() { 646 Eventually(func() error { 647 return ensureVerrazzanoFleetBindingExists(clusterName, t.Logs) 648 }, shortWaitTimeout, shortPollingInterval).Should(BeNil(), "verify VerrazzanoFleetBinding resource") 649 }) 650 651 WhenClusterAPIInstalledIt("Display objects from CAPI workload cluster", func() { 652 Eventually(func() error { 653 return displayWorkloadClusterResources(clusterName, t.Logs) 654 }, shortWaitTimeout, pollingInterval).Should(BeNil(), "Display objects from CAPI workload cluster") 655 }) 656 657 WhenClusterAPIInstalledIt("Verify VPO on the workload cluster", func() { 658 Eventually(func() bool { 659 return ensureVPOPodsAreRunningOnWorkloadCluster(clusterName, "verrazzano-install", t.Logs) 660 }, shortWaitTimeout, vzPollingInterval).Should(BeTrue(), "verify VPO") 661 }) 662 663 WhenClusterAPIInstalledIt("Verify verrazzano CR resource", func() { 664 Eventually(func() error { 665 return ensureVerrazzano(clusterName, t.Logs) 666 }, waitTimeOut, vzPollingInterval).Should(BeNil(), "verify verrazzano resource") 667 }) 668 669 WhenClusterAPIInstalledIt("create verrazzanofleet for unknown workload cluster", func() { 670 Eventually(func() error { 671 return createFleetForUnknownCluster(clusterName, t.Logs) 672 }, waitTimeOut, vzPollingInterval).Should(HaveOccurred(), "create verrazzanofleet for unknown workload cluster") 673 }) 674 675 WhenClusterAPIInstalledIt("verify create multiple verrazzanofleet for the same workload cluster", func() { 676 Eventually(func() error { 677 return createMultipleFleetForSameCluster(clusterName, t.Logs) 678 }, waitTimeOut, vzPollingInterval).Should(HaveOccurred(), "verify create multiple verrazzanofleet for the same workload cluster") 679 }) 680 681 WhenClusterAPIInstalledIt("Display objects from CAPI workload cluster", func() { 682 Eventually(func() error { 683 return displayWorkloadClusterResources(clusterName, t.Logs) 684 }, shortWaitTimeout, pollingInterval).Should(BeNil(), "Display objects from CAPI workload cluster") 685 }) 686 687 WhenClusterAPIInstalledIt("verify update verrazzano spec in verrazzanofleet", func() { 688 Eventually(func() error { 689 return updateVerrazzanoFleet(clusterName, t.Logs) 690 }, waitTimeOut, vzPollingInterval).Should(BeNil(), "verify update verrazzano spec in verrazzanofleet") 691 }) 692 693 WhenClusterAPIInstalledIt("Verify update to verrazzano CR resource ", func() { 694 Eventually(func() error { 695 return ensureVerrazzano(clusterName, t.Logs) 696 }, waitTimeOut, vzPollingInterval).Should(BeNil(), "verify update to verrazzano resource") 697 }) 698 699 WhenClusterAPIInstalledIt("Display objects from CAPI workload cluster", func() { 700 Eventually(func() error { 701 return displayWorkloadClusterResources(clusterName, t.Logs) 702 }, shortWaitTimeout, pollingInterval).Should(BeNil(), "Display objects from CAPI workload cluster") 703 }) 704 705 WhenClusterAPIInstalledIt("Delete VerrazzanoFleet from admin cluster", func() { 706 Eventually(func() error { 707 return deleteVerrazzanoFleet(t.Logs) 708 }, shortWaitTimeout, pollingInterval).Should(BeNil(), "Delete VerrazzanoFleet resource from admin cluster") 709 }) 710 711 WhenClusterAPIInstalledIt("Verify VerrazzanoFleet resource does not exist on adminc luster", func() { 712 Eventually(func() error { 713 return ensureVerrazzanoFleetExists(clusterName, t.Logs) 714 }, shortWaitTimeout, shortPollingInterval).Should(HaveOccurred(), "verify VerrazzanoFleetBinding resource does not exist on admin cluster") 715 }) 716 717 WhenClusterAPIInstalledIt("Verify VerrazzanoFleetBinding resource does not exist on admin cluster", func() { 718 Eventually(func() error { 719 return ensureVerrazzanoFleetBindingExists(clusterName, t.Logs) 720 }, shortWaitTimeout, shortPollingInterval).Should(HaveOccurred(), "verify VerrazzanoFleetBinding resource does not exist on admin cluster") 721 }) 722 723 WhenClusterAPIInstalledIt("Verify VPO does not exist on the workload cluster", func() { 724 Eventually(func() bool { 725 return ensureVPOPodsAreRunningOnWorkloadCluster(clusterName, "verrazzano-install", t.Logs) 726 }, shortWaitTimeout, vzPollingInterval).Should(BeFalse(), "verify VPO does not exist") 727 }) 728 729 WhenClusterAPIInstalledIt("Verify verrazzano CR resource on workload cluster after deleting VerrazzanoFleet resource", func() { 730 Eventually(func() error { 731 return ensureVerrazzano(clusterName, t.Logs) 732 }, waitTimeOut, vzPollingInterval).Should(HaveOccurred(), "verify verrazzano resource on workload cluster after deleting VerrazzanoFleet resource") 733 }) 734 735 WhenClusterAPIInstalledIt("Display objects from CAPI workload cluster", func() { 736 Eventually(func() error { 737 return displayWorkloadClusterResources(clusterName, t.Logs) 738 }, shortWaitTimeout, pollingInterval).Should(BeNil(), "Display objects from CAPI workload cluster") 739 }) 740 }) 741 })