From 23f79dbeeeae2bf5faa600835dd01ea4878e0cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20Gustav=20Str=C3=A5b=C3=B8?= Date: Mon, 16 Oct 2023 11:00:05 +0200 Subject: [PATCH 1/2] add pipeline job name label to all related pods --- charts/radix-operator/Chart.yaml | 4 ++-- pipeline-runner/steps/build_acr.go | 5 ++--- pipeline-runner/utils/tekton.go | 2 ++ pkg/apis/job/job_test.go | 5 +++++ pkg/apis/job/kubejob.go | 29 ++++++++++++++++------------ pkg/apis/kube/kube.go | 1 + pkg/apis/utils/labels/labels.go | 26 +++++++++++++++++++++++++ pkg/apis/utils/labels/labels_test.go | 24 +++++++++++++++++++++++ 8 files changed, 79 insertions(+), 17 deletions(-) diff --git a/charts/radix-operator/Chart.yaml b/charts/radix-operator/Chart.yaml index 92a62eba5..c1512e072 100644 --- a/charts/radix-operator/Chart.yaml +++ b/charts/radix-operator/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: radix-operator -version: 1.23.7 -appVersion: 1.43.7 +version: 1.23.8 +appVersion: 1.43.8 kubeVersion: ">=1.24.0" description: Radix Operator keywords: diff --git a/pipeline-runner/steps/build_acr.go b/pipeline-runner/steps/build_acr.go index a4937ee15..c6de6f8d9 100644 --- a/pipeline-runner/steps/build_acr.go +++ b/pipeline-runner/steps/build_acr.go @@ -14,6 +14,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/utils" radixannotations "github.com/equinor/radix-operator/pkg/apis/utils/annotations" "github.com/equinor/radix-operator/pkg/apis/utils/git" + radixlabels "github.com/equinor/radix-operator/pkg/apis/utils/labels" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -67,9 +68,7 @@ func createACRBuildJob(rr *v1.RadixRegistration, pipelineInfo *model.PipelineInf BackoffLimit: &backOffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - kube.RadixJobNameLabel: jobName, - }, + Labels: radixlabels.ForPipelineJobName(jobName), Annotations: annotations, }, Spec: corev1.PodSpec{ diff --git a/pipeline-runner/utils/tekton.go b/pipeline-runner/utils/tekton.go index 0ef3f2358..59e96e072 100644 --- a/pipeline-runner/utils/tekton.go +++ b/pipeline-runner/utils/tekton.go @@ -12,6 +12,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/utils" "github.com/equinor/radix-operator/pkg/apis/utils/annotations" "github.com/equinor/radix-operator/pkg/apis/utils/git" + radixlabels "github.com/equinor/radix-operator/pkg/apis/utils/labels" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,6 +44,7 @@ func CreateActionPipelineJob(containerName string, action string, pipelineInfo * BackoffLimit: &backOffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ + Labels: radixlabels.ForPipelineJobName(jobName), Annotations: annotations.ForClusterAutoscalerSafeToEvict(false), }, Spec: corev1.PodSpec{ diff --git a/pkg/apis/job/job_test.go b/pkg/apis/job/job_test.go index 23ea2acfd..fd0efef80 100644 --- a/pkg/apis/job/job_test.go +++ b/pkg/apis/job/job_test.go @@ -229,6 +229,11 @@ func (s *RadixJobTestSuite) TestObjectSynced_PipelineJobCreated() { }, }, } + + expectedPodLabels := map[string]string{kube.RadixJobNameLabel: jobName} + s.Equal(expectedPodLabels, podTemplate.Labels) + expectedPodAnnotations := annotations.ForClusterAutoscalerSafeToEvict(false) + s.Equal(expectedPodAnnotations, podTemplate.Annotations) expectedPodSpec := corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, Tolerations: expectedTolerations, diff --git a/pkg/apis/job/kubejob.go b/pkg/apis/job/kubejob.go index dae209e6e..0557e9829 100644 --- a/pkg/apis/job/kubejob.go +++ b/pkg/apis/job/kubejob.go @@ -13,11 +13,12 @@ import ( "github.com/equinor/radix-operator/pkg/apis/utils" "github.com/equinor/radix-operator/pkg/apis/utils/annotations" "github.com/equinor/radix-operator/pkg/apis/utils/git" + radixlabels "github.com/equinor/radix-operator/pkg/apis/utils/labels" log "github.com/sirupsen/logrus" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" + kubelabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" "sigs.k8s.io/yaml" ) @@ -82,6 +83,7 @@ func (job *Job) getPipelineJobConfig() (*batchv1.Job, error) { BackoffLimit: &backOffLimit, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ + Labels: radixlabels.ForPipelineJobName(jobName), Annotations: annotations.ForClusterAutoscalerSafeToEvict(false), }, Spec: corev1.PodSpec{ @@ -190,17 +192,20 @@ func (job *Job) getPipelineJobArguments(appName, jobName string, jobSpec v1.Radi func getPipelineJobLabels(appName, jobName string, jobSpec v1.RadixJobSpec, pipeline *pipelineJob.Definition) map[string]string { // Base labels for all types of pipeline - labels := map[string]string{ - kube.RadixJobNameLabel: jobName, - kube.RadixJobTypeLabel: kube.RadixJobTypeJob, - "radix-pipeline": string(pipeline.Type), - kube.RadixAppLabel: appName, - } + labels := radixlabels.Merge( + radixlabels.ForApplicationName(appName), + radixlabels.ForPipelineJobName(jobName), + radixlabels.ForPipelineJobType(), + radixlabels.ForPipelineJobPipelineType(pipeline.Type), + ) switch pipeline.Type { case v1.BuildDeploy, v1.Build: - labels[kube.RadixImageTagLabel] = jobSpec.Build.ImageTag - labels[kube.RadixCommitLabel] = jobSpec.Build.CommitID + labels = radixlabels.Merge( + labels, + radixlabels.ForCommitId(jobSpec.Build.CommitID), + radixlabels.ForRadixImageTag(jobSpec.Build.ImageTag), + ) } return labels @@ -259,7 +264,7 @@ func (job *Job) getRadixJobResult() (*v1.RadixJobResult, error) { } func getRadixPipelineJobResultConfigMapSelector(jobName string) string { - radixJobNameReq, _ := labels.NewRequirement(kube.RadixJobNameLabel, selection.Equals, []string{jobName}) - pipelineResultConfigMapReq, _ := labels.NewRequirement(kube.RadixConfigMapTypeLabel, selection.Equals, []string{string(kube.RadixPipelineResultConfigMap)}) - return labels.NewSelector().Add(*radixJobNameReq, *pipelineResultConfigMapReq).String() + radixJobNameReq, _ := kubelabels.NewRequirement(kube.RadixJobNameLabel, selection.Equals, []string{jobName}) + pipelineResultConfigMapReq, _ := kubelabels.NewRequirement(kube.RadixConfigMapTypeLabel, selection.Equals, []string{string(kube.RadixPipelineResultConfigMap)}) + return kubelabels.NewSelector().Add(*radixJobNameReq, *pipelineResultConfigMapReq).String() } diff --git a/pkg/apis/kube/kube.go b/pkg/apis/kube/kube.go index bd011b79d..38bcf4f70 100644 --- a/pkg/apis/kube/kube.go +++ b/pkg/apis/kube/kube.go @@ -70,6 +70,7 @@ const ( RadixBatchJobNameLabel = "radix-batch-job-name" RadixBatchTypeLabel = "radix-batch-type" RadixAccessValidationLabel = "radix-access-validation" + RadixPipelineTypeLabels = "radix-pipeline" // NodeTaintGpuCountKey defines the taint key on GPU nodes. // Pods required to run on nodes with this taint must add a toleration with effect NoSchedule diff --git a/pkg/apis/utils/labels/labels.go b/pkg/apis/utils/labels/labels.go index 106b14656..b8ff557cf 100644 --- a/pkg/apis/utils/labels/labels.go +++ b/pkg/apis/utils/labels/labels.go @@ -158,6 +158,32 @@ func ForJobScheduleJobType() kubelabels.Set { return ForJobType(kube.RadixJobTypeJobSchedule) } +// ForPipelineJobName returns labels describing the name of a pipeline job +func ForPipelineJobName(jobName string) kubelabels.Set { + return kubelabels.Set{ + kube.RadixJobNameLabel: jobName, + } +} + +// ForPipelineJobType returns labels describing the pipeline-job type +func ForPipelineJobType() kubelabels.Set { + return ForJobType(kube.RadixJobTypeJob) +} + +// ForPipelineJobPipelineType returns label describing the pipeline-job pipeline type, e.g. build-deploy, promote, deploy-only +func ForPipelineJobPipelineType(pipeline v1.RadixPipelineType) kubelabels.Set { + return kubelabels.Set{ + kube.RadixPipelineTypeLabels: string(pipeline), + } +} + +// ForRadixImageTag returns labels describing that image tag used by pipeline job in a build-deploy scenario +func ForRadixImageTag(imageTag string) kubelabels.Set { + return kubelabels.Set{ + kube.RadixImageTagLabel: imageTag, + } +} + func forAzureWorkloadUseIdentity() kubelabels.Set { return kubelabels.Set{ azureWorkloadIdentityUseLabel: "true", diff --git a/pkg/apis/utils/labels/labels_test.go b/pkg/apis/utils/labels/labels_test.go index d7deb79e4..1237dd4b1 100644 --- a/pkg/apis/utils/labels/labels_test.go +++ b/pkg/apis/utils/labels/labels_test.go @@ -112,6 +112,30 @@ func Test_ForAccessValidation(t *testing.T) { assert.Equal(t, expected, actual) } +func Test_ForPipelineJobName(t *testing.T) { + actual := ForPipelineJobName("anypipelinejobname") + expected := kubelabels.Set{kube.RadixJobNameLabel: "anypipelinejobname"} + assert.Equal(t, expected, actual) +} + +func Test_ForPipelineJobType(t *testing.T) { + actual := ForPipelineJobType() + expected := kubelabels.Set{kube.RadixJobTypeLabel: kube.RadixJobTypeJob} + assert.Equal(t, expected, actual) +} + +func Test_ForPipelineJobPipelineType(t *testing.T) { + actual := ForPipelineJobPipelineType("anypipelinetype") + expected := kubelabels.Set{kube.RadixPipelineTypeLabels: "anypipelinetype"} + assert.Equal(t, expected, actual) +} + +func Test_ForRadixImageTag(t *testing.T) { + actual := ForRadixImageTag("anyimagetag") + expected := kubelabels.Set{kube.RadixImageTagLabel: "anyimagetag"} + assert.Equal(t, expected, actual) +} + func Test_RequirementRadixBatchNameLabelExists(t *testing.T) { actual := requirementRadixBatchNameLabelExists() expected := kubelabels.Set{kube.RadixBatchNameLabel: "anyname"} From 7c9e546a421ccb0288d9214ca2ca86aa6630ce47 Mon Sep 17 00:00:00 2001 From: Sergey Smolnikov Date: Wed, 18 Oct 2023 09:51:50 +0200 Subject: [PATCH 2/2] Add commit id to deploy pipeline job (#955) * Added commit-id for deploy only job * Added commit-id to radix deployment * Cleanup * Added unit-test * Added unit-test * Added missing error handling in unit-tests, cleaunup --- charts/radix-operator/Chart.yaml | 4 +- pipeline-runner/steps/build_test.go | 3 +- pipeline-runner/steps/deploy.go | 9 +- pipeline-runner/steps/deploy_test.go | 64 +++++++++-- pipeline-runner/steps/prepare_pipelines.go | 15 ++- pipeline-runner/steps/promotion.go | 5 + pipeline-runner/steps/promotion_test.go | 124 ++++++++++++++++----- pkg/apis/deployment/deployment_test.go | 19 ++++ pkg/apis/job/kubejob.go | 1 + pkg/apis/kube/kube.go | 12 +- pkg/apis/radix/v1/radixjobtypes.go | 64 ++++++++--- pkg/apis/test/utils.go | 13 ++- 12 files changed, 270 insertions(+), 63 deletions(-) diff --git a/charts/radix-operator/Chart.yaml b/charts/radix-operator/Chart.yaml index c1512e072..59e10e75b 100644 --- a/charts/radix-operator/Chart.yaml +++ b/charts/radix-operator/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: radix-operator -version: 1.23.8 -appVersion: 1.43.8 +version: 1.23.9 +appVersion: 1.43.9 kubeVersion: ">=1.24.0" description: Radix Operator keywords: diff --git a/pipeline-runner/steps/build_test.go b/pipeline-runner/steps/build_test.go index 127b9ceb4..62037b53e 100644 --- a/pipeline-runner/steps/build_test.go +++ b/pipeline-runner/steps/build_test.go @@ -12,6 +12,7 @@ import ( radix "github.com/equinor/radix-operator/pkg/client/clientset/versioned/fake" monitoring "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kubernetes "k8s.io/client-go/kubernetes/fake" secretproviderfake "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned/fake" @@ -68,7 +69,7 @@ func TestBuild_BranchIsNotMapped_ShouldSkip(t *testing.T) { } err := cli.Run(pipelineInfo) - assert.NoError(t, err) + require.NoError(t, err) radixJobList, err := radixclient.RadixV1().RadixJobs(utils.GetAppNamespace(anyAppName)).List(context.Background(), metav1.ListOptions{}) assert.NoError(t, err) assert.Empty(t, radixJobList.Items) diff --git a/pipeline-runner/steps/deploy.go b/pipeline-runner/steps/deploy.go index 3062265dd..58ec63920 100644 --- a/pipeline-runner/steps/deploy.go +++ b/pipeline-runner/steps/deploy.go @@ -9,7 +9,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/deployment" "github.com/equinor/radix-operator/pkg/apis/kube" "github.com/equinor/radix-operator/pkg/apis/pipeline" - v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" + radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pkg/apis/utils" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -82,6 +82,9 @@ func (cli *DeployStepImplementation) deployToEnv(appName, env string, pipelineIn return fmt.Errorf("failed to retrieve default env vars for RadixDeployment in app %s. %v", appName, err) } + if commitID, ok := defaultEnvVars[defaults.RadixCommitHashEnvironmentVariable]; !ok || len(commitID) == 0 { + defaultEnvVars[defaults.RadixCommitHashEnvironmentVariable] = pipelineInfo.PipelineArguments.CommitID // Commit ID specified by job arguments + } radixDeployment, err := deployment.ConstructForTargetEnvironment( pipelineInfo.RadixApplication, pipelineInfo.PipelineArguments.JobName, @@ -109,11 +112,11 @@ func (cli *DeployStepImplementation) deployToEnv(appName, env string, pipelineIn return nil } -func getDefaultEnvVars(pipelineInfo *model.PipelineInfo) (v1.EnvVarsMap, error) { +func getDefaultEnvVars(pipelineInfo *model.PipelineInfo) (radixv1.EnvVarsMap, error) { gitCommitHash := pipelineInfo.GitCommitHash gitTags := pipelineInfo.GitTags - envVarsMap := make(v1.EnvVarsMap) + envVarsMap := make(radixv1.EnvVarsMap) envVarsMap[defaults.RadixCommitHashEnvironmentVariable] = gitCommitHash envVarsMap[defaults.RadixGitTagsEnvironmentVariable] = gitTags diff --git a/pipeline-runner/steps/deploy_test.go b/pipeline-runner/steps/deploy_test.go index 20141773b..f0a011925 100644 --- a/pipeline-runner/steps/deploy_test.go +++ b/pipeline-runner/steps/deploy_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/equinor/radix-operator/pkg/apis/defaults" + "github.com/stretchr/testify/require" "github.com/equinor/radix-operator/pipeline-runner/model" application "github.com/equinor/radix-operator/pkg/apis/applicationconfig" @@ -19,12 +20,11 @@ import ( ) const ( - anyContainerRegistry = "any.container.registry" - anyAppName = "any-app" - anyJobName = "any-job-name" - anyImageTag = "anytag" - anyCommitID = "4faca8595c5283a9d0f17a623b9255a0d9866a2e" - anyGitTags = "some tags go here" + anyAppName = "any-app" + anyJobName = "any-job-name" + anyImageTag = "anytag" + anyCommitID = "4faca8595c5283a9d0f17a623b9255a0d9866a2e" + anyGitTags = "some tags go here" ) // FakeNamespaceWatcher Unit tests doesn't handle muliti-threading well @@ -74,7 +74,7 @@ func TestDeploy_BranchIsNotMapped_ShouldSkip(t *testing.T) { } err := cli.Run(pipelineInfo) - assert.NoError(t, err) + require.NoError(t, err) radixJobList, err := radixclient.RadixV1().RadixJobs(utils.GetAppNamespace(anyAppName)).List(context.Background(), metav1.ListOptions{}) assert.NoError(t, err) assert.Empty(t, radixJobList.Items) @@ -187,6 +187,7 @@ func TestDeploy_PromotionSetup_ShouldCreateNamespacesForAllBranchesIfNotExists(t pipelineInfo.SetApplicationConfig(applicationConfig) pipelineInfo.SetGitAttributes(gitCommitHash, gitTags) err := cli.Run(pipelineInfo) + require.NoError(t, err) rds, _ := radixclient.RadixV1().RadixDeployments("any-app-dev").List(context.TODO(), metav1.ListOptions{}) t.Run("validate deploy", func(t *testing.T) { @@ -262,3 +263,52 @@ func TestDeploy_PromotionSetup_ShouldCreateNamespacesForAllBranchesIfNotExists(t }) } + +func TestDeploy_SetCommitID_whenSet(t *testing.T) { + kubeclient, kubeUtil, radixclient, _ := setupTest(t) + + rr := utils.ARadixRegistration(). + WithName(anyAppName). + BuildRR() + + ra := utils.NewRadixApplicationBuilder(). + WithAppName(anyAppName). + WithEnvironment("dev", "master"). + WithComponents(utils.AnApplicationComponent().WithName("app")). + BuildRA() + + // Prometheus doesn´t contain any fake + cli := NewDeployStep(FakeNamespaceWatcher{}) + cli.Init(kubeclient, radixclient, kubeUtil, &monitoring.Clientset{}, rr) + + applicationConfig, _ := application.NewApplicationConfig(kubeclient, kubeUtil, radixclient, rr, ra) + + const commitID = "222ca8595c5283a9d0f17a623b9255a0d9866a2e" + + pipelineInfo := &model.PipelineInfo{ + PipelineArguments: model.PipelineArguments{ + JobName: anyJobName, + ImageTag: anyImageTag, + Branch: "master", + CommitID: anyCommitID, + }, + BranchIsMapped: true, + TargetEnvironments: map[string]bool{"master": true}, + GitCommitHash: commitID, + GitTags: "", + } + + gitCommitHash := pipelineInfo.GitCommitHash + gitTags := pipelineInfo.GitTags + + pipelineInfo.SetApplicationConfig(applicationConfig) + pipelineInfo.SetGitAttributes(gitCommitHash, gitTags) + err := cli.Run(pipelineInfo) + require.NoError(t, err) + rds, err := radixclient.RadixV1().RadixDeployments("any-app-dev").List(context.TODO(), metav1.ListOptions{}) + + assert.NoError(t, err) + require.Len(t, rds.Items, 1) + rd := rds.Items[0] + assert.Equal(t, commitID, rd.ObjectMeta.Labels[kube.RadixCommitLabel]) +} diff --git a/pipeline-runner/steps/prepare_pipelines.go b/pipeline-runner/steps/prepare_pipelines.go index 54882ed89..6423be723 100644 --- a/pipeline-runner/steps/prepare_pipelines.go +++ b/pipeline-runner/steps/prepare_pipelines.go @@ -3,8 +3,6 @@ package steps import ( "context" "fmt" - "github.com/equinor/radix-operator/pkg/apis/kube" - v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pipeline-runner/model" pipelineDefaults "github.com/equinor/radix-operator/pipeline-runner/model/defaults" @@ -12,7 +10,9 @@ import ( "github.com/equinor/radix-operator/pkg/apis/applicationconfig" "github.com/equinor/radix-operator/pkg/apis/defaults" jobUtil "github.com/equinor/radix-operator/pkg/apis/job" + "github.com/equinor/radix-operator/pkg/apis/kube" "github.com/equinor/radix-operator/pkg/apis/pipeline" + radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pkg/apis/utils" "github.com/equinor/radix-operator/pkg/apis/utils/git" log "github.com/sirupsen/logrus" @@ -57,7 +57,7 @@ func (cli *PreparePipelinesStepImplementation) Run(pipelineInfo *model.PipelineI namespace := utils.GetAppNamespace(appName) log.Infof("Prepare pipelines app %s for branch %s and commit %s", appName, branch, commitID) - if v1.RadixPipelineType(pipelineInfo.PipelineArguments.PipelineType) == v1.Promote { + if radixv1.RadixPipelineType(pipelineInfo.PipelineArguments.PipelineType) == radixv1.Promote { sourceDeploymentGitCommitHash, sourceDeploymentGitBranch, err := cli.getSourceDeploymentGitInfo(appName, pipelineInfo.PipelineArguments.FromEnvironment, pipelineInfo.PipelineArguments.DeploymentName) if err != nil { return err @@ -159,7 +159,7 @@ func (cli *PreparePipelinesStepImplementation) getPreparePipelinesJobConfig(pipe }, { Name: defaults.RadixGithubWebhookCommitId, - Value: pipelineInfo.PipelineArguments.CommitID, + Value: getWebhookCommitID(pipelineInfo), }, } sshURL := registration.Spec.CloneURL @@ -169,6 +169,13 @@ func (cli *PreparePipelinesStepImplementation) getPreparePipelinesJobConfig(pipe } +func getWebhookCommitID(pipelineInfo *model.PipelineInfo) string { + if pipelineInfo.PipelineArguments.PipelineType == string(radixv1.BuildDeploy) { + return pipelineInfo.PipelineArguments.CommitID + } + return "" +} + func (cli *PreparePipelinesStepImplementation) getInitContainerCloningRepo(pipelineInfo *model.PipelineInfo, configBranch, sshURL string) []corev1.Container { return git.CloneInitContainersWithContainerName(sshURL, configBranch, git.CloneConfigContainerName, pipelineInfo.PipelineArguments.ContainerSecurityContext) diff --git a/pipeline-runner/steps/promotion.go b/pipeline-runner/steps/promotion.go index fdc25e1a4..7d6b3479b 100644 --- a/pipeline-runner/steps/promotion.go +++ b/pipeline-runner/steps/promotion.go @@ -108,10 +108,15 @@ func (cli *PromoteStepImplementation) Run(pipelineInfo *model.PipelineInfo) erro radixDeployment = rd.DeepCopy() radixDeployment.Name = utils.GetDeploymentName(cli.GetAppName(), pipelineInfo.PipelineArguments.ToEnvironment, pipelineInfo.PipelineArguments.ImageTag) + if radixDeployment.GetAnnotations() == nil { + radixDeployment.ObjectMeta.Annotations = make(map[string]string) + } if _, isRestored := radixDeployment.Annotations[kube.RestoredStatusAnnotation]; isRestored { // RA-817: Promotion reuses annotation - RD get inactive status radixDeployment.Annotations[kube.RestoredStatusAnnotation] = "" } + radixDeployment.Annotations[kube.RadixDeploymentPromotedFromDeploymentAnnotation] = rd.GetName() + radixDeployment.Annotations[kube.RadixDeploymentPromotedFromEnvironmentAnnotation] = pipelineInfo.PipelineArguments.FromEnvironment radixDeployment.ResourceVersion = "" radixDeployment.Namespace = toNs diff --git a/pipeline-runner/steps/promotion_test.go b/pipeline-runner/steps/promotion_test.go index 5c7f19fc8..e49af086b 100644 --- a/pipeline-runner/steps/promotion_test.go +++ b/pipeline-runner/steps/promotion_test.go @@ -41,28 +41,31 @@ func TestPromote_ErrorScenarios_ErrorIsReturned(t *testing.T) { // Setup kubeclient, kube, radixclient, commonTestUtils := setupTest(t) - commonTestUtils.ApplyDeployment(utils. + _, err := commonTestUtils.ApplyDeployment(utils. ARadixDeployment(). WithDeploymentName(anyDeployment1). WithAppName(anyApp1). WithEnvironment(anyProdEnvironment). WithImageTag(anyImageTag)) + require.NoError(t, err) - commonTestUtils.ApplyDeployment(utils. + _, err = commonTestUtils.ApplyDeployment(utils. ARadixDeployment(). WithDeploymentName(anyDeployment2). WithAppName(anyApp1). WithEnvironment(anyDevEnvironment). WithImageTag(anyImageTag)) + require.NoError(t, err) - commonTestUtils.ApplyDeployment(utils. + _, err = commonTestUtils.ApplyDeployment(utils. ARadixDeployment(). WithDeploymentName(anyDeployment3). WithAppName(anyApp2). WithEnvironment(anyDevEnvironment). WithImageTag(anyImageTag)) + require.NoError(t, err) - commonTestUtils.ApplyDeployment(utils. + _, err = commonTestUtils.ApplyDeployment(utils. ARadixDeployment(). WithDeploymentName(anyDeployment4). WithAppName(anyApp4). @@ -71,8 +74,9 @@ func TestPromote_ErrorScenarios_ErrorIsReturned(t *testing.T) { WithComponent(utils. NewDeployComponentBuilder(). WithName(nonExistingComponent))) + require.NoError(t, err) - commonTestUtils.ApplyDeployment(utils. + _, err = commonTestUtils.ApplyDeployment(utils. ARadixDeployment(). WithDeploymentName(anyDeployment5). WithAppName(anyApp5). @@ -81,6 +85,7 @@ func TestPromote_ErrorScenarios_ErrorIsReturned(t *testing.T) { WithJobComponent(utils. NewDeployJobComponentBuilder(). WithName(nonExistingJobComponent))) + require.NoError(t, err) test.CreateEnvNamespace(kubeclient, anyApp2, anyProdEnvironment) @@ -124,8 +129,7 @@ func TestPromote_ErrorScenarios_ErrorIsReturned(t *testing.T) { }, } - err := cli.Run(pipelineInfo) - assert.Error(t, err) + err = cli.Run(pipelineInfo) if scenario.expectedError != nil { assert.Equal(t, scenario.expectedError.Error(), err.Error()) @@ -150,7 +154,7 @@ func TestPromote_PromoteToOtherEnvironment_NewStateIsExpected(t *testing.T) { secretType := v1.RadixAzureKeyVaultObjectTypeSecret keyType := v1.RadixAzureKeyVaultObjectTypeKey - commonTestUtils.ApplyDeployment( + _, err := commonTestUtils.ApplyDeployment( utils.NewDeploymentBuilder(). WithComponent( utils.NewDeployComponentBuilder(). @@ -247,6 +251,7 @@ func TestPromote_PromoteToOtherEnvironment_NewStateIsExpected(t *testing.T) { WithEnvironment(anyDevEnvironment). WithImageTag(anyImageTag). WithLabel(kube.RadixJobNameLabel, anyBuildDeployJobName)) + require.NoError(t, err) // Create prod environment without any deployments test.CreateEnvNamespace(kubeclient, anyApp, anyProdEnvironment) @@ -273,8 +278,8 @@ func TestPromote_PromoteToOtherEnvironment_NewStateIsExpected(t *testing.T) { gitTags := pipelineInfo.GitTags pipelineInfo.SetApplicationConfig(applicationConfig) pipelineInfo.SetGitAttributes(gitCommitHash, gitTags) - err := cli.Run(pipelineInfo) - assert.NoError(t, err) + err = cli.Run(pipelineInfo) + require.NoError(t, err) rds, _ := radixclient.RadixV1().RadixDeployments(utils.GetEnvironmentNamespace(anyApp, anyProdEnvironment)).List(context.TODO(), metav1.ListOptions{}) assert.Equal(t, 1, len(rds.Items)) @@ -334,7 +339,7 @@ func TestPromote_PromoteToOtherEnvironment_Resources_NoOverride(t *testing.T) { // Setup kubeclient, kubeUtil, radixclient, commonTestUtils := setupTest(t) - commonTestUtils.ApplyDeployment( + _, err := commonTestUtils.ApplyDeployment( utils.ARadixDeployment(). WithRadixApplication( utils.NewRadixApplicationBuilder(). @@ -371,6 +376,7 @@ func TestPromote_PromoteToOtherEnvironment_Resources_NoOverride(t *testing.T) { WithEnvironment(anyDevEnvironment). WithImageTag(anyImageTag). WithLabel(kube.RadixJobNameLabel, anyBuildDeployJobName)) + require.NoError(t, err) // Create prod environment without any deployments test.CreateEnvNamespace(kubeclient, anyApp, anyProdEnvironment) @@ -397,8 +403,8 @@ func TestPromote_PromoteToOtherEnvironment_Resources_NoOverride(t *testing.T) { gitTags := pipelineInfo.GitTags pipelineInfo.SetApplicationConfig(applicationConfig) pipelineInfo.SetGitAttributes(gitCommitHash, gitTags) - err := cli.Run(pipelineInfo) - assert.NoError(t, err) + err = cli.Run(pipelineInfo) + require.NoError(t, err) rds, _ := radixclient.RadixV1().RadixDeployments(utils.GetEnvironmentNamespace(anyApp, anyProdEnvironment)).List(context.TODO(), metav1.ListOptions{}) assert.Equal(t, 1, len(rds.Items)) @@ -429,7 +435,7 @@ func TestPromote_PromoteToOtherEnvironment_Authentication(t *testing.T) { kubeclient, kubeUtil, radixclient, commonTestUtils := setupTest(t) verification := v1.VerificationTypeOptional - commonTestUtils.ApplyDeployment( + _, err := commonTestUtils.ApplyDeployment( utils.NewDeploymentBuilder(). WithAppName(anyApp). WithDeploymentName(anyDeploymentName). @@ -463,9 +469,11 @@ func TestPromote_PromoteToOtherEnvironment_Authentication(t *testing.T) { ), ), ))) + require.NoError(t, err) - // Create prod environment without any deployments + // Create environments test.CreateEnvNamespace(kubeclient, anyApp, anyProdEnvironment) + test.CreateEnvNamespace(kubeclient, anyApp, anyDevEnvironment) rr, _ := radixclient.RadixV1().RadixRegistrations().Get(context.TODO(), anyApp, metav1.GetOptions{}) ra, _ := radixclient.RadixV1().RadixApplications(utils.GetAppNamespace(anyApp)).Get(context.TODO(), anyApp, metav1.GetOptions{}) @@ -489,8 +497,8 @@ func TestPromote_PromoteToOtherEnvironment_Authentication(t *testing.T) { gitTags := pipelineInfo.GitTags pipelineInfo.SetApplicationConfig(applicationConfig) pipelineInfo.SetGitAttributes(gitCommitHash, gitTags) - err := cli.Run(pipelineInfo) - assert.NoError(t, err) + err = cli.Run(pipelineInfo) + require.NoError(t, err) rds, _ := radixclient.RadixV1().RadixDeployments(utils.GetEnvironmentNamespace(anyApp, anyProdEnvironment)).List(context.TODO(), metav1.ListOptions{}) assert.Equal(t, 1, len(rds.Items)) @@ -518,7 +526,7 @@ func TestPromote_PromoteToOtherEnvironment_Resources_WithOverride(t *testing.T) // Setup kubeclient, kubeUtil, radixclient, commonTestUtils := setupTest(t) - commonTestUtils.ApplyDeployment( + _, err := commonTestUtils.ApplyDeployment( utils.ARadixDeployment(). WithRadixApplication( utils.NewRadixApplicationBuilder(). @@ -578,6 +586,7 @@ func TestPromote_PromoteToOtherEnvironment_Resources_WithOverride(t *testing.T) WithEnvironment(anyDevEnvironment). WithImageTag(anyImageTag). WithLabel(kube.RadixJobNameLabel, anyBuildDeployJobName)) + require.NoError(t, err) // Create prod environment without any deployments test.CreateEnvNamespace(kubeclient, anyApp, anyProdEnvironment) @@ -604,8 +613,8 @@ func TestPromote_PromoteToOtherEnvironment_Resources_WithOverride(t *testing.T) gitTags := pipelineInfo.GitTags pipelineInfo.SetApplicationConfig(applicationConfig) pipelineInfo.SetGitAttributes(gitCommitHash, gitTags) - err := cli.Run(pipelineInfo) - assert.NoError(t, err) + err = cli.Run(pipelineInfo) + require.NoError(t, err) rds, _ := radixclient.RadixV1().RadixDeployments(utils.GetEnvironmentNamespace(anyApp, anyProdEnvironment)).List(context.TODO(), metav1.ListOptions{}) assert.Equal(t, 1, len(rds.Items)) @@ -634,13 +643,14 @@ func TestPromote_PromoteToSameEnvironment_NewStateIsExpected(t *testing.T) { // Setup kubeclient, kubeUtil, radixclient, commonTestUtils := setupTest(t) - commonTestUtils.ApplyDeployment( + _, err := commonTestUtils.ApplyDeployment( utils.ARadixDeployment(). WithAppName(anyApp). WithDeploymentName(anyDeploymentName). WithEnvironment(anyDevEnvironment). WithImageTag(anyImageTag). WithLabel(kube.RadixJobNameLabel, anyBuildDeployJobName)) + require.NoError(t, err) rr, _ := radixclient.RadixV1().RadixRegistrations().Get(context.TODO(), anyApp, metav1.GetOptions{}) ra, _ := radixclient.RadixV1().RadixApplications(utils.GetAppNamespace(anyApp)).Get(context.TODO(), anyApp, metav1.GetOptions{}) @@ -664,8 +674,8 @@ func TestPromote_PromoteToSameEnvironment_NewStateIsExpected(t *testing.T) { gitTags := pipelineInfo.GitTags pipelineInfo.SetApplicationConfig(applicationConfig) pipelineInfo.SetGitAttributes(gitCommitHash, gitTags) - err := cli.Run(pipelineInfo) - assert.NoError(t, err) + err = cli.Run(pipelineInfo) + require.NoError(t, err) rds, _ := radixclient.RadixV1().RadixDeployments(utils.GetEnvironmentNamespace(anyApp, anyDevEnvironment)).List(context.TODO(), metav1.ListOptions{}) assert.Equal(t, 2, len(rds.Items)) @@ -716,7 +726,7 @@ func TestPromote_PromoteToOtherEnvironment_Identity(t *testing.T) { jobEnvironmentConfigs = append(jobEnvironmentConfigs, utils.AJobComponentEnvironmentConfig().WithEnvironment(anyProdEnvironment).WithIdentity(scenario.environmentConfig)) } - commonTestUtils.ApplyDeployment( + _, err := commonTestUtils.ApplyDeployment( utils.NewDeploymentBuilder(). WithComponents( utils.NewDeployComponentBuilder(). @@ -755,6 +765,7 @@ func TestPromote_PromoteToOtherEnvironment_Identity(t *testing.T) { WithEnvironmentConfigs(jobEnvironmentConfigs...), )), ) + require.NoError(t, err) // Create prod environment without any deployments test.CreateEnvNamespace(kubeclient, anyApp, anyProdEnvironment) @@ -778,7 +789,7 @@ func TestPromote_PromoteToOtherEnvironment_Identity(t *testing.T) { applicationConfig, _ := application.NewApplicationConfig(kubeclient, kubeUtil, radixclient, rr, ra) pipelineInfo.SetApplicationConfig(applicationConfig) - err := cli.Run(pipelineInfo) + err = cli.Run(pipelineInfo) require.NoError(t, err) rds, _ := radixclient.RadixV1().RadixDeployments(utils.GetEnvironmentNamespace(anyApp, anyProdEnvironment)).List(context.TODO(), metav1.ListOptions{}) @@ -789,3 +800,66 @@ func TestPromote_PromoteToOtherEnvironment_Identity(t *testing.T) { } } + +func TestPromote_AnnotatedBySourceDeploymentAttributes(t *testing.T) { + srcDeploymentName := "deployment-1" + anyImageTag := "abcdef" + anyBuildDeployJobName := "any-build-deploy-job" + anyPromoteJobName := "any-promote-job" + dstEnv := "test" + srcEnv := "dev" + srcDeploymentCommitID := "222ca8595c5283a9d0f17a623b9255a0d9866a2e" + + // Setup + kubeclient, kubeUtil, radixclient, commonTestUtils := setupTest(t) + + _, err := commonTestUtils.ApplyDeployment( + utils.NewDeploymentBuilder(). + WithRadixApplication( + utils.NewRadixApplicationBuilder(). + WithRadixRegistration(utils.ARadixRegistration()). + WithAppName(anyAppName). + WithEnvironment(srcEnv, "dev-branch"). + WithEnvironment(dstEnv, "test-branch"). + WithComponent(utils.NewApplicationComponentBuilder().WithName("comp1"))). + WithAppName(anyAppName). + WithDeploymentName(srcDeploymentName). + WithEnvironment(srcEnv). + WithImageTag(anyImageTag). + WithLabel(kube.RadixJobNameLabel, anyBuildDeployJobName). + WithLabel(kube.RadixCommitLabel, srcDeploymentCommitID)) + require.NoError(t, err) + + rr, _ := radixclient.RadixV1().RadixRegistrations().Get(context.TODO(), anyAppName, metav1.GetOptions{}) + ra, _ := radixclient.RadixV1().RadixApplications(utils.GetAppNamespace(anyAppName)).Get(context.TODO(), anyAppName, metav1.GetOptions{}) + + cli := NewPromoteStep() + cli.Init(kubeclient, radixclient, kubeUtil, &monitoring.Clientset{}, rr) + + pipelineInfo := &model.PipelineInfo{ + PipelineArguments: model.PipelineArguments{ + FromEnvironment: srcEnv, + ToEnvironment: dstEnv, + DeploymentName: srcDeploymentName, + JobName: anyPromoteJobName, + ImageTag: anyImageTag, + CommitID: anyCommitID, + }, + } + + applicationConfig, _ := application.NewApplicationConfig(kubeclient, kubeUtil, radixclient, rr, ra) + gitCommitHash := pipelineInfo.GitCommitHash + gitTags := pipelineInfo.GitTags + pipelineInfo.SetApplicationConfig(applicationConfig) + pipelineInfo.SetGitAttributes(gitCommitHash, gitTags) + err = cli.Run(pipelineInfo) + require.NoError(t, err) + + rds, err := radixclient.RadixV1().RadixDeployments(utils.GetEnvironmentNamespace(anyAppName, dstEnv)).List(context.TODO(), metav1.ListOptions{}) + assert.NoError(t, err) + assert.Len(t, rds.Items, 1) + promotedRD := rds.Items[0] + assert.Equal(t, srcEnv, promotedRD.GetAnnotations()[kube.RadixDeploymentPromotedFromEnvironmentAnnotation]) + assert.Equal(t, srcDeploymentName, promotedRD.GetAnnotations()[kube.RadixDeploymentPromotedFromDeploymentAnnotation]) + assert.Equal(t, srcDeploymentCommitID, promotedRD.GetLabels()[kube.RadixCommitLabel]) +} diff --git a/pkg/apis/deployment/deployment_test.go b/pkg/apis/deployment/deployment_test.go index b48234ee4..6771eb12d 100644 --- a/pkg/apis/deployment/deployment_test.go +++ b/pkg/apis/deployment/deployment_test.go @@ -2132,6 +2132,25 @@ func TestConstructForTargetEnvironment_AlwaysPullImageOnDeployOverride(t *testin assert.False(t, rd.Spec.Components[1].AlwaysPullImageOnDeploy) } +func TestConstructForTargetEnvironment_GetCommitID(t *testing.T) { + ra := utils.ARadixApplication(). + WithEnvironment("prod", "dev"). + WithComponents(utils.AnApplicationComponent().WithName("app")). + BuildRA() + + componentImages := make(map[string]pipeline.ComponentImage) + componentImages["app"] = pipeline.ComponentImage{ImageName: "anyImage", ImagePath: "anyImagePath"} + + envVarsMap := make(v1.EnvVarsMap) + envVarsMap[defaults.RadixCommitHashEnvironmentVariable] = "commit-abc" + envVarsMap[defaults.RadixGitTagsEnvironmentVariable] = "anytag" + + rd, err := ConstructForTargetEnvironment(ra, "anyjob", "anyimageTag", "anybranch", componentImages, "dev", envVarsMap) + require.NoError(t, err) + + assert.Equal(t, "commit-abc", rd.ObjectMeta.Labels[kube.RadixCommitLabel]) +} + func TestObjectSynced_PublicPort_OldPublic(t *testing.T) { tu, client, kubeUtil, radixclient, prometheusclient, _ := setupTest() defer teardownTest() diff --git a/pkg/apis/job/kubejob.go b/pkg/apis/job/kubejob.go index 0557e9829..cb51f3435 100644 --- a/pkg/apis/job/kubejob.go +++ b/pkg/apis/job/kubejob.go @@ -181,6 +181,7 @@ func (job *Job) getPipelineJobArguments(appName, jobName string, jobSpec v1.Radi args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixConfigFileEnvironmentVariable, radixConfigFullName)) case v1.Deploy: args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixPromoteToEnvironmentEnvironmentVariable, jobSpec.Deploy.ToEnvironment)) + args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixCommitIdEnvironmentVariable, jobSpec.Deploy.CommitID)) for componentName, imageTagName := range jobSpec.Deploy.ImageTagNames { args = append(args, fmt.Sprintf("--%s=%s=%s", defaults.RadixImageTagNameEnvironmentVariable, componentName, imageTagName)) } diff --git a/pkg/apis/kube/kube.go b/pkg/apis/kube/kube.go index 38bcf4f70..05b4672d5 100644 --- a/pkg/apis/kube/kube.go +++ b/pkg/apis/kube/kube.go @@ -17,11 +17,13 @@ import ( // Radix Annotations const ( - RadixBranchAnnotation = "radix-branch" - RadixGitTagsAnnotation = "radix.equinor.com/radix-git-tags" - RadixCommitAnnotation = "radix.equinor.com/radix-commit" - RadixComponentImagesAnnotation = "radix-component-images" - RadixDeploymentNameAnnotation = "radix-deployment-name" + RadixBranchAnnotation = "radix-branch" + RadixGitTagsAnnotation = "radix.equinor.com/radix-git-tags" + RadixCommitAnnotation = "radix.equinor.com/radix-commit" + RadixComponentImagesAnnotation = "radix-component-images" + RadixDeploymentNameAnnotation = "radix-deployment-name" + RadixDeploymentPromotedFromDeploymentAnnotation = "radix.equinor.com/radix-deployment-promoted-from-deployment" + RadixDeploymentPromotedFromEnvironmentAnnotation = "radix.equinor.com/radix-deployment-promoted-from-environment" // See https://github.com/equinor/radix-velero-plugin/blob/master/velero-plugins/deployment/restore.go RestoredStatusAnnotation = "equinor.com/velero-restored-status" diff --git a/pkg/apis/radix/v1/radixjobtypes.go b/pkg/apis/radix/v1/radixjobtypes.go index 3b4f9b66b..c47a90329 100644 --- a/pkg/apis/radix/v1/radixjobtypes.go +++ b/pkg/apis/radix/v1/radixjobtypes.go @@ -15,7 +15,7 @@ type RadixJob struct { Status RadixJobStatus `json:"status" yaml:"status"` } -//RadixJobStatus is the status for a Radix job +// RadixJobStatus is the status for a Radix job type RadixJobStatus struct { Condition RadixJobCondition `json:"condition" yaml:"condition"` Created *meta_v1.Time `json:"created" yaml:"created"` @@ -45,7 +45,7 @@ const ( JobStoppedNoChanges RadixJobCondition = "StoppedNoChanges" ) -//RadixJobSpec is the spec for a job +// RadixJobSpec is the spec for a job type RadixJobSpec struct { AppName string `json:"appName" yaml:"appName"` CloneURL string `json:"cloneURL" yaml:"cloneURL"` @@ -70,40 +70,76 @@ const ( Deploy RadixPipelineType = "deploy" ) -//RadixBuildSpec is the spec for a build job +// RadixBuildSpec is the spec for a build job type RadixBuildSpec struct { - ImageTag string `json:"imageTag" yaml:"imageTag"` - Branch string `json:"branch" yaml:"branch"` - CommitID string `json:"commitID" yaml:"commitID"` - PushImage bool `json:"pushImage" yaml:"pushImage"` + // Tag of the built image + // + // required: true + ImageTag string `json:"imageTag" yaml:"imageTag"` + + // Branch, from which the image to be built + // + // required: true + Branch string `json:"branch" yaml:"branch"` + + // CommitID, from which the image to be built + // + // required: false + CommitID string `json:"commitID" yaml:"commitID"` + + // Is the built image need to be pushed to the container registry repository + // + // required: false + PushImage bool `json:"pushImage" yaml:"pushImage"` } -//RadixPromoteSpec is the spec for a promote job +// RadixPromoteSpec is the spec for a promote job type RadixPromoteSpec struct { - DeploymentName string `json:"deploymentName" yaml:"deploymentName"` + // Name of the Radix deployment to be promoted + // + // required: false + DeploymentName string `json:"deploymentName" yaml:"deploymentName"` + + // Environment name, from which the Radix deployment is being promoted + // + // required: true + FromEnvironment string `json:"fromEnvironment" yaml:"fromEnvironment"` - ToEnvironment string `json:"toEnvironment" yaml:"toEnvironment"` + // Environment name, to which the Radix deployment is being promoted + // + // required: true + ToEnvironment string `json:"toEnvironment" yaml:"toEnvironment"` } -//RadixDeploySpec is the spec for a deploy job +// RadixDeploySpec is the spec for a deploy job type RadixDeploySpec struct { // Target environment for deploy + // + // required: true ToEnvironment string `json:"toEnvironment" yaml:"toEnvironment"` + // Image tags names for components - if empty will use default logic + // + // required: false // Example: component1: tag1,component2: tag2 ImageTagNames map[string]string `json:"imageTagNames" yaml:"imageTagNames"` + + // Commit ID connected to the deployment + // + // required: false + CommitID string `json:"commitID" yaml:"commitID"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -//RadixJobList is a list of Radix jobs +// RadixJobList is a list of Radix jobs type RadixJobList struct { meta_v1.TypeMeta `json:",inline" yaml:",inline"` meta_v1.ListMeta `json:"metadata" yaml:"metadata"` Items []RadixJob `json:"items" yaml:"items"` } -//RadixJobStep holds status for a single step +// RadixJobStep holds status for a single step type RadixJobStep struct { Name string `json:"name" yaml:"name"` Condition RadixJobCondition `json:"condition" yaml:"condition"` @@ -121,7 +157,7 @@ const ( RadixJobResultStoppedNoChanges RadixJobResultType = "stoppedNoChanges" ) -//RadixJobResult is returned by Radix pipeline jobs via ConfigMap +// RadixJobResult is returned by Radix pipeline jobs via ConfigMap type RadixJobResult struct { Result RadixJobResultType `json:"result" yaml:"result"` Message string `json:"message" yaml:"message"` diff --git a/pkg/apis/test/utils.go b/pkg/apis/test/utils.go index 59287d185..bf2514257 100644 --- a/pkg/apis/test/utils.go +++ b/pkg/apis/test/utils.go @@ -142,14 +142,23 @@ func (tu *Utils) ApplyApplicationUpdate(applicationBuilder utils.ApplicationBuil // ApplyDeployment Will help persist a deployment func (tu *Utils) ApplyDeployment(deploymentBuilder utils.DeploymentBuilder) (*v1.RadixDeployment, error) { + envs := make(map[string]struct{}) if deploymentBuilder.GetApplicationBuilder() != nil { - tu.ApplyApplication(deploymentBuilder.GetApplicationBuilder()) + ra, _ := tu.ApplyApplication(deploymentBuilder.GetApplicationBuilder()) + for _, env := range ra.Spec.Environments { + envs[env.Name] = struct{}{} + } } rd := deploymentBuilder.BuildRD() log.Debugf("%s", rd.GetObjectMeta().GetCreationTimestamp()) + envs[rd.Namespace] = struct{}{} + for env := range envs { + CreateEnvNamespace(tu.client, rd.Spec.AppName, env) + } + + envNamespace := rd.Namespace - envNamespace := CreateEnvNamespace(tu.client, rd.Spec.AppName, rd.Spec.Environment) tu.applyRadixDeploymentEnvVarsConfigMaps(rd) newRd, err := tu.radixclient.RadixV1().RadixDeployments(envNamespace).Create(context.TODO(), rd, metav1.CreateOptions{}) if err != nil {