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  }