Skip to content

Commit

Permalink
feat(RELEASE-927): add e2e tests for multi-arch
Browse files Browse the repository at this point in the history
Signed-off-by: Jing Qi <[email protected]>
  • Loading branch information
jinqi7 committed Jun 26, 2024
1 parent ed83b13 commit 134ac92
Show file tree
Hide file tree
Showing 5 changed files with 494 additions and 41 deletions.
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ clean-gitops-repositories:
DRY_RUN=false ./mage -v local:cleanupGithubOrg

clean-github-webhooks:
./mage -v cleanGitHubWebHooks

clean-gitlab-webhooks:
./mage -v cleanGitLabWebHooks
./mage -v cleanWebHooks

clean-quay-repos-and-robots:
./mage -v local:cleanupQuayReposAndRobots
Expand All @@ -75,6 +72,9 @@ clean-private-repos:
clean-registered-servers:
./mage -v CleanupRegisteredPacServers

setup-multi-arch-tests:
./mage -v SetupMultiArchTests

setup-multi-platform-tests:
./mage -v SetupMultiPlatformTests

Expand Down
234 changes: 197 additions & 37 deletions magefiles/magefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (
"github.com/konflux-ci/e2e-tests/magefiles/installation"
"github.com/konflux-ci/e2e-tests/magefiles/upgrade"
"github.com/konflux-ci/e2e-tests/pkg/clients/github"
"github.com/konflux-ci/e2e-tests/pkg/clients/gitlab"
"github.com/konflux-ci/e2e-tests/pkg/clients/slack"
"github.com/konflux-ci/e2e-tests/pkg/clients/sprayproxy"
"github.com/konflux-ci/e2e-tests/pkg/constants"
Expand All @@ -36,7 +35,7 @@ import (
"github.com/konflux-ci/image-controller/pkg/quay"
"github.com/magefile/mage/sh"
tektonapi "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
gl "github.com/xanzy/go-gitlab"
"k8s.io/apimachinery/pkg/selection"
)

const (
Expand All @@ -59,6 +58,7 @@ var (
requiresSprayProxyRegistering bool

requiresMultiPlatformTests bool
requiresMultiArchTests bool
platforms = []string{"linux/arm64", "linux/s390x", "linux/ppc64le"}

sprayProxyConfig *sprayproxy.SprayProxyConfig
Expand Down Expand Up @@ -274,6 +274,12 @@ func (ci CI) TestE2E() error {
}
}

if requiresMultiArchTests {
if err := SetupMultiArchTests(); err != nil {
return err
}
}

if requiresMultiPlatformTests {
if err := SetupMultiPlatformTests(); err != nil {
return err
Expand Down Expand Up @@ -502,6 +508,7 @@ func setRequiredEnvVars() error {
*/
os.Setenv("E2E_TEST_SUITE_LABEL", "e2e-demo,rhtap-demo,spi-suite,remote-secret,integration-service,ec,build-templates,multi-platform")
} else if strings.Contains(jobName, "release-service-catalog") { // release-service-catalog jobs (pull, rehearsal)
requiresMultiArchTests = true
envVarPrefix := "RELEASE_SERVICE"
os.Setenv("E2E_TEST_SUITE_LABEL", "release-pipelines")
// "rehearse" jobs metadata are not relevant for testing
Expand Down Expand Up @@ -542,6 +549,192 @@ func setRequiredEnvVars() error {
return nil
}

func SetupMultiArchTests() error {
klog.Infof("going to create new Tekton bundle remote-build for the purpose of testing multi-arch PR")
var err error
var defaultBundleRef string
var tektonObj runtime.Object
//currently, we can only create one image and the image index
platformType := "linux/amd64"

tag := fmt.Sprintf("%d-%s", time.Now().Unix(), util.GenerateRandomString(4))
quayOrg := utils.GetEnv(constants.DEFAULT_QUAY_ORG_ENV, constants.DefaultQuayOrg)
newMultiPlatformBuilderPipelineImg := strings.ReplaceAll(constants.DefaultImagePushRepo, constants.DefaultQuayOrg, quayOrg)
var newRemotePipeline, _ = name.ParseReference(fmt.Sprintf("%s:pipeline-bundle-%s", newMultiPlatformBuilderPipelineImg, tag))
var newPipelineYaml []byte

if err = utils.CreateDockerConfigFile(os.Getenv("QUAY_TOKEN")); err != nil {
return fmt.Errorf("failed to create docker config file: %+v", err)
}
if defaultBundleRef, err = tekton.GetDefaultPipelineBundleRef(constants.BuildPipelineConfigConfigMapYamlURL, "docker-build"); err != nil {
return fmt.Errorf("failed to get the pipeline bundle ref: %+v", err)
}
if tektonObj, err = tekton.ExtractTektonObjectFromBundle(defaultBundleRef, "pipeline", "docker-build"); err != nil {
return fmt.Errorf("failed to extract the Tekton Pipeline from bundle: %+v", err)
}
dockerPipelineObject := tektonObj.(*tektonapi.Pipeline)

var currentBuildahTaskRef string
for i := range dockerPipelineObject.PipelineSpec().Tasks {
t := &dockerPipelineObject.PipelineSpec().Tasks[i]
if t.Name == "build-source-image" {
t.RunAfter = []string{"build-container"}
for i, p := range t.Params {
tmpParam := &t.Params[i]
if p.Name == "BASE_IMAGES" {
tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.BASE_IMAGES_DIGESTS)")
}
}
}
if t.Name == "ecosystem-cert-preflight-checks" {
t.RunAfter = []string{"build-container"}
for i, p := range t.Params {
tmpParam := &t.Params[i]
if p.Name == "image-url" {
tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_URL)")
}
}
}
if t.Name == "clair-scan" || t.Name == "clamav-scan" {
t.RunAfter = []string{"build-container"}
for i, p := range t.Params {
tmpParam := &t.Params[i]
if p.Name == "image-digest" {
tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_DIGEST)")
}
if p.Name == "image-url" {
tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_URL)")
}
}
}
if t.Name == "deprecated-base-image-check" || t.Name == "sbom-json-check" {
t.RunAfter = []string{"build-container"}
for i, p := range t.Params {
tmpParam := &t.Params[i]
if p.Name == "IMAGE_URL" {
tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_URL)")
}
if p.Name == "IMAGES_DIGESTS" {
tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGES_DIGESTS)")
}
if t.Name == "deprecated-base-image-check" && p.Name == "BASE_IMAGES_DIGESTS" {
tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.BASE_IMAGES_DIGESTS)")
}
}
}
}
for i := range dockerPipelineObject.PipelineSpec().Finally {
t := &dockerPipelineObject.PipelineSpec().Finally[i]
if t.Name == "show-sbom" {
for i, p := range t.Params {
tmpParam := &t.Params[i]
if p.Name == "IMAGE_URL" {
tmpParam.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.IMAGE_URL)")
}
}
}
}
for i := range dockerPipelineObject.PipelineSpec().Tasks {
t := &dockerPipelineObject.PipelineSpec().Tasks[i]
params := t.TaskRef.Params
var lastBundle *tektonapi.Param
var lastName *tektonapi.Param
buildahTask := false
for i, param := range params {
if param.Name == "bundle" {
lastBundle = &t.TaskRef.Params[i]
} else if param.Name == "name" && param.Value.StringVal == "buildah" {
lastName = &t.TaskRef.Params[i]
buildahTask = true
}
}
if buildahTask {
t.Name = "build-container-amd64"
currentBuildahTaskRef = lastBundle.Value.StringVal
klog.Infof("Found current task ref %s", currentBuildahTaskRef)
//TODO: current use pinned sha?
lastBundle.Value = *tektonapi.NewStructuredValues("quay.io/redhat-appstudio-tekton-catalog/task-buildah-remote:0.1-ac185e95bbd7a25c1c4acf86995cbaf30eebedc4")
lastName.Value = *tektonapi.NewStructuredValues("buildah-remote")
t.Params = append(t.Params, tektonapi.Param{Name: "PLATFORM", Value: *tektonapi.NewStructuredValues("$(params.PLATFORM)")})
dockerPipelineObject.Spec.Params = append(dockerPipelineObject.PipelineSpec().Params, tektonapi.ParamSpec{Name: "PLATFORM", Default: tektonapi.NewStructuredValues(platformType)})
for i, result := range dockerPipelineObject.Spec.Results {
if result.Name == "JAVA_COMMUNITY_DEPENDENCIES" {
javaResult := &dockerPipelineObject.Spec.Results[i]
javaResult.Value = *tektonapi.NewStructuredValues("$(tasks.build-container-amd64.results.JAVA_COMMUNITY_DEPENDENCIES)")
}
}
dockerPipelineObject.Name = "multi-arch-pipeline"
break
}
}
newTaskRef := &tektonapi.TaskRef{
ResolverRef: tektonapi.ResolverRef{
Params: []tektonapi.Param{
{
Name: "name",
Value: *tektonapi.NewStructuredValues("build-image-manifest"),
},
{
Name: "bundle",
//?use the fixed sha
Value: *tektonapi.NewStructuredValues("quay.io/redhat-appstudio-tekton-catalog/task-build-image-manifest:0.1@sha256:e064b63b2311d23d6bf6538347cb4eb18c980d61883f48149bc9c728f76b276c"),
},
{
Name: "kind",
Value: *tektonapi.NewStructuredValues("task"),
},
},
Resolver: "bundles",
},
}

