github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/release/pipelines/rh_push_to_external_registry.go (about) 1 package pipelines 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "os" 8 "time" 9 10 "github.com/devfile/library/v2/pkg/util" 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 appservice "github.com/redhat-appstudio/application-api/api/v1alpha1" 14 "github.com/redhat-appstudio/e2e-tests/pkg/clients/has" 15 "github.com/redhat-appstudio/e2e-tests/pkg/clients/release" 16 "github.com/redhat-appstudio/e2e-tests/pkg/constants" 17 "github.com/redhat-appstudio/e2e-tests/pkg/framework" 18 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 19 "github.com/redhat-appstudio/e2e-tests/pkg/utils/contract" 20 "github.com/redhat-appstudio/e2e-tests/pkg/utils/tekton" 21 releasecommon "github.com/redhat-appstudio/e2e-tests/tests/release" 22 releaseApi "github.com/redhat-appstudio/release-service/api/v1alpha1" 23 tektonutils "github.com/redhat-appstudio/release-service/tekton/utils" 24 pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" 25 "k8s.io/apimachinery/pkg/runtime" 26 27 ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1" 28 corev1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 ) 31 32 var _ = framework.ReleasePipelinesSuiteDescribe("[HACBS-1571]test-release-e2e-push-image-to-pyxis", Label("release-pipelines", "pushPyxis", "HACBS"), func() { 33 defer GinkgoRecover() 34 // Initialize the tests controllers 35 var fw *framework.Framework 36 AfterEach(framework.ReportFailure(&fw)) 37 var err error 38 var devNamespace, managedNamespace, compName, additionalCompName string 39 var avgControllerQueryTimeout = 5 * time.Minute 40 41 var imageIDs []string 42 var pyxisKeyDecoded, pyxisCertDecoded []byte 43 var releasePR1, releasePR2 *pipeline.PipelineRun 44 scGitRevision := fmt.Sprintf("test-pyxis-%s", util.GenerateRandomString(4)) 45 46 var component1, component2 *appservice.Component 47 var snapshot1, snapshot2 *appservice.Snapshot 48 var releaseCR1, releaseCR2 *releaseApi.Release 49 50 var componentDetected, additionalComponentDetected appservice.ComponentDetectionDescription 51 52 BeforeAll(func() { 53 fw, err = framework.NewFramework(utils.GetGeneratedNamespace("push-pyxis")) 54 Expect(err).NotTo(HaveOccurred()) 55 devNamespace = fw.UserNamespace 56 managedNamespace = utils.GetGeneratedNamespace("push-pyxis-managed") 57 58 _, err = fw.AsKubeAdmin.CommonController.CreateTestNamespace(managedNamespace) 59 Expect(err).NotTo(HaveOccurred(), "Error when creating managedNamespace") 60 61 sourceAuthJson := utils.GetEnv("QUAY_TOKEN", "") 62 Expect(sourceAuthJson).ToNot(BeEmpty()) 63 64 keyPyxisStage := os.Getenv(constants.PYXIS_STAGE_KEY_ENV) 65 Expect(keyPyxisStage).ToNot(BeEmpty()) 66 67 certPyxisStage := os.Getenv(constants.PYXIS_STAGE_CERT_ENV) 68 Expect(certPyxisStage).ToNot(BeEmpty()) 69 70 // Create secret for the release registry repo "hacbs-release-tests". 71 _, err = fw.AsKubeAdmin.CommonController.CreateRegistryAuthSecret(releasecommon.RedhatAppstudioUserSecret, managedNamespace, sourceAuthJson) 72 Expect(err).ToNot(HaveOccurred()) 73 74 // Linking the build secret to the pipeline service account in dev namespace. 75 err = fw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(devNamespace, releasecommon.HacbsReleaseTestsTokenSecret, constants.DefaultPipelineServiceAccount, true) 76 Expect(err).ToNot(HaveOccurred()) 77 78 publicKey, err := fw.AsKubeAdmin.TektonController.GetTektonChainsPublicKey() 79 Expect(err).ToNot(HaveOccurred()) 80 81 // Creating k8s secret to access Pyxis stage based on base64 decoded of key and cert 82 pyxisKeyDecoded, err = base64.StdEncoding.DecodeString(string(keyPyxisStage)) 83 Expect(err).ToNot(HaveOccurred()) 84 85 pyxisCertDecoded, err = base64.StdEncoding.DecodeString(string(certPyxisStage)) 86 Expect(err).ToNot(HaveOccurred()) 87 88 secret := &corev1.Secret{ 89 ObjectMeta: metav1.ObjectMeta{ 90 Name: "pyxis", 91 Namespace: managedNamespace, 92 }, 93 Type: corev1.SecretTypeOpaque, 94 Data: map[string][]byte{ 95 "cert": pyxisCertDecoded, 96 "key": pyxisKeyDecoded, 97 }, 98 } 99 100 _, err = fw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, secret) 101 Expect(err).ToNot(HaveOccurred()) 102 103 Expect(fw.AsKubeAdmin.TektonController.CreateOrUpdateSigningSecret( 104 publicKey, releasecommon.PublicSecretNameAuth, managedNamespace)).To(Succeed()) 105 106 defaultECP, err := fw.AsKubeAdmin.TektonController.GetEnterpriseContractPolicy("default", "enterprise-contract-service") 107 Expect(err).NotTo(HaveOccurred()) 108 policy := contract.PolicySpecWithSourceConfig(defaultECP.Spec, ecp.SourceConfig{Include: []string{"@minimal"}, Exclude: []string{"cve"}}) 109 110 managedServiceAccount, err := fw.AsKubeAdmin.CommonController.CreateServiceAccount(releasecommon.ReleasePipelineServiceAccountDefault, managedNamespace, releasecommon.ManagednamespaceSecret, nil) 111 Expect(err).NotTo(HaveOccurred()) 112 113 _, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePipelineRoleBindingForServiceAccount(managedNamespace, managedServiceAccount) 114 Expect(err).NotTo(HaveOccurred()) 115 116 err = fw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, releasecommon.RedhatAppstudioUserSecret, releasecommon.ReleasePipelineServiceAccountDefault, true) 117 Expect(err).ToNot(HaveOccurred()) 118 119 // using cdq since git ref is not known 120 cdq, err := fw.AsKubeAdmin.HasController.CreateComponentDetectionQuery(releasecommon.ComponentName, devNamespace, releasecommon.GitSourceComponentUrl, "", "", "", false) 121 Expect(err).NotTo(HaveOccurred()) 122 Expect(cdq.Status.ComponentDetected).To(HaveLen(1), "Expected length of the detected Components was not 1") 123 124 for _, compDetected := range cdq.Status.ComponentDetected { 125 compName = compDetected.ComponentStub.ComponentName 126 componentDetected = compDetected 127 } 128 129 // using cdq since git ref is not known 130 additionalCompName = releasecommon.AdditionalComponentName 131 cdq, err = fw.AsKubeAdmin.HasController.CreateComponentDetectionQuery(additionalCompName, devNamespace, releasecommon.AdditionalGitSourceComponentUrl, "", "", "", false) 132 Expect(err).NotTo(HaveOccurred()) 133 Expect(cdq.Status.ComponentDetected).To(HaveLen(1), "Expected length of the detected Components was not 1") 134 135 for _, compDetected := range cdq.Status.ComponentDetected { 136 additionalCompName = compDetected.ComponentStub.ComponentName 137 additionalComponentDetected = compDetected 138 } 139 140 _, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePlan(releasecommon.SourceReleasePlanName, devNamespace, releasecommon.ApplicationNameDefault, managedNamespace, "true", nil) 141 Expect(err).NotTo(HaveOccurred()) 142 143 data, err := json.Marshal(map[string]interface{}{ 144 "mapping": map[string]interface{}{ 145 "components": []map[string]interface{}{ 146 { 147 "name": compName, 148 "repository": "quay.io/" + utils.GetQuayIOOrganization() + "/dcmetromap", 149 }, 150 { 151 "name": additionalCompName, 152 "repository": "quay.io/" + utils.GetQuayIOOrganization() + "/simplepython", 153 }, 154 }, 155 }, 156 "pyxis": map[string]interface{}{ 157 "server": "stage", 158 "secret": "pyxis", 159 }, 160 }) 161 Expect(err).NotTo(HaveOccurred()) 162 163 _, err = fw.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission(releasecommon.TargetReleasePlanAdmissionName, managedNamespace, "", devNamespace, releasecommon.ReleaseStrategyPolicyDefault, releasecommon.ReleasePipelineServiceAccountDefault, []string{releasecommon.ApplicationNameDefault}, true, &tektonutils.PipelineRef{ 164 Resolver: "git", 165 Params: []tektonutils.Param{ 166 {Name: "url", Value: releasecommon.RelSvcCatalogURL}, 167 {Name: "revision", Value: releasecommon.RelSvcCatalogRevision}, 168 {Name: "pathInRepo", Value: "pipelines/rh-push-to-external-registry/rh-push-to-external-registry.yaml"}, 169 }, 170 }, &runtime.RawExtension{ 171 Raw: data, 172 }) 173 Expect(err).NotTo(HaveOccurred()) 174 175 _, err = fw.AsKubeAdmin.TektonController.CreateEnterpriseContractPolicy(releasecommon.ReleaseStrategyPolicyDefault, managedNamespace, policy) 176 Expect(err).NotTo(HaveOccurred()) 177 178 _, err = fw.AsKubeAdmin.TektonController.CreatePVCInAccessMode(releasecommon.ReleasePvcName, managedNamespace, corev1.ReadWriteOnce) 179 Expect(err).NotTo(HaveOccurred()) 180 181 _, err = fw.AsKubeAdmin.CommonController.CreateRole("role-release-service-account", managedNamespace, map[string][]string{ 182 "apiGroupsList": {""}, 183 "roleResources": {"secrets"}, 184 "roleVerbs": {"get", "list", "watch"}, 185 }) 186 Expect(err).NotTo(HaveOccurred()) 187 188 _, err = fw.AsKubeAdmin.CommonController.CreateRoleBinding("role-release-service-account-binding", managedNamespace, "ServiceAccount", releasecommon.ReleasePipelineServiceAccountDefault, managedNamespace, "Role", "role-release-service-account", "rbac.authorization.k8s.io") 189 Expect(err).NotTo(HaveOccurred()) 190 191 _, err = fw.AsKubeAdmin.HasController.CreateApplication(releasecommon.ApplicationNameDefault, devNamespace) 192 Expect(err).NotTo(HaveOccurred()) 193 }) 194 195 AfterAll(func() { 196 err = fw.AsKubeAdmin.CommonController.Github.DeleteRef(constants.StrategyConfigsRepo, scGitRevision) 197 if err != nil { 198 Expect(err.Error()).To(ContainSubstring("Reference does not exist")) 199 } 200 if !CurrentSpecReport().Failed() { 201 Expect(fw.AsKubeAdmin.CommonController.DeleteNamespace(managedNamespace)).NotTo(HaveOccurred()) 202 Expect(fw.SandboxController.DeleteUserSignup(fw.UserName)).To(BeTrue()) 203 } 204 }) 205 206 var _ = Describe("Post-release verification", func() { 207 208 It("verifies that Component 1 can be created and build PipelineRun is created for it in dev namespace and succeeds", func() { 209 component1, err = fw.AsKubeAdmin.HasController.CreateComponent(componentDetected.ComponentStub, devNamespace, "", "", releasecommon.ApplicationNameDefault, true, map[string]string{}) 210 Expect(err).NotTo(HaveOccurred()) 211 Expect(fw.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component1, "", 212 fw.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, nil)).To(Succeed()) 213 }) 214 215 It("verifies that Component 2 can be created and build PipelineRun is created for it in dev namespace and succeeds", func() { 216 component2, err = fw.AsKubeAdmin.HasController.CreateComponent(additionalComponentDetected.ComponentStub, devNamespace, "", "", releasecommon.ApplicationNameDefault, true, map[string]string{}) 217 Expect(err).NotTo(HaveOccurred()) 218 Expect(fw.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component2, "", 219 fw.AsKubeAdmin.TektonController, &has.RetryOptions{Retries: 2, Always: true}, nil)).To(Succeed()) 220 }) 221 222 It("tests that Snapshot is created for each Component", func() { 223 Eventually(func() error { 224 snapshot1, err = fw.AsKubeAdmin.IntegrationController.GetSnapshot("", "", component1.GetName(), devNamespace) 225 if err != nil { 226 GinkgoWriter.Printf("cannot get the Snapshot for component %s/%s: %v\n", component1.GetNamespace(), component1.GetName(), err) 227 return err 228 } 229 snapshot2, err = fw.AsKubeAdmin.IntegrationController.GetSnapshot("", "", component2.GetName(), devNamespace) 230 if err != nil { 231 GinkgoWriter.Printf("cannot get the Snapshot for component %s/%s: %v\n", component2.GetNamespace(), component2.GetName(), err) 232 return err 233 } 234 return nil 235 }, 5*time.Minute, releasecommon.DefaultInterval).Should(Succeed(), "timed out waiting for Snapshots to be created in %s namespace", devNamespace) 236 }) 237 238 It("tests that associated Release CR is created for each Component's Snapshot", func() { 239 Eventually(func() error { 240 releaseCR1, err = fw.AsKubeAdmin.ReleaseController.GetRelease("", snapshot1.GetName(), devNamespace) 241 if err != nil { 242 GinkgoWriter.Printf("cannot get the Release CR for snapshot %s/%s: %v\n", snapshot1.GetNamespace(), component1.GetName(), err) 243 return err 244 } 245 releaseCR2, err = fw.AsKubeAdmin.ReleaseController.GetRelease("", snapshot2.GetName(), devNamespace) 246 if err != nil { 247 GinkgoWriter.Printf("cannot get the Release CR for snapshot %s/%s: %v\n", snapshot2.GetNamespace(), component1.GetName(), err) 248 return err 249 } 250 return nil 251 }, releasecommon.ReleaseCreationTimeout, releasecommon.DefaultInterval).Should(Succeed(), "timed out waiting for Release CRs to be created in %s namespace", devNamespace) 252 }) 253 254 It("verifies that Release PipelineRun is triggered for each Release CR", func() { 255 Eventually(func() error { 256 releasePR1, err = fw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedNamespace, releaseCR1.GetName(), releaseCR1.GetNamespace()) 257 if err != nil { 258 GinkgoWriter.Printf("release pipelineRun for Release %s/%s not created yet: %+v\n", releaseCR1.GetNamespace(), releaseCR1.GetName(), err) 259 return err 260 } 261 releasePR2, err = fw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedNamespace, releaseCR2.GetName(), releaseCR2.GetNamespace()) 262 if err != nil { 263 GinkgoWriter.Printf("release pipelineRun for Release %s/%s not created yet: %+v\n", releaseCR2.GetNamespace(), releaseCR2.GetName(), err) 264 return err 265 } 266 var errMsg string 267 for _, pr := range []*pipeline.PipelineRun{releasePR1, releasePR2} { 268 Expect(tekton.HasPipelineRunFailed(pr)).ToNot(BeTrue(), fmt.Sprintf("Release PipelineRun %s/%s failed", pr.GetNamespace(), pr.GetName())) 269 if !pr.HasStarted() { 270 errMsg += fmt.Sprintf("Release PipelineRun %s/%s did not started yet\n", pr.GetNamespace(), pr.GetName()) 271 } 272 } 273 if len(errMsg) > 1 { 274 return fmt.Errorf(errMsg) 275 } 276 return nil 277 }, releasecommon.ReleasePipelineRunCreationTimeout, constants.PipelineRunPollingInterval).Should(Succeed(), fmt.Sprintf("timed out waiting for a PipelineRun to start for each Release CR in %s namespace", managedNamespace)) 278 }) 279 280 It("verifies a release PipelineRun for each component succeeded in managed namespace", func() { 281 Eventually(func() error { 282 var errMsg string 283 for _, pr := range []*pipeline.PipelineRun{releasePR1, releasePR2} { 284 pr, err = fw.AsKubeAdmin.TektonController.GetPipelineRun(pr.GetName(), pr.GetNamespace()) 285 if err != nil { 286 return err 287 } 288 Expect(tekton.HasPipelineRunFailed(pr)).ToNot(BeTrue(), fmt.Sprintf("Release PipelineRun %s/%s failed", pr.GetNamespace(), pr.GetName())) 289 if pr.IsDone() { 290 Expect(tekton.HasPipelineRunSucceeded(pr)).To(BeTrue(), fmt.Sprintf("Release PipelineRun %s/%s did not succceed", pr.GetNamespace(), pr.GetName())) 291 } else { 292 errMsg += fmt.Sprintf("Release PipelineRun %s/%s did not finish yet\n", pr.GetNamespace(), pr.GetName()) 293 } 294 } 295 if len(errMsg) > 1 { 296 return fmt.Errorf(errMsg) 297 } 298 return nil 299 }, releasecommon.ReleasePipelineRunCompletionTimeout, constants.PipelineRunPollingInterval).Should(Succeed()) 300 }) 301 302 It("validate the result of task create-pyxis-image contains image ids", func() { 303 Eventually(func() []string { 304 releasePR1, err = fw.AsKubeAdmin.TektonController.GetPipelineRun(releasePR1.GetName(), releasePR1.GetNamespace()) 305 Expect(err).NotTo(HaveOccurred()) 306 releasePR2, err = fw.AsKubeAdmin.TektonController.GetPipelineRun(releasePR2.GetName(), releasePR2.GetNamespace()) 307 Expect(err).NotTo(HaveOccurred()) 308 309 trReleaseLogs, err := fw.AsKubeAdmin.TektonController.GetTaskRunLogs(releasePR1.GetName(), "create-pyxis-image", releasePR1.GetNamespace()) 310 Expect(err).NotTo(HaveOccurred()) 311 312 trAdditionalReleaseLogs, err := fw.AsKubeAdmin.TektonController.GetTaskRunLogs(releasePR2.GetName(), "create-pyxis-image", releasePR2.GetNamespace()) 313 Expect(err).NotTo(HaveOccurred()) 314 315 trReleaseImageIDs, err := fw.AsKubeAdmin.ReleaseController.GetPyxisImageIDsFromCreatePyxisImageTaskLogs(trReleaseLogs) 316 Expect(err).NotTo(HaveOccurred()) 317 trAdditionalReleaseIDs, err := fw.AsKubeAdmin.ReleaseController.GetPyxisImageIDsFromCreatePyxisImageTaskLogs(trAdditionalReleaseLogs) 318 Expect(err).NotTo(HaveOccurred()) 319 320 Expect(trReleaseImageIDs).NotTo(BeEmpty(), fmt.Sprintf("Invalid ImageID in results of task create-pyxis-image. TaskRun log: %+s", trReleaseLogs)) 321 Expect(trAdditionalReleaseIDs).ToNot(BeEmpty(), fmt.Sprintf("Invalid ImageID in results of task create-pyxis-image. TaskRun log: %+s", trAdditionalReleaseLogs)) 322 323 Expect(trReleaseImageIDs).ToNot(HaveLen(len(trAdditionalReleaseIDs)), "the number of image IDs should not be the same in both taskrun results. (%+v vs. %+v)", trReleaseImageIDs, trAdditionalReleaseIDs) 324 325 if len(trReleaseImageIDs) > len(trAdditionalReleaseIDs) { 326 imageIDs = trReleaseImageIDs 327 } else { 328 imageIDs = trAdditionalReleaseIDs 329 } 330 331 return imageIDs 332 }, avgControllerQueryTimeout, releasecommon.DefaultInterval).Should(HaveLen(2)) 333 }) 334 335 It("tests that associated Release CR has completed for each Component's Snapshot", func() { 336 Eventually(func() error { 337 var errMsg string 338 for _, cr := range []*releaseApi.Release{releaseCR1, releaseCR2} { 339 cr, err = fw.AsKubeAdmin.ReleaseController.GetRelease("", cr.Spec.Snapshot, devNamespace) 340 Expect(err).ShouldNot(HaveOccurred()) 341 if !cr.IsReleased() { 342 errMsg += fmt.Sprintf("release %s/%s is not marked as finished yet", cr.GetNamespace(), cr.GetName()) 343 } 344 } 345 if len(errMsg) > 1 { 346 return fmt.Errorf(errMsg) 347 } 348 return nil 349 }, releasecommon.ReleaseCreationTimeout, releasecommon.DefaultInterval).Should(Succeed(), "timed out waiting for Release CRs to be created in %s namespace", devNamespace) 350 }) 351 352 It("validates that imageIds from task create-pyxis-image exist in Pyxis.", func() { 353 for _, imageID := range imageIDs { 354 Eventually(func() error { 355 body, err := fw.AsKubeAdmin.ReleaseController.GetPyxisImageByImageID(releasecommon.PyxisStageImagesApiEndpoint, imageID, 356 []byte(pyxisCertDecoded), []byte(pyxisKeyDecoded)) 357 Expect(err).NotTo(HaveOccurred(), "failed to get response body") 358 359 sbomImage := release.Image{} 360 Expect(json.Unmarshal(body, &sbomImage)).To(Succeed(), "failed to unmarshal body content: %s", string(body)) 361 362 return nil 363 }, releasecommon.ReleaseCreationTimeout, releasecommon.DefaultInterval).Should(Succeed()) 364 } 365 }) 366 }) 367 })