github.com/redhat-appstudio/e2e-tests@v0.0.0-20230619105049-9a422b2094d7/tests/byoc/byoc.go (about) 1 package byoc 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "time" 8 9 "github.com/devfile/library/pkg/util" 10 "github.com/magefile/mage/sh" 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 appservice "github.com/redhat-appstudio/application-api/api/v1alpha1" 14 client "github.com/redhat-appstudio/e2e-tests/pkg/apis/kubernetes" 15 "github.com/redhat-appstudio/e2e-tests/pkg/apis/vcluster" 16 "github.com/redhat-appstudio/e2e-tests/pkg/framework" 17 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 18 appsv1 "k8s.io/api/apps/v1" 19 corev1 "k8s.io/api/core/v1" 20 v1 "k8s.io/api/networking/v1" 21 "k8s.io/apimachinery/pkg/api/errors" 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 "k8s.io/client-go/kubernetes" 24 "k8s.io/client-go/tools/clientcmd" 25 ) 26 27 const ( 28 ManagedEnvironmentSecretName string = "byoc-managed-environment" 29 ManagedEnvironmentType string = "managed-gitops.redhat.com/managed-environment" 30 ManagedEnvironmentName string = "development" 31 QuarkusDevfileSource string = "https://github.com/devfile-samples/devfile-sample-code-with-quarkus" 32 QuarkusComponentEndpoint string = "/hello-resteasy" 33 ) 34 35 var ( 36 applicationName = utils.GetGeneratedNamespace("byoc-app") 37 cdqName = utils.GetGeneratedNamespace("byoc-comp") 38 ) 39 40 // Initialize simple scenarios to test RHTAP byoc feature flow: Feature jira link: https://issues.redhat.com/browse/RHTAP-129 41 // QE Test Jira link: https://issues.redhat.com/browse/RHTAP-542 42 var byocTestScenario = []Scenario{ 43 { 44 Name: "Deploy RHTAP sample application into a Kubernetes cluster provided by user", 45 ApplicationService: ApplicationService{ 46 GithubRepository: QuarkusDevfileSource, 47 ApplicationName: applicationName, 48 }, 49 Byoc: Byoc{ 50 ClusterType: appservice.ConfigurationClusterType_Kubernetes, 51 TargetNamespace: utils.GetGeneratedNamespace("byoc-k8s-target"), 52 }, 53 }, 54 { 55 Name: "Deploy RHTAP sample application into a Openshift cluster provided by user", 56 ApplicationService: ApplicationService{ 57 GithubRepository: QuarkusDevfileSource, 58 ApplicationName: applicationName, 59 }, 60 Byoc: Byoc{ 61 ClusterType: appservice.ConfigurationClusterType_OpenShift, 62 TargetNamespace: utils.GetGeneratedNamespace("byoc-ocp-target"), 63 }, 64 }, 65 } 66 67 var _ = framework.E2ESuiteDescribe(Label("byoc"), Ordered, func() { 68 rootPath, err := os.Getwd() 69 Expect(err).NotTo(HaveOccurred()) 70 71 var vc vcluster.Vcluster 72 var ephemeralClusterClient *kubernetes.Clientset 73 var fw *framework.Framework 74 var byocKubeconfig, byocAPIServerURL, kubeIngressDomain string 75 76 // Initialize the application struct 77 application := &appservice.Application{} 78 cdq := &appservice.ComponentDetectionQuery{} 79 compDetected := appservice.ComponentDetectionDescription{} 80 componentObj := &appservice.Component{} 81 82 for _, suite := range byocTestScenario { 83 suite := suite 84 85 Describe(suite.Name, func() { 86 BeforeAll(func() { 87 fw, err = framework.NewFramework(utils.GetGeneratedNamespace("byoc")) 88 Expect(err).NotTo(HaveOccurred()) 89 90 // Use target test cluster as Ingress for the cluster provided for user. Ingress is mandatory for kubernetes cluster like vcluster in this case. 91 openshiftIngress, err := fw.AsKubeAdmin.CommonController.GetOpenshiftIngress() 92 Expect(err).NotTo(HaveOccurred()) 93 94 kubeIngressDomain = openshiftIngress.Spec.Domain 95 Expect(kubeIngressDomain).NotTo(BeEmpty(), "domain is not pressent in the cluster. Make sure your openshift cluster have the domain defined in ingress cluster object") 96 97 if suite.Byoc.ClusterType == appservice.ConfigurationClusterType_Kubernetes { 98 Expect(sh.Run("which", "vcluster")).NotTo(HaveOccurred(), "please install vcluster locally in order to run kubernetes suite") 99 100 vc = vcluster.NewVclusterController(fmt.Sprintf("%s/tmp", rootPath), fw.AsKubeAdmin.CommonController.CustomClient) 101 102 byocKubeconfig, err = vc.InitializeVCluster(fw.UserNamespace, fw.UserNamespace, kubeIngressDomain) 103 Expect(err).NotTo(HaveOccurred()) 104 Expect(byocKubeconfig).NotTo(BeEmpty(), "failed to initialize vcluster. Kubeconfig not provided") 105 106 } else if suite.Byoc.ClusterType == appservice.ConfigurationClusterType_OpenShift { 107 byocKubeconfig = utils.GetEnv("BYOC_KUBECONFIG", "") 108 Expect(byocKubeconfig).NotTo(BeEmpty(), "Please provide BYOC_KUBECONFIG env pointing to a valid openshift kubeconfig file") 109 } 110 }) 111 112 // Remove all resources created by the tests in case the suite was successfull 113 AfterAll(func() { 114 if !CurrentSpecReport().Failed() { 115 Expect(fw.AsKubeDeveloper.HasController.DeleteAllComponentsInASpecificNamespace(fw.UserNamespace, 30*time.Second)).To(Succeed()) 116 Expect(fw.AsKubeAdmin.HasController.DeleteAllApplicationsInASpecificNamespace(fw.UserNamespace, 30*time.Second)).To(Succeed()) 117 Expect(fw.AsKubeAdmin.HasController.DeleteAllSnapshotEnvBindingsInASpecificNamespace(fw.UserNamespace, 30*time.Second)).To(Succeed()) 118 Expect(fw.AsKubeAdmin.ReleaseController.DeleteAllSnapshotsInASpecificNamespace(fw.UserNamespace, 30*time.Second)).To(Succeed()) 119 Expect(fw.AsKubeAdmin.GitOpsController.DeleteAllEnvironmentsInASpecificNamespace(fw.UserNamespace, 30*time.Second)).To(Succeed()) 120 Expect(fw.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(fw.UserNamespace)).To(Succeed()) 121 Expect(fw.AsKubeAdmin.GitOpsController.DeleteAllGitOpsDeploymentInASpecificNamespace(fw.UserNamespace, 30*time.Second)).To(Succeed()) 122 Expect(fw.SandboxController.DeleteUserSignup(fw.UserName)).NotTo(BeFalse()) 123 } 124 }) 125 126 It("initializes byoc cluster connection and creates targetNamespace", func() { 127 config, err := clientcmd.BuildConfigFromFlags("", byocKubeconfig) 128 Expect(err).NotTo(HaveOccurred()) 129 byocAPIServerURL = config.Host 130 Expect(byocAPIServerURL).NotTo(BeEmpty()) 131 132 ephemeralClusterClient, err = client.NewKubeFromKubeConfigFile(byocKubeconfig) 133 Expect(err).NotTo(HaveOccurred()) 134 135 // Cluster is managed by a user so we need to create the target cluster where we will deploy the RHTAP components 136 ns, err := ephemeralClusterClient.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: suite.Byoc.TargetNamespace}}, metav1.CreateOptions{}) 137 Expect(err).NotTo(HaveOccurred()) 138 Expect(ns.Name).To(Equal(suite.Byoc.TargetNamespace)) 139 }) 140 141 It("creates managed-gitops.redhat.com/managed-environment secret type", func() { 142 kubeConfData, err := os.ReadFile(byocKubeconfig) 143 data := make(map[string][]byte) 144 data["kubeconfig"] = kubeConfData 145 Expect(err).NotTo(HaveOccurred()) 146 147 secret := &corev1.Secret{ 148 ObjectMeta: metav1.ObjectMeta{ 149 Name: ManagedEnvironmentSecretName, 150 Namespace: fw.UserNamespace, 151 }, 152 Type: corev1.SecretType(ManagedEnvironmentType), 153 Data: data, 154 } 155 156 _, err = fw.AsKubeAdmin.CommonController.CreateSecret(fw.UserNamespace, secret) 157 Expect(err).NotTo(HaveOccurred()) 158 }) 159 160 It("creates environment", func() { 161 // Note: It is not possible yet to configure integration service snapshots to deploy to a specific environment. 162 // As an workaround for now: Deletes the development environment and recreate it with kubernetes cluster information 163 Expect(fw.AsKubeAdmin.GitOpsController.DeleteAllEnvironmentsInASpecificNamespace(fw.UserNamespace, 1*time.Minute)).NotTo(HaveOccurred()) 164 165 environment, err := fw.AsKubeAdmin.GitOpsController.CreateEphemeralEnvironment(ManagedEnvironmentName, fw.UserNamespace, suite.Byoc.TargetNamespace, byocAPIServerURL, ManagedEnvironmentSecretName, suite.Byoc.ClusterType, kubeIngressDomain) 166 Expect(environment.Name).To(Equal(ManagedEnvironmentName)) 167 Expect(err).NotTo(HaveOccurred()) 168 }) 169 170 It("creates RHTAP application and check healths", func() { 171 createdApplication, err := fw.AsKubeDeveloper.HasController.CreateHasApplication(applicationName, fw.UserNamespace) 172 Expect(err).NotTo(HaveOccurred()) 173 Expect(createdApplication.Spec.DisplayName).To(Equal(applicationName)) 174 Expect(createdApplication.Namespace).To(Equal(fw.UserNamespace)) 175 176 Eventually(func() string { 177 application, err = fw.AsKubeAdmin.HasController.GetHasApplication(applicationName, fw.UserNamespace) 178 Expect(err).NotTo(HaveOccurred()) 179 180 return application.Status.Devfile 181 }, 3*time.Minute, 100*time.Millisecond).Should(Not(BeEmpty()), "Error creating gitOps repository") 182 183 Eventually(func() bool { 184 // application info should be stored even after deleting the application in application variable 185 gitOpsRepository := utils.ObtainGitOpsRepositoryName(application.Status.Devfile) 186 187 return fw.AsKubeAdmin.CommonController.Github.CheckIfRepositoryExist(gitOpsRepository) 188 }, 1*time.Minute, 1*time.Second).Should(BeTrue(), "Has controller didn't create gitops repository") 189 }) 190 191 It("creates Red Hat AppStudio ComponentDetectionQuery for Component repository", func() { 192 _, err := fw.AsKubeAdmin.HasController.CreateComponentDetectionQuery(cdqName, fw.UserNamespace, suite.ApplicationService.GithubRepository, "", "", "", false) 193 Expect(err).NotTo(HaveOccurred()) 194 }) 195 196 It("validates CDQ object information", func() { 197 // Validate that the CDQ completes successfully 198 Eventually(func() bool { 199 // application info should be stored even after deleting the application in application variable 200 cdq, err = fw.AsKubeAdmin.HasController.GetComponentDetectionQuery(cdqName, fw.UserNamespace) 201 return err == nil && len(cdq.Status.ComponentDetected) > 0 202 }, 1*time.Minute, 1*time.Second).Should(BeTrue(), "ComponentDetectionQuery did not complete successfully") 203 204 // Validate that the completed CDQ only has one detected component 205 Expect(len(cdq.Status.ComponentDetected)).To(Equal(1), "Expected length of the detected Components was not 1") 206 207 // Get the stub CDQ and validate its content 208 for _, compDetected = range cdq.Status.ComponentDetected { 209 Expect(compDetected.DevfileFound).To(BeTrue(), "DevfileFound was not set to true") 210 Expect(compDetected.Language).To(Equal("Java"), "Detected language was not java") 211 Expect(compDetected.ProjectType).To(Equal("Quarkus"), "Detected framework was not quarkus") 212 } 213 }) 214 215 It("creates Red Hat AppStudio Quarkus component", func() { 216 compDetected.ComponentStub.ComponentName = util.GenerateRandomString(4) 217 componentObj, err = fw.AsKubeAdmin.HasController.CreateComponentFromStub(compDetected, fw.UserNamespace, "", "", applicationName) 218 Expect(err).NotTo(HaveOccurred()) 219 }) 220 221 It("waits component pipeline to finish", func() { 222 223 Expect(fw.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(componentObj, "", 2)).To(Succeed()) 224 }) 225 226 // Deploy the component using gitops and check for the health 227 It(fmt.Sprintf("checks if component %s was deployed in the target cluster and namespace", componentObj.Name), func() { 228 var deployment *appsv1.Deployment 229 Eventually(func() bool { 230 deployment, err = ephemeralClusterClient.AppsV1().Deployments(suite.Byoc.TargetNamespace).Get(context.TODO(), componentObj.Name, metav1.GetOptions{}) 231 if err != nil && !errors.IsNotFound(err) { 232 return false 233 } 234 if deployment.Status.AvailableReplicas == 1 { 235 GinkgoWriter.Printf("Deployment %s is ready\n", deployment.Name) 236 return true 237 } 238 239 return false 240 }, 25*time.Minute, 10*time.Second).Should(BeTrue(), fmt.Sprintf("Component deployment didn't become ready: %+v", deployment)) 241 Expect(err).NotTo(HaveOccurred()) 242 }) 243 244 if suite.Byoc.ClusterType == appservice.ConfigurationClusterType_Kubernetes { 245 It("checks if ingress exists and is accessible in the kubernetes ephemeral cluster", func() { 246 var ingress *v1.Ingress 247 Eventually(func() bool { 248 ingress, err = ephemeralClusterClient.NetworkingV1().Ingresses(suite.Byoc.TargetNamespace).Get(context.TODO(), componentObj.Name, metav1.GetOptions{}) 249 if err != nil && !errors.IsNotFound(err) { 250 return false 251 } 252 253 return true 254 }, 10*time.Minute, 10*time.Second).Should(BeTrue(), fmt.Sprintf("ingress didn't appear in target cluster in 10 minutes: %+v", ingress)) 255 256 if len(ingress.Spec.Rules) == 0 { 257 Fail("kubernetes ingress set any rule during component creation") 258 } 259 260 // Add complex endpoint checks when: https://issues.redhat.com/browse/DEVHAS-367 is ready 261 Eventually(func() bool { 262 // Add endpoint of component when: https://issues.redhat.com/browse/DEVHAS-367 is ready 263 return utils.HostIsAccessible(fmt.Sprintf("http://%s", ingress.Spec.Rules[0].Host)) 264 }, 10*time.Minute, 10*time.Second).Should(BeTrue(), fmt.Sprintf("ingress is not accessible: %+v", ingress)) 265 }) 266 } 267 }) 268 } 269 })