github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/tests/release/pipelines/rh_push_to_redhat_io.go (about)

     1  package pipelines
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os"
     8  	"regexp"
     9  	"time"
    10  
    11  	"github.com/devfile/library/v2/pkg/util"
    12  	ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1"
    13  	. "github.com/onsi/ginkgo/v2"
    14  	. "github.com/onsi/gomega"
    15  	appservice "github.com/redhat-appstudio/application-api/api/v1alpha1"
    16  	"github.com/redhat-appstudio/e2e-tests/pkg/clients/has"
    17  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    18  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    19  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    20  	"github.com/redhat-appstudio/e2e-tests/pkg/utils/tekton"
    21  	tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
    22  	releaseapi "github.com/redhat-appstudio/release-service/api/v1alpha1"
    23  	releasecommon "github.com/redhat-appstudio/e2e-tests/tests/release"
    24  	tektonutils "github.com/redhat-appstudio/release-service/tekton/utils"
    25  	"k8s.io/apimachinery/pkg/runtime"
    26  	corev1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  )
    29  
    30  const (
    31  	rhioServiceAccountName   = "release-service-account"
    32  	rhioCatalogPathInRepo    = "pipelines/rh-push-to-registry-redhat-io/rh-push-to-registry-redhat-io.yaml"
    33  )
    34  
    35  var testComponent *appservice.Component
    36  
    37  var _ = framework.ReleasePipelinesSuiteDescribe("e2e tests for rh-push-to-redhat-io pipeline", Label("release-pipelines", "rh-push-to-redhat-io"), func() {
    38  	defer GinkgoRecover()
    39  	var pyxisKeyDecoded, pyxisCertDecoded []byte
    40  
    41  	var devWorkspace = utils.GetEnv(constants.RELEASE_DEV_WORKSPACE_ENV, constants.DevReleaseTeam)
    42  	var managedWorkspace = utils.GetEnv(constants.RELEASE_MANAGED_WORKSPACE_ENV, constants.ManagedReleaseTeam)
    43  
    44  	var devNamespace = devWorkspace + "-tenant"
    45  	var managedNamespace = managedWorkspace + "-tenant"
    46  
    47  	var err error
    48  	var devFw *framework.Framework
    49  	var managedFw *framework.Framework
    50  	var rhioApplicationName = "rhio-app-" + util.GenerateRandomString(4)
    51  	var rhioComponentName = "rhio-comp-" + util.GenerateRandomString(4)
    52  	var rhioReleasePlanName = "rhio-rp-" + util.GenerateRandomString(4)
    53  	var rhioReleasePlanAdmissionName = "rhio-rpa-" + util.GenerateRandomString(4)
    54  	var rhioEnterpriseContractPolicyName = "rhio-policy-" + util.GenerateRandomString(4)
    55  
    56  	var snapshot *appservice.Snapshot
    57  	var releaseCR *releaseapi.Release
    58  	var releasePR, buildPR *tektonv1.PipelineRun
    59  
    60  	AfterEach(framework.ReportFailure(&devFw))
    61  
    62  	Describe("Rh-push-to-redhat-io happy path", Label("PushToRedhatIO"), func() {
    63  		BeforeAll(func() {
    64  			devFw = releasecommon.NewFramework(devWorkspace)
    65  			managedFw = releasecommon.NewFramework(managedWorkspace)
    66  			managedNamespace = managedFw.UserNamespace
    67  
    68  			keyPyxisStage := os.Getenv(constants.PYXIS_STAGE_KEY_ENV)
    69  			Expect(keyPyxisStage).ToNot(BeEmpty())
    70  
    71  			certPyxisStage := os.Getenv(constants.PYXIS_STAGE_CERT_ENV)
    72  			Expect(certPyxisStage).ToNot(BeEmpty())
    73  
    74  			// Creating k8s secret to access Pyxis stage based on base64 decoded of key and cert
    75  			pyxisKeyDecoded, err = base64.StdEncoding.DecodeString(string(keyPyxisStage))
    76  			Expect(err).ToNot(HaveOccurred())
    77  
    78  			pyxisCertDecoded, err = base64.StdEncoding.DecodeString(string(certPyxisStage))
    79  			Expect(err).ToNot(HaveOccurred())
    80  
    81  			secret := &corev1.Secret{
    82  				ObjectMeta: metav1.ObjectMeta{
    83  					Name:      "pyxis",
    84  					Namespace: managedNamespace,
    85  				},
    86  				Type: corev1.SecretTypeOpaque,
    87  				Data: map[string][]byte{
    88  					"cert": pyxisCertDecoded,
    89  					"key":  pyxisKeyDecoded,
    90  				},
    91  			}
    92  
    93  			// Delete the secret if it exists in case it is not correct
    94  			_ = managedFw.AsKubeAdmin.CommonController.DeleteSecret(managedNamespace, "pyxis")
    95  			_, err = managedFw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, secret)
    96  			Expect(err).ToNot(HaveOccurred())
    97  
    98  			err = managedFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, releasecommon.RedhatAppstudioUserSecret, constants.DefaultPipelineServiceAccount, true)
    99  			Expect(err).ToNot(HaveOccurred())
   100  
   101  			_, err = devFw.AsKubeDeveloper.HasController.CreateApplication(rhioApplicationName, devNamespace)
   102  			Expect(err).NotTo(HaveOccurred())
   103  
   104  			 _, err = devFw.AsKubeDeveloper.ReleaseController.CreateReleasePlan(rhioReleasePlanName, devNamespace, rhioApplicationName, managedNamespace, "true", nil)
   105  			Expect(err).NotTo(HaveOccurred())
   106  
   107  			testComponent = releasecommon.CreateComponentByCDQ(*devFw, devNamespace, managedNamespace, rhioApplicationName, rhioComponentName, releasecommon.AdditionalGitSourceComponentUrl)
   108  			createRHIOReleasePlanAdmission(rhioReleasePlanAdmissionName, *managedFw, devNamespace, managedNamespace, rhioApplicationName, rhioEnterpriseContractPolicyName, rhioCatalogPathInRepo)
   109  
   110  			createRHIOEnterpriseContractPolicy(rhioEnterpriseContractPolicyName, *managedFw, devNamespace, managedNamespace)
   111  		})
   112  
   113  		AfterAll(func() {
   114  			devFw = releasecommon.NewFramework(devWorkspace)
   115  			managedFw = releasecommon.NewFramework(managedWorkspace)
   116  			Expect(devFw.AsKubeDeveloper.HasController.DeleteApplication(rhioApplicationName, devNamespace, false)).NotTo(HaveOccurred())
   117  			Expect(managedFw.AsKubeDeveloper.TektonController.DeleteEnterpriseContractPolicy(rhioEnterpriseContractPolicyName, managedNamespace, false)).NotTo(HaveOccurred())
   118  			Expect(managedFw.AsKubeDeveloper.ReleaseController.DeleteReleasePlanAdmission(rhioReleasePlanAdmissionName, managedNamespace, false)).NotTo(HaveOccurred())
   119  		})
   120  
   121  		var _ = Describe("Post-release verification", func() {
   122  			It("verifies that a build PipelineRun is created in dev namespace and succeeds", func() {
   123  				devFw = releasecommon.NewFramework(devWorkspace)
   124  				// Create a ticker that ticks every 3 minutes
   125  				ticker := time.NewTicker(3 * time.Minute)
   126  				// Schedule the stop of the ticker after 15 minutes
   127  				time.AfterFunc(10*time.Minute, func() {
   128  					ticker.Stop()
   129  					fmt.Println("Stopped executing every 3 minutes.")
   130  				})
   131  				// Run a goroutine to handle the ticker ticks
   132  				go func() {
   133  					for range ticker.C {
   134  						devFw = releasecommon.NewFramework(devWorkspace)
   135  					}
   136  				}()
   137  				Eventually(func() error {
   138  					buildPR, err = devFw.AsKubeDeveloper.HasController.GetComponentPipelineRun(testComponent.Name, rhioApplicationName, devNamespace, "")
   139  					if err != nil {
   140  						return err
   141  					}
   142  					if !buildPR.IsDone() {
   143  						return fmt.Errorf("build pipelinerun %s in namespace %s did not finish yet", buildPR.Name, buildPR.Namespace)
   144  					}
   145  					Expect(tekton.HasPipelineRunSucceeded(buildPR)).To(BeTrue(), fmt.Sprintf("build pipelinerun %s/%s did not succeed", buildPR.GetNamespace(), buildPR.GetName()))
   146  					snapshot, err = devFw.AsKubeDeveloper.IntegrationController.GetSnapshot("", buildPR.Name, "", devNamespace)
   147  					if err != nil {
   148  						return err
   149  					}
   150  					return nil
   151  				}, releasecommon.BuildPipelineRunCompletionTimeout, releasecommon.DefaultInterval).Should(Succeed(), "timed out when waiting for build pipelinerun to be created")
   152  				Expect(devFw.AsKubeDeveloper.HasController.WaitForComponentPipelineToBeFinished(testComponent, "", devFw.AsKubeDeveloper.TektonController, &has.RetryOptions{Retries: 3, Always: true}, nil)).To(Succeed())
   153  			})
   154  			It("verifies the rhio release pipelinerun is running and succeeds", func() {
   155  				devFw = releasecommon.NewFramework(devWorkspace)
   156  				managedFw = releasecommon.NewFramework(managedWorkspace)
   157  
   158  				Eventually(func() error {
   159  					releaseCR, err = devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace)
   160  					if err != nil {
   161  						return err
   162  					}
   163  					releasePR, err = managedFw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedFw.UserNamespace, releaseCR.GetName(), releaseCR.GetNamespace())
   164  					if err != nil {
   165  						return err
   166  					}
   167  					GinkgoWriter.Println("Release PR: ", releasePR.Name)
   168  					if  !releasePR.IsDone(){
   169  						return fmt.Errorf("release pipelinerun %s in namespace %s did not finished yet", releasePR.Name, releasePR.Namespace)
   170  					}
   171  					return nil
   172  				}, releasecommon.ReleasePipelineRunCompletionTimeout, releasecommon.DefaultInterval).Should(Succeed(), "timed out when waiting for release pipelinerun to succeed")
   173  				Expect(tekton.HasPipelineRunSucceeded(releasePR)).To(BeTrue(), fmt.Sprintf("release pipelinerun %s/%s did not succeed", releasePR.GetNamespace(), releasePR.GetName()))
   174  			})
   175  
   176  			It("verifies release CR completed and set succeeded.", func() {
   177  				devFw = releasecommon.NewFramework(devWorkspace)
   178  				Eventually(func() error {
   179  					releaseCr, err := devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace)
   180  					if err != nil {
   181  						return err
   182  					}
   183  					GinkgoWriter.Println("Release CR: ", releaseCr.Name)
   184  					if !releaseCr.IsReleased() {
   185  						return fmt.Errorf("release %s/%s is not marked as finished yet", releaseCR.GetNamespace(), releaseCR.GetName())
   186  					}
   187  					return nil
   188  				}, 10 * time.Minute, releasecommon.DefaultInterval).Should(Succeed())
   189  			})
   190  
   191  			It("verifies if the MR URL is valid", func() {
   192  				managedFw = releasecommon.NewFramework(managedWorkspace)
   193  				releasePR, err = managedFw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedFw.UserNamespace, releaseCR.GetName(), releaseCR.GetNamespace())
   194  				Expect(err).NotTo(HaveOccurred())
   195  
   196  				trReleaseLogs, err := managedFw.AsKubeAdmin.TektonController.GetTaskRunLogs(releasePR.GetName(), "run-file-updates", releasePR.GetNamespace())
   197  				Expect(err).NotTo(HaveOccurred())
   198  
   199  				var log, mrURL string
   200  				for _, tasklog := range trReleaseLogs {
   201  					log = tasklog
   202  				}
   203  
   204  				re := regexp.MustCompile(`(?:MR Created: )(.+)`)
   205  				mrURL = re.FindStringSubmatch(log)[1]
   206  
   207  				pattern := `https?://[^/\s]+/[^/\s]+/[^/\s]+/+\-\/merge_requests\/(\d+)`
   208  				re, err = regexp.Compile(pattern)
   209  				Expect(err).NotTo(HaveOccurred())
   210  				Expect(re.MatchString(mrURL)).To(BeTrue(), fmt.Sprintf("MR URL %s is not valid", mrURL))
   211  			})
   212  		})
   213  	})
   214  })
   215  
   216  func createRHIOEnterpriseContractPolicy(rhioECPName string, managedFw framework.Framework, devNamespace, managedNamespace string) {
   217  	defaultEcPolicySpec := ecp.EnterpriseContractPolicySpec{
   218  		Description: "Red Hat's enterprise requirements",
   219  		PublicKey:   "k8s://openshift-pipelines/public-key",
   220  		Sources: []ecp.Source{{
   221  			Name:   "Default",
   222  			Policy: []string{releasecommon.EcPolicyLibPath, releasecommon.EcPolicyReleasePath},
   223  			Data:   []string{releasecommon.EcPolicyDataBundle, releasecommon.EcPolicyDataPath},
   224  		}},
   225  		Configuration: &ecp.EnterpriseContractPolicyConfiguration{
   226  			Exclude: []string{"cve", "step_image_registries", "tasks.required_tasks_found:prefetch-dependencies"},
   227  			Include: []string{"minimal"},
   228  		},
   229  	}
   230  
   231  	_, err := managedFw.AsKubeDeveloper.TektonController.CreateEnterpriseContractPolicy(rhioECPName, managedNamespace, defaultEcPolicySpec)
   232  	Expect(err).NotTo(HaveOccurred())
   233  
   234  }
   235  
   236  func createRHIOReleasePlanAdmission(rhioRPAName string, managedFw framework.Framework, devNamespace, managedNamespace, rhioAppName, rhioECPName, pathInRepoValue string) {
   237  	var err error
   238  
   239  	data, err := json.Marshal(map[string]interface{}{
   240  		"mapping": map[string]interface{}{
   241  			"components": []map[string]interface{}{
   242  				{
   243  					"name"       : testComponent.GetName(),
   244  					"repository" : "quay.io/redhat-pending/rhtap----konflux-release-e2e",
   245  				},
   246  			},
   247  		},
   248  		"pyxis": map[string]interface{}{
   249  			"server": "stage",
   250  			"secret": "pyxis",
   251  		},
   252  		"images": map[string]interface{}{
   253  			"defaultTag":      "latest",
   254  			"addGitShaTag":    false,
   255  			"addTimestampTag": false,
   256  			"addSourceShaTag": false,
   257  			"floatingTags":    []string{"testtag", "testtag2"},
   258  		},
   259  		"fileUpdates":  []map[string]interface{}{
   260  			{
   261  				"repo": releasecommon.GitLabRunFileUpdatesTestRepo,
   262  				"upstream_repo": releasecommon.GitLabRunFileUpdatesTestRepo,
   263  				"ref": "master",
   264  				"paths": []map[string]interface{}{
   265  					{
   266  						"path": "data/app-interface/app-interface-settings.yml",
   267  						"replacements": []map[string]interface{}{
   268  							{
   269  								"key": ".description",
   270  								// description: App Interface settings 
   271  								"replacement": "|description:.*|description: {{ .components[0].containerImage }}|",
   272  							},
   273  						},
   274  					},
   275  				},
   276  			},
   277  		},
   278  		"sign": map[string]interface{}{
   279  			"configMapName": "hacbs-signing-pipeline-config-redhatbeta2",
   280  		},
   281  	})
   282  	Expect(err).NotTo(HaveOccurred())
   283  
   284  	_, err = managedFw.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission(rhioRPAName, managedNamespace, "", devNamespace, rhioECPName, rhioServiceAccountName, []string{rhioAppName}, true, &tektonutils.PipelineRef{
   285  		Resolver: "git",
   286  		Params: []tektonutils.Param{
   287  			{Name: "url", Value: releasecommon.RelSvcCatalogURL},
   288  			{Name: "revision", Value: releasecommon.RelSvcCatalogRevision},
   289  			{Name: "pathInRepo", Value: pathInRepoValue},
   290  		},
   291  	}, &runtime.RawExtension{
   292  		Raw: data,
   293  	})
   294  	Expect(err).NotTo(HaveOccurred())
   295  }