newTask := &tektonapi.PipelineTask{
Name: "build-container",
RunAfter: []string{"build-container-amd64"},
TaskRef: newTaskRef,
Params: []tektonapi.Param{
{
Name: "IMAGE",
Value: *tektonapi.NewStructuredValues("$(params.output-image)"),
},
{
Name: "COMMIT_SHA",
Value: *tektonapi.NewStructuredValues("$(tasks.clone-repository.results.commit)"),
},
{
Name: "IMAGES",
Value: tektonapi.ParamValue{
Type: tektonapi.ParamTypeArray,
ArrayVal: []string{
"$(tasks.build-container-amd64.results.IMAGE_URL)@$(tasks.build-container-amd64.results.IMAGE_DIGEST)",
},
},
},
},
When: tektonapi.WhenExpressions{{
Input: "$(tasks.init.results.build)",
Operator: selection.In,
Values: []string{"true"},
}},
}

dockerPipelineObject.Spec.Tasks = append(dockerPipelineObject.PipelineSpec().Tasks, *newTask)
if newPipelineYaml, err = yaml.Marshal(dockerPipelineObject); err != nil {
return fmt.Errorf("error when marshalling a new pipeline to YAML: %v", err)
}

keychain := authn.NewMultiKeychain(authn.DefaultKeychain)
authOption := remoteimg.WithAuthFromKeychain(keychain)

