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  }