github.com/redhat-appstudio/e2e-tests@v0.0.0-20230619105049-9a422b2094d7/magefiles/installation/install.go (about) 1 package installation 2 3 import ( 4 "context" 5 "encoding/base64" 6 "fmt" 7 "os" 8 9 "github.com/devfile/library/pkg/util" 10 "github.com/go-git/go-git/v5" 11 "github.com/go-git/go-git/v5/config" 12 "github.com/go-git/go-git/v5/plumbing" 13 kubeCl "github.com/redhat-appstudio/e2e-tests/pkg/apis/kubernetes" 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 k8sErrors "k8s.io/apimachinery/pkg/api/errors" 18 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 19 "k8s.io/klog/v2" 20 ) 21 22 const ( 23 DEFAULT_TMP_DIR = "tmp" 24 DEFAULT_INFRA_DEPLOYMENTS_BRANCH = "main" 25 DEFAULT_INFRA_DEPLOYMENTS_GH_ORG = "redhat-appstudio" 26 DEFAULT_LOCAL_FORK_NAME = "qe" 27 DEFAULT_LOCAL_FORK_ORGANIZATION = "redhat-appstudio-qe" 28 DEFAULT_E2E_APPLICATIONS_NAMEPSPACE = "appstudio-e2e-test" 29 DEFAULT_E2E_QUAY_ORG = "redhat-appstudio-qe" 30 ) 31 32 var ( 33 previewInstallArgs = []string{"preview", "--keycloak", "--toolchain"} 34 ) 35 36 type InstallAppStudio struct { 37 // Kubernetes Client to interact with Openshift Cluster 38 KubernetesClient *kubeCl.CustomClient 39 40 // TmpDirectory to store temporary files like git repos or some metadata 41 TmpDirectory string 42 43 // Directory where to clone https://github.com/redhat-appstudio/infra-deployments repo 44 InfraDeploymentsCloneDir string 45 46 // Branch to clone from https://github.com/redhat-appstudio/infra-deployments. By default will be main 47 InfraDeploymentsBranch string 48 49 // Github organization from where will be cloned 50 InfraDeploymentsOrganizationName string 51 52 // Desired fork name for testing 53 LocalForkName string 54 55 // Github organization to use for testing purposes in preview mode 56 LocalGithubForkOrganization string 57 58 // Namespace where build applications will be placed 59 E2EApplicationsNamespace string 60 61 // base64-encoded content of a docker/config.json file which contains a valid login credentials for quay.io 62 QuayToken string 63 64 // Default quay organization for repositories generated by Image-controller 65 DefaultImageQuayOrg string 66 67 // Oauth2 token for default quay organization 68 DefaultImageQuayOrgOAuth2Token string 69 70 // Default expiration for image tags 71 DefaultImageTagExpiration string 72 } 73 74 func NewAppStudioInstallController() (*InstallAppStudio, error) { 75 cwd, _ := os.Getwd() 76 k8sClient, err := kubeCl.NewAdminKubernetesClient() 77 78 if err != nil { 79 return nil, err 80 } 81 82 return &InstallAppStudio{ 83 KubernetesClient: k8sClient, 84 TmpDirectory: DEFAULT_TMP_DIR, 85 InfraDeploymentsCloneDir: fmt.Sprintf("%s/%s/infra-deployments", cwd, DEFAULT_TMP_DIR), 86 InfraDeploymentsBranch: utils.GetEnv("INFRA_DEPLOYMENTS_BRANCH", DEFAULT_INFRA_DEPLOYMENTS_BRANCH), 87 InfraDeploymentsOrganizationName: utils.GetEnv("INFRA_DEPLOYMENTS_ORG", DEFAULT_INFRA_DEPLOYMENTS_GH_ORG), 88 LocalForkName: DEFAULT_LOCAL_FORK_NAME, 89 LocalGithubForkOrganization: utils.GetEnv("MY_GITHUB_ORG", DEFAULT_LOCAL_FORK_ORGANIZATION), 90 QuayToken: utils.GetEnv("QUAY_TOKEN", ""), 91 DefaultImageQuayOrg: utils.GetEnv("DEFAULT_QUAY_ORG", DEFAULT_E2E_QUAY_ORG), 92 DefaultImageQuayOrgOAuth2Token: utils.GetEnv("DEFAULT_QUAY_ORG_TOKEN", ""), 93 DefaultImageTagExpiration: utils.GetEnv(constants.IMAGE_TAG_EXPIRATION_ENV, constants.DefaultImageTagExpiration), 94 }, nil 95 } 96 97 // Start the appstudio installation in preview mode. 98 func (i *InstallAppStudio) InstallAppStudioPreviewMode() error { 99 if _, err := i.cloneInfraDeployments(); err != nil { 100 return err 101 } 102 i.setInstallationEnvironments() 103 104 if err := utils.ExecuteCommandInASpecificDirectory("hack/bootstrap-cluster.sh", previewInstallArgs, i.InfraDeploymentsCloneDir); err != nil { 105 return err 106 } 107 108 return i.createE2EQuaySecret() 109 } 110 111 func (i *InstallAppStudio) setInstallationEnvironments() { 112 os.Setenv("MY_GITHUB_ORG", i.LocalGithubForkOrganization) 113 os.Setenv("MY_GITHUB_TOKEN", utils.GetEnv("GITHUB_TOKEN", "")) 114 os.Setenv("MY_GIT_FORK_REMOTE", i.LocalForkName) 115 os.Setenv("TEST_BRANCH_ID", util.GenerateRandomString(4)) 116 os.Setenv("QUAY_TOKEN", i.QuayToken) 117 os.Setenv("IMAGE_CONTROLLER_QUAY_ORG", i.DefaultImageQuayOrg) 118 os.Setenv("IMAGE_CONTROLLER_QUAY_TOKEN", i.DefaultImageQuayOrgOAuth2Token) 119 os.Setenv("BUILD_SERVICE_IMAGE_TAG_EXPIRATION", i.DefaultImageTagExpiration) 120 } 121 122 func (i *InstallAppStudio) cloneInfraDeployments() (*git.Remote, error) { 123 dirInfo, err := os.Stat(i.InfraDeploymentsCloneDir) 124 125 if !os.IsNotExist(err) && dirInfo.IsDir() { 126 klog.Warningf("folder %s already exists... removing", i.InfraDeploymentsCloneDir) 127 128 err := os.RemoveAll(i.InfraDeploymentsCloneDir) 129 if err != nil { 130 return nil, fmt.Errorf("error removing %s folder", i.InfraDeploymentsCloneDir) 131 } 132 } 133 134 url := fmt.Sprintf("https://github.com/%s/infra-deployments", i.InfraDeploymentsOrganizationName) 135 refName := fmt.Sprintf("refs/heads/%s", i.InfraDeploymentsBranch) 136 klog.Infof("cloning '%s' with git ref '%s'", url, refName) 137 repo, _ := git.PlainClone(i.InfraDeploymentsCloneDir, false, &git.CloneOptions{ 138 URL: url, 139 ReferenceName: plumbing.ReferenceName(refName), 140 Progress: os.Stdout, 141 }) 142 143 return repo.CreateRemote(&config.RemoteConfig{Name: i.LocalForkName, URLs: []string{fmt.Sprintf("https://github.com/%s/infra-deployments.git", i.LocalGithubForkOrganization)}}) 144 } 145 146 // Create secret in e2e-secrets which can be copied to testing namespaces 147 func (i *InstallAppStudio) createE2EQuaySecret() error { 148 quayToken := os.Getenv("QUAY_TOKEN") 149 if quayToken == "" { 150 return fmt.Errorf("failed to obtain quay token from 'QUAY_TOKEN' env; make sure the env exists") 151 } 152 153 decodedToken, err := base64.StdEncoding.DecodeString(quayToken) 154 if err != nil { 155 return fmt.Errorf("failed to decode quay token. Make sure that QUAY_TOKEN env contain a base64 token") 156 } 157 158 namespace := constants.QuayRepositorySecretNamespace 159 _, err = i.KubernetesClient.KubeInterface().CoreV1().Namespaces().Get(context.Background(), namespace, metav1.GetOptions{}) 160 if err != nil { 161 if k8sErrors.IsNotFound(err) { 162 _, err := i.KubernetesClient.KubeInterface().CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ 163 ObjectMeta: metav1.ObjectMeta{ 164 Name: namespace, 165 }, 166 }, metav1.CreateOptions{}) 167 if err != nil { 168 return fmt.Errorf("error when creating namespace %s : %v", namespace, err) 169 } 170 } else { 171 return fmt.Errorf("error when getting namespace %s : %v", namespace, err) 172 } 173 } 174 175 secretName := constants.QuayRepositorySecretName 176 secret, err := i.KubernetesClient.KubeInterface().CoreV1().Secrets(namespace).Get(context.Background(), secretName, metav1.GetOptions{}) 177 178 if err != nil { 179 if k8sErrors.IsNotFound(err) { 180 _, err := i.KubernetesClient.KubeInterface().CoreV1().Secrets(namespace).Create(context.Background(), &corev1.Secret{ 181 ObjectMeta: metav1.ObjectMeta{ 182 Name: secretName, 183 Namespace: namespace, 184 }, 185 Type: corev1.SecretTypeDockerConfigJson, 186 Data: map[string][]byte{ 187 corev1.DockerConfigJsonKey: decodedToken, 188 }, 189 }, metav1.CreateOptions{}) 190 191 if err != nil { 192 return fmt.Errorf("error when creating secret %s : %v", secretName, err) 193 } 194 } else { 195 secret.Data = map[string][]byte{ 196 corev1.DockerConfigJsonKey: decodedToken, 197 } 198 _, err = i.KubernetesClient.KubeInterface().CoreV1().Secrets(namespace).Update(context.TODO(), secret, metav1.UpdateOptions{}) 199 if err != nil { 200 return fmt.Errorf("error when updating secret '%s' namespace: %v", secretName, err) 201 } 202 } 203 } 204 205 return nil 206 }