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  })