github.com/redhat-appstudio/e2e-tests@v0.0.0-20230619105049-9a422b2094d7/tests/spi/quay-imagepullsecret-usage.go (about) 1 package spi 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "strings" 8 "time" 9 10 "github.com/google/uuid" 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 "github.com/redhat-appstudio/e2e-tests/pkg/constants" 14 "github.com/redhat-appstudio/e2e-tests/pkg/framework" 15 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 16 "github.com/redhat-appstudio/service-provider-integration-operator/api/v1beta1" 17 taskrunv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" 18 corev1 "k8s.io/api/core/v1" 19 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 ) 21 22 /* 23 * Component: spi 24 * Description: SVPI-407 - Check ImagePullSecret usage for the private Quay image 25 SVPI-408 - Check the secret that can be used with scopeo Tekton task to authorize a copy of one private Quay image to the second Quay image repository 26 * Note: To avoid code repetition, SVPI-408 was integrated with SVPI-407 27 28 * Flow of the test: 29 * 1º - creates SPITokenBinding 30 * 2º - uploads token 31 * 3º - creates a Pod from a Private Quay image 32 * 4º - checks the secret that can be used with scopeo Tekton task to authorize a copy of one private Quay image to the second Quay image repository 33 */ 34 35 var _ = framework.SPISuiteDescribe(Label("spi-suite", "quay-imagepullsecret-usage"), func() { 36 37 defer GinkgoRecover() 38 39 var fw *framework.Framework 40 var err error 41 var namespace string 42 var QuayAuthToken string 43 var QuayAuthUser string 44 45 Describe("SVPI-407 - Check ImagePullSecret usage for the private Quay image", Ordered, func() { 46 BeforeAll(func() { 47 if os.Getenv("CI") != "true" { 48 Skip(fmt.Sprintln("test skipped on local execution")) 49 } 50 // Initialize the tests controllers 51 fw, err = framework.NewFramework(utils.GetGeneratedNamespace("spi-demos")) 52 Expect(err).NotTo(HaveOccurred()) 53 namespace = fw.UserNamespace 54 Expect(namespace).NotTo(BeEmpty()) 55 56 // collect SPI ResourceQuota metrics (temporary) 57 err := fw.AsKubeAdmin.CommonController.GetResourceQuotaInfo("token-upload-rest-endpoint", namespace, "appstudio-crds-spi") 58 Expect(err).NotTo(HaveOccurred()) 59 60 // Quay username and token are required by SPI to generate valid credentials 61 QuayAuthToken = utils.GetEnv(constants.QUAY_OAUTH_TOKEN_ENV, "") 62 QuayAuthUser = utils.GetEnv(constants.QUAY_OAUTH_USER_ENV, "") 63 Expect(QuayAuthToken).NotTo(BeEmpty()) 64 Expect(QuayAuthUser).NotTo(BeEmpty()) 65 }) 66 67 // Clean up after running these tests and before the next tests block: can't have multiple AccessTokens in Injected phase 68 AfterAll(func() { 69 // collect SPI ResourceQuota metrics (temporary) 70 err := fw.AsKubeAdmin.CommonController.GetResourceQuotaInfo("quay-imagepullsecret-usage", namespace, "appstudio-crds-spi") 71 Expect(err).NotTo(HaveOccurred()) 72 73 if !CurrentSpecReport().Failed() { 74 Expect(fw.AsKubeAdmin.SPIController.DeleteAllBindingTokensInASpecificNamespace(namespace)).To(Succeed()) 75 Expect(fw.AsKubeAdmin.SPIController.DeleteAllAccessTokensInASpecificNamespace(namespace)).To(Succeed()) 76 Expect(fw.AsKubeAdmin.SPIController.DeleteAllAccessTokenDataInASpecificNamespace(namespace)).To(Succeed()) 77 Expect(fw.AsKubeAdmin.CommonController.DeleteAllServiceAccountsInASpecificNamespace(namespace)).To(Succeed()) 78 Expect(fw.AsKubeAdmin.TektonController.DeleteAllTasksInASpecificNamespace(namespace)).To(Succeed()) 79 Expect(fw.AsKubeAdmin.TektonController.DeleteAllTaskRunsInASpecificNamespace(namespace)).To(Succeed()) 80 } 81 }) 82 83 var SPITokenBinding *v1beta1.SPIAccessTokenBinding 84 var QuaySPITokenBindingName = "quay-spi-token-binding" 85 var SecretName = "test-secret-dockerconfigjson" 86 var TestQuayPrivateRepoURL = fmt.Sprintf("%s:test", QuayPrivateRepoURL) 87 88 It("creates SPITokenBinding", func() { 89 SPITokenBinding, err = fw.AsKubeDeveloper.SPIController.CreateSPIAccessTokenBinding(QuaySPITokenBindingName, namespace, TestQuayPrivateRepoURL, SecretName, corev1.SecretTypeDockerConfigJson) 90 Expect(err).NotTo(HaveOccurred()) 91 92 SPITokenBinding, err = fw.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace) 93 Expect(err).NotTo(HaveOccurred()) 94 }) 95 96 // start of upload token 97 It("SPITokenBinding to be in AwaitingTokenData phase", func() { 98 // wait SPITokenBinding to be in AwaitingTokenData phase before trying to upload a token 99 Eventually(func() bool { 100 SPITokenBinding, err = fw.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace) 101 Expect(err).NotTo(HaveOccurred()) 102 103 return (SPITokenBinding.Status.Phase == v1beta1.SPIAccessTokenBindingPhaseAwaitingTokenData) 104 }, 1*time.Minute, 5*time.Second).Should(BeTrue(), "SPIAccessTokenBinding is not in AwaitingTokenData phase") 105 }) 106 107 It("uploads username and token using rest endpoint", func() { 108 // the UploadUrl in SPITokenBinding should be available before uploading the token 109 Eventually(func() bool { 110 SPITokenBinding, err = fw.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace) 111 Expect(err).NotTo(HaveOccurred()) 112 113 return SPITokenBinding.Status.UploadUrl != "" 114 }, 1*time.Minute, 10*time.Second).Should(BeTrue(), "uploadUrl not set") 115 Expect(err).NotTo(HaveOccurred()) 116 117 // linked accessToken token should exist 118 linkedAccessTokenName := SPITokenBinding.Status.LinkedAccessTokenName 119 Expect(linkedAccessTokenName).NotTo(BeEmpty()) 120 121 // get the url to manually upload the token 122 uploadURL := SPITokenBinding.Status.UploadUrl 123 Expect(uploadURL).NotTo(BeEmpty()) 124 125 // Get the token for the current openshift user 126 bearerToken, err := utils.GetOpenshiftToken() 127 Expect(err).NotTo(HaveOccurred()) 128 129 // build and upload the payload using the uploadURL. it should return 204 130 oauthCredentials := `{"access_token":"` + utils.GetEnv(constants.QUAY_OAUTH_TOKEN_ENV, "") + `", "username":"` + utils.GetEnv(constants.QUAY_OAUTH_USER_ENV, "") + `"}` 131 statusCode, err := fw.AsKubeDeveloper.SPIController.UploadWithRestEndpoint(uploadURL, oauthCredentials, bearerToken) 132 Expect(err).NotTo(HaveOccurred()) 133 Expect(statusCode).Should(Equal(204)) 134 }) 135 136 It("SPITokenBinding to be in Injected phase", func() { 137 Eventually(func() bool { 138 SPITokenBinding, err = fw.AsKubeDeveloper.SPIController.GetSPIAccessTokenBinding(SPITokenBinding.Name, namespace) 139 Expect(err).NotTo(HaveOccurred()) 140 return SPITokenBinding.Status.Phase == v1beta1.SPIAccessTokenBindingPhaseInjected 141 }, 1*time.Minute, 5*time.Second).Should(BeTrue(), "SPIAccessTokenBinding is not in Injected phase") 142 }) 143 144 It("SPIAccessToken exists and is in Read phase", func() { 145 Eventually(func() bool { 146 SPIAccessToken, err := fw.AsKubeDeveloper.SPIController.GetSPIAccessToken(SPITokenBinding.Status.LinkedAccessTokenName, namespace) 147 148 if err != nil { 149 return false 150 } 151 152 return (SPIAccessToken.Status.Phase == v1beta1.SPIAccessTokenPhaseReady) 153 }, 1*time.Minute, 5*time.Second).Should(BeTrue(), "SPIAccessToken should be in ready phase") 154 }) 155 156 // Create a pod using the generated ImagePullSecret to pull a private quay image 157 It("creates a Pod from a Private Quay image", func() { 158 pod := &corev1.Pod{ 159 ObjectMeta: metav1.ObjectMeta{Name: "rtw"}, 160 Spec: corev1.PodSpec{ 161 RestartPolicy: corev1.RestartPolicyNever, 162 Containers: []corev1.Container{ 163 { 164 Name: "quay-image", 165 Image: TestQuayPrivateRepoURL, 166 ImagePullPolicy: corev1.PullAlways, 167 }, 168 }, 169 ImagePullSecrets: []corev1.LocalObjectReference{ 170 {Name: SPITokenBinding.Status.SyncedObjectRef.Name}, 171 }, 172 }} 173 174 pod, err = fw.AsKubeAdmin.CommonController.KubeInterface().CoreV1().Pods(namespace).Create(context.Background(), pod, metav1.CreateOptions{}) 175 pod, err := fw.AsKubeAdmin.CommonController.GetPod(namespace, pod.Name) 176 Expect(err).NotTo(HaveOccurred()) 177 178 Eventually(func() bool { 179 pod, err := fw.AsKubeAdmin.CommonController.GetPod(namespace, pod.Name) 180 Expect(err).NotTo(HaveOccurred()) 181 182 return pod.Status.Phase == corev1.PodRunning 183 }, 1*time.Minute, 5*time.Second).Should(BeTrue(), "Pod not created successfully") 184 }) 185 186 Describe("SVPI-408 - Check the secret that can be used with skopeo Tekton task to authorize a copy of one private Quay image to the second Quay image repository", Ordered, func() { 187 serviceAccountName := "tekton-task-service-account" 188 189 It("creates skopeo copy task", func() { 190 err := fw.AsKubeAdmin.TektonController.CreateSkopeoCopyTask(namespace) 191 Expect(err).NotTo(HaveOccurred()) 192 193 _, err = fw.AsKubeDeveloper.TektonController.GetTask("skopeo-copy", namespace) 194 Expect(err).NotTo(HaveOccurred()) 195 }) 196 197 It("creates service account for the TaskRun referencing the docker config json secret", func() { 198 secrets := []corev1.ObjectReference{ 199 {Name: SecretName}, 200 } 201 _, err := fw.AsKubeAdmin.CommonController.CreateServiceAccount(serviceAccountName, namespace, secrets) 202 Expect(err).NotTo(HaveOccurred()) 203 _, err = fw.AsKubeAdmin.CommonController.GetServiceAccount(serviceAccountName, namespace) 204 Expect(err).NotTo(HaveOccurred()) 205 }) 206 207 var TaskRun *taskrunv1beta1.TaskRun 208 taskRunName := "skopeo-run" 209 210 It("creates taskrun", func() { 211 srcImageURL := fmt.Sprintf("docker://%s", TestQuayPrivateRepoURL) 212 destTag := fmt.Sprintf("spi-test-%s", strings.Replace(uuid.New().String(), "-", "", -1)) 213 destImageURL := fmt.Sprintf("docker://%s:%s", QuayPrivateRepoURL, destTag) 214 215 TaskRun, err = fw.AsKubeAdmin.TektonController.CreateTaskRunCopy(taskRunName, namespace, serviceAccountName, srcImageURL, destImageURL) 216 Expect(err).NotTo(HaveOccurred()) 217 TaskRun, err = fw.AsKubeDeveloper.TektonController.GetTaskRun(taskRunName, namespace) 218 Expect(err).NotTo(HaveOccurred()) 219 }) 220 221 It("checks if taskrun is complete", func() { 222 Eventually(func() bool { 223 TaskRun, err = fw.AsKubeDeveloper.TektonController.GetTaskRun(taskRunName, namespace) 224 Expect(err).NotTo(HaveOccurred()) 225 226 return TaskRun.Status.CompletionTime != nil 227 }, 1*time.Minute, 5*time.Second).Should(BeTrue(), "taskrun is not complete") 228 }) 229 230 It("checks if taskrun is successful", func() { 231 TaskRun, err = fw.AsKubeDeveloper.TektonController.GetTaskRun(taskRunName, namespace) 232 Expect(err).NotTo(HaveOccurred()) 233 Expect(len(TaskRun.Status.Conditions)).NotTo(BeZero()) 234 Expect(TaskRun.Status.Conditions[0].Status).To(Equal(corev1.ConditionTrue)) 235 }) 236 }) 237 238 }) 239 })