github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/pkg/utils/build/quay.go (about) 1 package build 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "regexp" 9 "strings" 10 11 quay "github.com/konflux-ci/image-controller/pkg/quay" 12 . "github.com/onsi/gomega" 13 "github.com/openshift/library-go/pkg/image/reference" 14 "github.com/redhat-appstudio/e2e-tests/pkg/constants" 15 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 16 corev1 "k8s.io/api/core/v1" 17 ) 18 19 var ( 20 quayApiUrl = "https://quay.io/api/v1" 21 quayOrg = utils.GetEnv("DEFAULT_QUAY_ORG", "redhat-appstudio-qe") 22 quayToken = utils.GetEnv("DEFAULT_QUAY_ORG_TOKEN", "") 23 quayClient = quay.NewQuayClient(&http.Client{Transport: &http.Transport{}}, quayToken, quayApiUrl) 24 ) 25 26 func GetQuayImageName(annotations map[string]string) (string, error) { 27 type imageAnnotation struct { 28 Image string `json:"Image"` 29 Secret string `json:"Secret"` 30 } 31 image_annotation_str := annotations["image.redhat.com/image"] 32 var ia imageAnnotation 33 err := json.Unmarshal([]byte(image_annotation_str), &ia) 34 if err != nil { 35 return "", err 36 } 37 tokens := strings.Split(ia.Image, "/") 38 return strings.Join(tokens[2:], "/"), nil 39 } 40 41 func IsImageAnnotationPresent(annotations map[string]string) bool { 42 image_annotation_str := annotations["image.redhat.com/image"] 43 return image_annotation_str != "" 44 } 45 46 func ImageRepoCreationSucceeded(annotations map[string]string) bool { 47 imageAnnotationValue := annotations["image.redhat.com/image"] 48 return !strings.Contains(imageAnnotationValue, "failed to generete image repository") 49 } 50 51 func GetRobotAccountName(imageName string) string { 52 tokens := strings.Split(imageName, "/") 53 return strings.Join(tokens, "") 54 } 55 56 func DoesImageRepoExistInQuay(quayImageRepoName string) (bool, error) { 57 exists, err := quayClient.DoesRepositoryExist(quayOrg, quayImageRepoName) 58 if exists { 59 return true, nil 60 } else if !exists && strings.Contains(err.Error(), "does not exist") { 61 return false, nil 62 } else { 63 return false, err 64 } 65 } 66 67 func DoesRobotAccountExistInQuay(robotAccountName string) (bool, error) { 68 _, err := quayClient.GetRobotAccount(quayOrg, robotAccountName) 69 if err != nil { 70 if err.Error() == "Could not find robot with specified username" { 71 return false, nil 72 } else { 73 return false, err 74 } 75 } 76 return true, nil 77 } 78 79 func DeleteImageRepo(imageName string) (bool, error) { 80 if imageName == "" { 81 return false, nil 82 } 83 _, err := quayClient.DeleteRepository(quayOrg, imageName) 84 if err != nil { 85 return false, err 86 } 87 return true, nil 88 } 89 90 // imageURL format example: quay.io/redhat-appstudio-qe/devfile-go-rhtap-uvv7:build-66d4e-1685533053 91 func DoesTagExistsInQuay(imageURL string) (bool, error) { 92 ref, err := reference.Parse(imageURL) 93 if err != nil { 94 return false, err 95 } 96 if ref.Tag == "" { 97 return false, fmt.Errorf("image URL %s does not have tag", imageURL) 98 } 99 if ref.Namespace == "" { 100 return false, fmt.Errorf("image URL %s does not have namespace", imageURL) 101 } 102 tagList, _, err := quayClient.GetTagsFromPage(ref.Namespace, ref.Name, 0) 103 if err != nil { 104 return false, err 105 } 106 for _, tag := range tagList { 107 if tag.Name == ref.Tag { 108 return true, nil 109 } 110 } 111 return false, nil 112 } 113 114 func IsImageRepoPublic(quayImageRepoName string) (bool, error) { 115 return quayClient.IsRepositoryPublic(quayOrg, quayImageRepoName) 116 } 117 118 func DoesQuayOrgSupportPrivateRepo() (bool, error) { 119 repositoryRequest := quay.RepositoryRequest{ 120 Namespace: quayOrg, 121 Visibility: "private", 122 Description: "Test private repository", 123 Repository: constants.SamplePrivateRepoName, 124 } 125 repo, err := quayClient.CreateRepository(repositoryRequest) 126 if err != nil { 127 if err.Error() == "payment required" { 128 return false, nil 129 } else { 130 return false, err 131 } 132 } 133 if repo == nil { 134 return false, fmt.Errorf("%v repository created is nil", repo) 135 } 136 // Delete the created image repo 137 _, err = DeleteImageRepo(constants.SamplePrivateRepoName) 138 if err != nil { 139 return true, fmt.Errorf("error while deleting private image repo: %v", err) 140 } 141 return true, nil 142 } 143 144 // GetRobotAccountToken gets the robot account token from a given robot account name 145 func GetRobotAccountToken(robotAccountName string) (string, error) { 146 ra, err := quayClient.GetRobotAccount(quayOrg, robotAccountName) 147 if err != nil { 148 return "", err 149 } 150 151 return ra.Token, nil 152 } 153 154 // GetRobotAccountInfoFromSecret gets robot account name and token from secret data 155 func GetRobotAccountInfoFromSecret(secret *corev1.Secret) (string, string) { 156 uploadSecretDockerconfigJson := string(secret.Data[corev1.DockerConfigJsonKey]) 157 var authDataJson interface{} 158 Expect(json.Unmarshal([]byte(uploadSecretDockerconfigJson), &authDataJson)).To(Succeed()) 159 160 authRegexp := regexp.MustCompile(`.*{"auth":"([A-Za-z0-9+/=]*)"}.*`) 161 uploadSecretAuthString, err := base64.StdEncoding.DecodeString(authRegexp.FindStringSubmatch(uploadSecretDockerconfigJson)[1]) 162 Expect(err).To(Succeed()) 163 164 auth := strings.Split(string(uploadSecretAuthString), ":") 165 Expect(auth).To(HaveLen(2)) 166 167 robotAccountName := strings.TrimPrefix(auth[0], quayOrg+"+") 168 robotAccountToken := auth[1] 169 170 return robotAccountName, robotAccountToken 171 } 172 173 func GetImageTag(organization, repository, tagName string) (quay.Tag, error) { 174 page := 0 175 for { 176 page++ 177 tags, hasAdditional, err := quayClient.GetTagsFromPage(organization, repository, page) 178 if err != nil { 179 return quay.Tag{}, err 180 } 181 for _, tag := range tags { 182 if tag.Name == tagName { 183 return tag, nil 184 } 185 } 186 if !hasAdditional { 187 return quay.Tag{}, fmt.Errorf(fmt.Sprintf("cannot find tag %s", tagName)) 188 } 189 } 190 }