if err = tekton.BuildAndPushTektonBundle(newPipelineYaml, newRemotePipeline, authOption); err != nil {
return fmt.Errorf("error when building/pushing a tekton pipeline bundle: %v", err)
}
klog.Infof("SETTING ENV VAR %s to value %s\n", constants.CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE_ENV, newRemotePipeline.String())
os.Setenv(constants.CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE_ENV, newRemotePipeline.String())

Check warning

Code scanning / gosec

Errors unhandled. Warning

Errors unhandled.

return nil
}

func SetupMultiPlatformTests() error {
klog.Infof("going to create new Tekton bundle remote-build for the purpose of testing multi-platform-controller PR")
var err error
Expand Down Expand Up @@ -825,9 +1018,8 @@ func GenerateTestSuiteFile(packageName string) error {
return nil
}

// Remove all webhooks older than 1 day from GitHub repo.
// By default will delete webhooks from redhat-appstudio-qe
func CleanGitHubWebHooks() error {
// Remove all webhooks which with 1 day lifetime. By default will delete webooks from redhat-appstudio-qe
func CleanWebHooks() error {
token := utils.GetEnv(constants.GITHUB_TOKEN_ENV, "")
if token == "" {
return fmt.Errorf("empty GITHUB_TOKEN env. Please provide a valid github token")
Expand Down Expand Up @@ -856,38 +1048,6 @@ func CleanGitHubWebHooks() error {
return nil
}

// Remove all webhooks older than 1 day from GitLab repo.
func CleanGitLabWebHooks() error {
gcToken := utils.GetEnv(constants.GITLAB_TOKEN_ENV, "")
if gcToken == "" {
return fmt.Errorf("empty PAC_GITLAB_TOKEN env")
}
projectID := utils.GetEnv(constants.GITLAB_PROJECT_ID, "")
if projectID == "" {
return fmt.Errorf("empty PAC_PROJECT_ID env. Please provide a valid GitLab Project ID")
}
gitlabURL := utils.GetEnv(constants.GITLAB_URL_ENV, "https://gitlab.com/api/v4")
gc, err := gitlab.NewGitlabClient(gcToken, gitlabURL)
if err != nil {
return err
}
webhooks, _, err := gc.GetClient().Projects.ListProjectHooks(projectID, &gl.ListProjectHooksOptions{PerPage: 100})
if err != nil {
return fmt.Errorf("failed to list project hooks: %v", err)
}
// Delete webhooks that are older than 1 day
for _, webhook := range webhooks {
dayDuration, _ := time.ParseDuration("24h")
if time.Since(*webhook.CreatedAt) > dayDuration {
klog.Infof("removing webhookURL: %s", webhook.URL)
if _, err := gc.GetClient().Projects.DeleteProjectHook(projectID, webhook.ID); err != nil {
return fmt.Errorf("failed to delete webhook (URL: %s): %v", webhook.URL, err)
}
}
}
return nil
}

// Generate a Text Outline file from a Ginkgo Spec
func GenerateTextOutlineFromGinkgoSpec(source string, destination string) error {

Expand Down
3 changes: 3 additions & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ const (
// Managed workspace for release pipelines tests
RELEASE_MANAGED_WORKSPACE_ENV = "RELEASE_MANAGED_WORKSPACE"

// Bundle ref for overriding the default Java build bundle specified in BuildPipelineConfigConfigMapYamlURL
CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE_ENV string = "CUSTOM_MULTI_ARCH_PIPELINE_BUILD_BUNDLE"

// Bundle ref for overriding the default Java build bundle specified in BuildPipelineConfigConfigMapYamlURL
CUSTOM_JAVA_PIPELINE_BUILD_BUNDLE_ENV string = "CUSTOM_JAVA_PIPELINE_BUILD_BUNDLE"

Expand Down
1 change: 1 addition & 0 deletions tests/release/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
ComponentName string = "dc-metro-map"
GitSourceComponentUrl string = "https://github.com/scoheb/dc-metro-map"
AdditionalComponentName string = "simple-python"
MultiArchComponentUrl string = "https://github.com/jinqi7/multi-platform-test-prod"
AdditionalGitSourceComponentUrl string = "https://github.com/devfile-samples/devfile-sample-python-basic"
ReleasedImagePushRepo string = "quay.io/redhat-appstudio-qe/dcmetromap"
AdditionalReleasedImagePushRepo string = "quay.io/redhat-appstudio-qe/simplepython"
Expand Down
Loading

0 comments on commit 134ac92

Please sign in to comment.