diff --git a/charts/radix-operator/Chart.yaml b/charts/radix-operator/Chart.yaml index 88b2a0859..bf1474fb8 100644 --- a/charts/radix-operator/Chart.yaml +++ b/charts/radix-operator/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: radix-operator -version: 1.31.2 -appVersion: 1.51.1 +version: 1.31.4 +appVersion: 1.51.3 kubeVersion: ">=1.24.0" description: Radix Operator keywords: diff --git a/pipeline-runner/model/pipelineInfo_test.go b/pipeline-runner/model/pipelineInfo_test.go index e83c86b09..69940857d 100644 --- a/pipeline-runner/model/pipelineInfo_test.go +++ b/pipeline-runner/model/pipelineInfo_test.go @@ -58,6 +58,17 @@ func Test_BuildAndDefaultNoPushOnlyPipeline(t *testing.T) { assert.Equal(t, "run pipelines completed", p.Steps[3].SucceededMsg()) } +func Test_ApplyConfigPipeline(t *testing.T) { + pipelineType, _ := pipeline.GetPipelineFromName(string(v1.ApplyConfig)) + + p, _ := model.InitPipeline(pipelineType, getPipelineArguments(), prepareTektonPipelineStep, applyConfigStep) + assert.Equal(t, v1.ApplyConfig, p.Definition.Type) + assert.False(t, p.PipelineArguments.PushImage) + assert.Equal(t, 2, len(p.Steps)) + assert.Equal(t, "pipelines prepared", p.Steps[0].SucceededMsg()) + assert.Equal(t, "config applied", p.Steps[1].SucceededMsg()) +} + func Test_GetImageTagNamesFromArgs(t *testing.T) { pipelineType, _ := pipeline.GetPipelineFromName(string(v1.Deploy)) type scenario struct { diff --git a/pipeline-runner/steps/apply_radixconfig_test.go b/pipeline-runner/steps/apply_radixconfig_test.go index 6d7df51fc..153d6e3df 100644 --- a/pipeline-runner/steps/apply_radixconfig_test.go +++ b/pipeline-runner/steps/apply_radixconfig_test.go @@ -102,6 +102,50 @@ func (s *applyConfigTestSuite) Test_Deploy_BuildJobInDeployPiplineShouldFail() { s.ErrorIs(err, steps.ErrDeployOnlyPipelineDoesNotSupportBuild) } +func (s *applyConfigTestSuite) Test_ApplyConfig_ShouldNotFail() { + appName := "anyapp" + prepareConfigMapName := "preparecm" + type scenario struct { + name string + componentBuilder *utils.RadixApplicationComponentBuilder + jobComponentBuilder *utils.RadixApplicationJobComponentBuilder + } + scenarios := []scenario{ + {name: "no components"}, + {name: "with a component", componentBuilder: pointers.Ptr(utils.NewApplicationComponentBuilder().WithPort("any", 8080).WithName("comp1"))}, + {name: "with a job-component", jobComponentBuilder: pointers.Ptr(utils.NewApplicationJobComponentBuilder().WithSchedulerPort(pointers.Ptr[int32](8080)).WithName("job1"))}, + } + + for _, ts := range scenarios { + s.T().Run(ts.name, func(t *testing.T) { + s.SetupTest() + rr := utils.NewRegistrationBuilder().WithName(appName).BuildRR() + _, _ = s.radixClient.RadixV1().RadixRegistrations().Create(context.Background(), rr, metav1.CreateOptions{}) + raBuilder := utils.NewRadixApplicationBuilder(). + WithAppName(appName). + WithEnvironment("dev", "anybranch") + if ts.componentBuilder != nil { + raBuilder = raBuilder.WithComponent(*ts.componentBuilder) + } + if ts.jobComponentBuilder != nil { + raBuilder = raBuilder.WithJobComponent(*ts.jobComponentBuilder) + } + ra := raBuilder.BuildRA() + s.Require().NoError(internaltest.CreatePreparePipelineConfigMapResponse(s.kubeClient, prepareConfigMapName, appName, ra, nil)) + + pipeline := model.PipelineInfo{ + PipelineArguments: model.PipelineArguments{}, + RadixConfigMapName: prepareConfigMapName, + } + + applyStep := steps.NewApplyConfigStep() + applyStep.Init(s.kubeClient, s.radixClient, s.kubeUtil, s.promClient, rr) + err := applyStep.Run(&pipeline) + s.NoError(err) + }) + } +} + func (s *applyConfigTestSuite) Test_Deploy_ComponentImageTagName() { appName := "anyapp" prepareConfigMapName := "preparecm" diff --git a/pipeline-runner/steps/prepare_pipelines.go b/pipeline-runner/steps/prepare_pipelines.go index 743127e07..5b99f6c41 100644 --- a/pipeline-runner/steps/prepare_pipelines.go +++ b/pipeline-runner/steps/prepare_pipelines.go @@ -71,7 +71,7 @@ func (cli *PreparePipelinesStepImplementation) Run(pipelineInfo *model.PipelineI commitID := pipelineInfo.PipelineArguments.CommitID appName := cli.GetAppName() namespace := utils.GetAppNamespace(appName) - log.Info().Msgf("Prepare pipelines app %s for branch %s and commit %s", appName, branch, commitID) + logPipelineInfo(pipelineInfo.Definition.Type, appName, branch, commitID) if pipelineInfo.IsPipelineType(radixv1.Promote) { sourceDeploymentGitCommitHash, sourceDeploymentGitBranch, err := cli.getSourceDeploymentGitInfo(appName, pipelineInfo.PipelineArguments.FromEnvironment, pipelineInfo.PipelineArguments.DeploymentName) @@ -102,6 +102,18 @@ func (cli *PreparePipelinesStepImplementation) Run(pipelineInfo *model.PipelineI return cli.jobWaiter.Wait(job) } +func logPipelineInfo(pipelineType radixv1.RadixPipelineType, appName, branch, commitID string) { + stringBuilder := strings.Builder{} + stringBuilder.WriteString(fmt.Sprintf("Prepare pipeline %s for the app %s", pipelineType, appName)) + if len(branch) > 0 { + stringBuilder.WriteString(fmt.Sprintf(", the branch %s", branch)) + } + if len(branch) > 0 { + stringBuilder.WriteString(fmt.Sprintf(", the commit %s", commitID)) + } + log.Info().Msg(stringBuilder.String()) +} + func (cli *PreparePipelinesStepImplementation) getPreparePipelinesJobConfig(pipelineInfo *model.PipelineInfo) *batchv1.Job { appName := cli.GetAppName() registration := cli.GetRegistration() diff --git a/pkg/apis/deployment/deployment_test.go b/pkg/apis/deployment/deployment_test.go index 6169c5c7f..ce5448acb 100644 --- a/pkg/apis/deployment/deployment_test.go +++ b/pkg/apis/deployment/deployment_test.go @@ -4034,6 +4034,7 @@ func Test_ExternalDNS_Legacy_ResourcesMigrated(t *testing.T) { SecretTemplate: &cmv1.CertificateSecretTemplate{ Labels: map[string]string{kube.RadixAppLabel: appName, kube.RadixExternalAliasFQDNLabel: fqdnAutomation}, }, + PrivateKey: &cmv1.CertificatePrivateKey{RotationPolicy: cmv1.RotationPolicyAlways}, } assert.Equal(t, expectedCertSpec, cert.Spec) } @@ -4097,6 +4098,7 @@ func Test_ExternalDNS_ContainsAllResources(t *testing.T) { SecretTemplate: &cmv1.CertificateSecretTemplate{ Labels: map[string]string{kube.RadixAppLabel: appName, kube.RadixExternalAliasFQDNLabel: fqdn}, }, + PrivateKey: &cmv1.CertificatePrivateKey{RotationPolicy: cmv1.RotationPolicyAlways}, } assert.Equal(t, expectedCertSpec, cert.Spec) } diff --git a/pkg/apis/deployment/externaldns.go b/pkg/apis/deployment/externaldns.go index 3638c6137..96069fb9c 100644 --- a/pkg/apis/deployment/externaldns.go +++ b/pkg/apis/deployment/externaldns.go @@ -162,6 +162,9 @@ func (deploy *Deployment) createOrUpdateExternalDnsCertificate(externalDns radix SecretTemplate: &cmv1.CertificateSecretTemplate{ Labels: radixlabels.ForExternalDNSTLSSecret(deploy.registration.Name, externalDns), }, + PrivateKey: &cmv1.CertificatePrivateKey{ + RotationPolicy: cmv1.RotationPolicyAlways, + }, }, } diff --git a/pkg/apis/environment/environment.go b/pkg/apis/environment/environment.go index 03d594340..e44e07bc8 100644 --- a/pkg/apis/environment/environment.go +++ b/pkg/apis/environment/environment.go @@ -131,9 +131,10 @@ func (env *Environment) handleDeletedRadixEnvironmentDependencies(re *v1.RadixEn return err } env.logger.Debug().Msgf("delete %d RadixDNSAlias(es)", len(radixDNSAliasList.Items)) - return env.kubeutil.DeleteRadixDNSAliases(slice.Reduce(radixDNSAliasList.Items, []*v1.RadixDNSAlias{}, func(acc []*v1.RadixDNSAlias, radixDNSAlias v1.RadixDNSAlias) []*v1.RadixDNSAlias { + dnsAliases := slice.Reduce(radixDNSAliasList.Items, []*v1.RadixDNSAlias{}, func(acc []*v1.RadixDNSAlias, radixDNSAlias v1.RadixDNSAlias) []*v1.RadixDNSAlias { return append(acc, &radixDNSAlias) - })...) + }) + return env.kubeutil.DeleteRadixDNSAliases(dnsAliases...) } // ApplyNamespace sets up namespace metadata and applies configuration to kubernetes diff --git a/pkg/apis/job/job_test.go b/pkg/apis/job/job_test.go index 4af1626ca..68eefb8b0 100644 --- a/pkg/apis/job/job_test.go +++ b/pkg/apis/job/job_test.go @@ -222,12 +222,12 @@ func (s *RadixJobTestSuite) TestObjectSynced_PipelineJobCreated() { fmt.Sprintf("--AZURE_SUBSCRIPTION_ID=%s", s.config.subscriptionID), "--RADIX_RESERVED_APP_DNS_ALIASES=api=radix-api", "--RADIX_RESERVED_DNS_ALIASES=grafana", + "--RADIX_FILE_NAME=/workspace/radixconfig.yaml", fmt.Sprintf("--IMAGE_TAG=%s", imageTag), fmt.Sprintf("--BRANCH=%s", branch), fmt.Sprintf("--COMMIT_ID=%s", commitID), "--PUSH_IMAGE=1", "--USE_CACHE=", - "--RADIX_FILE_NAME=/workspace/radixconfig.yaml", }, SecurityContext: &corev1.SecurityContext{ Privileged: pointers.Ptr(false), diff --git a/pkg/apis/job/kubejob.go b/pkg/apis/job/kubejob.go index 284210758..749732d21 100644 --- a/pkg/apis/job/kubejob.go +++ b/pkg/apis/job/kubejob.go @@ -150,6 +150,10 @@ func (job *Job) getPipelineJobArguments(appName, jobName string, jobSpec v1.Radi if job.radixJob.Spec.TektonImage != "" { radixTektonImage = fmt.Sprintf("%s:%s", tektonImage, job.radixJob.Spec.TektonImage) } + radixConfigFullName := jobSpec.RadixConfigFullName + if len(radixConfigFullName) == 0 { + radixConfigFullName = fmt.Sprintf("%s/%s", git.Workspace, defaults.DefaultRadixConfigFileName) + } // Base arguments for all types of pipeline args := []string{ @@ -175,12 +179,9 @@ func (job *Job) getPipelineJobArguments(appName, jobName string, jobSpec v1.Radi fmt.Sprintf("--%s=%s", defaults.AzureSubscriptionIdEnvironmentVariable, subscriptionId), fmt.Sprintf("--%s=%s", defaults.RadixReservedAppDNSAliasesEnvironmentVariable, maps.ToString(job.config.DNSConfig.ReservedAppDNSAliases)), fmt.Sprintf("--%s=%s", defaults.RadixReservedDNSAliasesEnvironmentVariable, strings.Join(job.config.DNSConfig.ReservedDNSAliases, ",")), + fmt.Sprintf("--%s=%s", defaults.RadixConfigFileEnvironmentVariable, radixConfigFullName), } - radixConfigFullName := jobSpec.RadixConfigFullName - if len(radixConfigFullName) == 0 { - radixConfigFullName = fmt.Sprintf("%s/%s", git.Workspace, defaults.DefaultRadixConfigFileName) - } switch pipeline.Type { case v1.BuildDeploy, v1.Build: args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixImageTagEnvironmentVariable, jobSpec.Build.ImageTag)) @@ -188,19 +189,16 @@ func (job *Job) getPipelineJobArguments(appName, jobName string, jobSpec v1.Radi args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixCommitIdEnvironmentVariable, jobSpec.Build.CommitID)) args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixPushImageEnvironmentVariable, getPushImageTag(jobSpec.Build.PushImage))) args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixUseCacheEnvironmentVariable, useImageBuilderCache)) - args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixConfigFileEnvironmentVariable, radixConfigFullName)) case v1.Promote: args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixPromoteDeploymentEnvironmentVariable, jobSpec.Promote.DeploymentName)) args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixPromoteFromEnvironmentEnvironmentVariable, jobSpec.Promote.FromEnvironment)) args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixPromoteToEnvironmentEnvironmentVariable, jobSpec.Promote.ToEnvironment)) - 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)) } - args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixConfigFileEnvironmentVariable, radixConfigFullName)) args = append(args, fmt.Sprintf("--%s=%s", defaults.RadixComponentsToDeployVariable, strings.Join(jobSpec.Deploy.ComponentsToDeploy, ","))) } diff --git a/pkg/apis/kube/radix_dns_alias.go b/pkg/apis/kube/radix_dns_alias.go index e66598a26..a5c7654d4 100644 --- a/pkg/apis/kube/radix_dns_alias.go +++ b/pkg/apis/kube/radix_dns_alias.go @@ -2,6 +2,7 @@ package kube import ( "context" + "errors" "fmt" "github.com/equinor/radix-common/utils/slice" @@ -84,11 +85,14 @@ func (kubeutil *Kube) UpdateRadixDNSAlias(radixDNSAlias *radixv1.RadixDNSAlias) // DeleteRadixDNSAliases Delete RadixDNSAliases func (kubeutil *Kube) DeleteRadixDNSAliases(radixDNSAliases ...*radixv1.RadixDNSAlias) error { + var errs []error for _, radixDNSAlias := range radixDNSAliases { - err := kubeutil.radixclient.RadixV1().RadixDNSAliases().Delete(context.Background(), radixDNSAlias.GetName(), metav1.DeleteOptions{}) - if err != nil { - return err + if radixDNSAlias.ObjectMeta.DeletionTimestamp != nil { + continue + } + if err := kubeutil.radixclient.RadixV1().RadixDNSAliases().Delete(context.Background(), radixDNSAlias.GetName(), metav1.DeleteOptions{}); err != nil { + errs = append(errs, err) } } - return nil + return errors.Join(errs...) } diff --git a/pkg/apis/pipeline/pipeline.go b/pkg/apis/pipeline/pipeline.go index 2157eaad1..e63fb0d52 100644 --- a/pkg/apis/pipeline/pipeline.go +++ b/pkg/apis/pipeline/pipeline.go @@ -37,7 +37,11 @@ func GetSupportedPipelines() []Definition { PreparePipelinesStep, ApplyConfigStep, RunPipelinesStep, - DeployStep}}} + DeployStep}}, + {v1.ApplyConfig, []StepType{ + PreparePipelinesStep, + ApplyConfigStep}}, + } } // GetPipelineFromName Gets pipeline from string diff --git a/pkg/apis/pipeline/pipeline_test.go b/pkg/apis/pipeline/pipeline_test.go index 1c6bbb00f..faa83f5e2 100644 --- a/pkg/apis/pipeline/pipeline_test.go +++ b/pkg/apis/pipeline/pipeline_test.go @@ -20,4 +20,8 @@ func Test_StringToPipelineToString(t *testing.T) { p, _ = GetPipelineFromName("build") assert.Equal(t, "build", string(p.Type)) + + p, _ = GetPipelineFromName("apply-config") + + assert.Equal(t, "apply-config", string(p.Type)) } diff --git a/pkg/apis/radix/v1/radixjobtypes.go b/pkg/apis/radix/v1/radixjobtypes.go index 9f2437aa0..d74a75f04 100644 --- a/pkg/apis/radix/v1/radixjobtypes.go +++ b/pkg/apis/radix/v1/radixjobtypes.go @@ -69,6 +69,7 @@ const ( BuildDeploy RadixPipelineType = "build-deploy" Promote RadixPipelineType = "promote" Deploy RadixPipelineType = "deploy" + ApplyConfig RadixPipelineType = "apply-config" ) // RadixBuildSpec is the spec for a build job diff --git a/radix-operator/dnsalias/controller.go b/radix-operator/dnsalias/controller.go index 3e7667601..297f1bb8d 100644 --- a/radix-operator/dnsalias/controller.go +++ b/radix-operator/dnsalias/controller.go @@ -5,6 +5,7 @@ import ( "reflect" radixutils "github.com/equinor/radix-common/utils" + "github.com/equinor/radix-common/utils/slice" "github.com/equinor/radix-operator/pkg/apis/metrics" radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" radixlabels "github.com/equinor/radix-operator/pkg/apis/utils/labels" @@ -60,6 +61,7 @@ func NewController(kubeClient kubernetes.Interface, addEventHandlersForRadixDeployments(radixInformerFactory, controller, radixClient, &logger) addEventHandlersForIngresses(kubeInformerFactory, controller, &logger) addEventHandlersForRadixRegistrations(radixInformerFactory, controller, radixClient, &logger) + addEventHandlersForRadixApplication(radixInformerFactory, controller, radixClient, &logger) return controller } @@ -72,15 +74,46 @@ func addEventHandlersForRadixRegistrations(radixInformerFactory informers.Shared if oldRR.GetResourceVersion() == newRR.GetResourceVersion() && radixutils.ArrayEqualElements(oldRR.Spec.AdGroups, newRR.Spec.AdGroups) && radixutils.ArrayEqualElements(oldRR.Spec.ReaderAdGroups, newRR.Spec.ReaderAdGroups) { - return // updating RadixDeployment has the same resource version. Do nothing. + return // updating RadixRegistration has the same resource version. Do nothing. + } + enqueueRadixDNSAliasesForAppName(controller, radixClient, newRR.GetName(), logger) + }, + }); err != nil { + panic(err) + } +} + +func addEventHandlersForRadixApplication(radixInformerFactory informers.SharedInformerFactory, controller *common.Controller, radixClient radixclient.Interface, logger *zerolog.Logger) { + informer := radixInformerFactory.Radix().V1().RadixApplications() + if _, err := informer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + UpdateFunc: func(oldObj, newObj interface{}) { + oldRA := oldObj.(*radixv1.RadixApplication) + newRA := newObj.(*radixv1.RadixApplication) + if oldRA.GetResourceVersion() == newRA.GetResourceVersion() || + equalDNSAliases(oldRA.Spec.DNSAlias, newRA.Spec.DNSAlias) { + return // updating RadixApplication has the same resource version and DNS aliases. Do nothing. } - enqueueRadixDNSAliasesForRadixRegistration(controller, radixClient, newRR, logger) + enqueueRadixDNSAliasesForAppName(controller, radixClient, newRA.GetName(), logger) }, }); err != nil { panic(err) } } +func equalDNSAliases(dnsAliases1, dnsAliases2 []radixv1.DNSAlias) bool { + if len(dnsAliases1) != len(dnsAliases2) { + return false + } + dnsAlias1Map := slice.Reduce(dnsAliases1, make(map[string]radixv1.DNSAlias), func(acc map[string]radixv1.DNSAlias, dnsAlias radixv1.DNSAlias) map[string]radixv1.DNSAlias { + acc[dnsAlias.Alias] = dnsAlias + return acc + }) + return slice.All(dnsAliases2, func(dnsAlias2 radixv1.DNSAlias) bool { + dnsAlias1, ok := dnsAlias1Map[dnsAlias2.Alias] + return ok && dnsAlias1.Environment == dnsAlias2.Environment && dnsAlias1.Component == dnsAlias2.Component + }) +} + func addEventHandlersForIngresses(kubeInformerFactory kubeinformers.SharedInformerFactory, controller *common.Controller, logger *zerolog.Logger) { ingressInformer := kubeInformerFactory.Networking().V1().Ingresses() if _, err := ingressInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -192,11 +225,11 @@ func enqueueRadixDNSAliasesForRadixDeployment(controller *common.Controller, rad } } -func enqueueRadixDNSAliasesForRadixRegistration(controller *common.Controller, radixClient radixclient.Interface, rr *radixv1.RadixRegistration, logger *zerolog.Logger) { - logger.Debug().Msgf("Added or updated an RadixRegistration %s. Enqueue relevant RadixDNSAliases", rr.GetName()) - radixDNSAliases, err := getRadixDNSAliasForApp(radixClient, rr.GetName()) +func enqueueRadixDNSAliasesForAppName(controller *common.Controller, radixClient radixclient.Interface, appName string, logger *zerolog.Logger) { + logger.Debug().Msgf("Added or updated an RadixRegistration %s. Enqueue relevant RadixDNSAliases", appName) + radixDNSAliases, err := getRadixDNSAliasForApp(radixClient, appName) if err != nil { - logger.Error().Err(err).Msgf("failed to get list of RadixDNSAliases for the application %s", rr.GetName()) + logger.Error().Err(err).Msgf("failed to get list of RadixDNSAliases for the application %s", appName) return } for _, radixDNSAlias := range radixDNSAliases { @@ -233,7 +266,8 @@ func deepEqual(old, new *radixv1.RadixDNSAlias) bool { return reflect.DeepEqual(new.Spec, old.Spec) && reflect.DeepEqual(new.ObjectMeta.Labels, old.ObjectMeta.Labels) && reflect.DeepEqual(new.ObjectMeta.Annotations, old.ObjectMeta.Annotations) && - reflect.DeepEqual(new.ObjectMeta.Finalizers, old.ObjectMeta.Finalizers) + reflect.DeepEqual(new.ObjectMeta.Finalizers, old.ObjectMeta.Finalizers) && + reflect.DeepEqual(new.ObjectMeta.DeletionTimestamp, old.ObjectMeta.DeletionTimestamp) } func getOwner(radixClient radixclient.Interface, _, name string) (interface{}, error) { diff --git a/radix-operator/dnsalias/controller_test.go b/radix-operator/dnsalias/controller_test.go index 011fbd97c..dd3a606a5 100644 --- a/radix-operator/dnsalias/controller_test.go +++ b/radix-operator/dnsalias/controller_test.go @@ -47,6 +47,7 @@ func (s *controllerTestSuite) Test_RadixDNSAliasEvents() { const ( appName1 = "any-app1" aliasName = "alias-alias-1" + aliasName2 = "alias-alias-2" envName1 = "env1" componentName1 = "server1" componentName2 = "server2" @@ -68,6 +69,12 @@ func (s *controllerTestSuite) Test_RadixDNSAliasEvents() { s.Require().NoError(err) s.WaitForSynced("Sync should be called on add RadixDNSAlias") + appNamespace := utils.GetAppNamespace(appName1) + ra, err := s.RadixClient.RadixV1().RadixApplications(appNamespace).Create(context.Background(), &radixv1.RadixApplication{ + ObjectMeta: metav1.ObjectMeta{Name: appName1}, + Spec: radixv1.RadixApplicationSpec{DNSAlias: []radixv1.DNSAlias{{Alias: aliasName, Environment: envName1, Component: componentName1}}}}, metav1.CreateOptions{}) + s.Require().NoError(err) + // Updating the RadixDNSAlias with component should trigger a sync s.Handler.EXPECT().Sync("", aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(1) alias.Spec.Component = componentName2 @@ -85,28 +92,28 @@ func (s *controllerTestSuite) Test_RadixDNSAliasEvents() { cfg := &dnsalias2.DNSConfig{DNSZone: dnsZone} ing := buildRadixDNSAliasIngress(alias, int32(8080), cfg) ing.SetOwnerReferences([]metav1.OwnerReference{{APIVersion: radixv1.SchemeGroupVersion.Identifier(), Kind: radixv1.KindRadixDNSAlias, Name: aliasName, Controller: pointers.Ptr(true)}}) - namespace := utils.GetEnvironmentNamespace(alias.Spec.AppName, alias.Spec.Environment) - s.Handler.EXPECT().Sync(namespace, aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(0) + envNamespace := utils.GetEnvironmentNamespace(alias.Spec.AppName, alias.Spec.Environment) + s.Handler.EXPECT().Sync(envNamespace, aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(0) ing, err = dnsaliasapi.CreateRadixDNSAliasIngress(s.KubeClient, alias.Spec.AppName, alias.Spec.Environment, ing) s.Require().NoError(err) s.WaitForNotSynced("Sync should not be called when adding ingress") // Sync should not trigger on ingress update if resource version is unchanged - s.Handler.EXPECT().Sync(namespace, aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(0) - ing, err = s.KubeClient.NetworkingV1().Ingresses(namespace).Update(context.Background(), ing, metav1.UpdateOptions{}) + s.Handler.EXPECT().Sync(envNamespace, aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(0) + ing, err = s.KubeClient.NetworkingV1().Ingresses(envNamespace).Update(context.Background(), ing, metav1.UpdateOptions{}) s.Require().NoError(err) s.WaitForNotSynced("Sync should not be called on ingress update with no resource version change") // Sync should trigger on ingress update if resource version is changed ing.ResourceVersion = "2" s.Handler.EXPECT().Sync("", aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(1) - _, err = s.KubeClient.NetworkingV1().Ingresses(namespace).Update(context.Background(), ing, metav1.UpdateOptions{}) + _, err = s.KubeClient.NetworkingV1().Ingresses(envNamespace).Update(context.Background(), ing, metav1.UpdateOptions{}) s.Require().NoError(err) s.WaitForSynced("Sync should be called on k8s ingress update with changed resource version") // Sync should trigger when deleting ingress s.Handler.EXPECT().Sync("", aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(1) - err = s.KubeClient.NetworkingV1().Ingresses(namespace).Delete(context.Background(), ing.GetName(), metav1.DeleteOptions{}) + err = s.KubeClient.NetworkingV1().Ingresses(envNamespace).Delete(context.Background(), ing.GetName(), metav1.DeleteOptions{}) s.Require().NoError(err) s.WaitForSynced("Sync should be called on ingress deletion") @@ -124,6 +131,34 @@ func (s *controllerTestSuite) Test_RadixDNSAliasEvents() { s.Require().NoError(err) s.WaitForSynced("Sync should be called on updated reader ad group") + // Sync should trigger when changed DNSAlias in radix application + s.Handler.EXPECT().Sync("", aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(1) + ra.Spec.DNSAlias[0].Component = componentName2 + ra.ObjectMeta.ResourceVersion = string(uuid.NewUUID()) + _, err = s.RadixClient.RadixV1().RadixApplications(appNamespace).Update(context.Background(), ra, metav1.UpdateOptions{}) + s.Require().NoError(err) + s.WaitForSynced("Sync should be called on updated alias") + + // Sync should trigger when added DNSAlias in radix application + s.Handler.EXPECT().Sync("", aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(1) + ra.Spec.DNSAlias = append(ra.Spec.DNSAlias, radixv1.DNSAlias{ + Alias: aliasName2, + Environment: envName1, + Component: componentName1, + }) + ra.ObjectMeta.ResourceVersion = string(uuid.NewUUID()) + _, err = s.RadixClient.RadixV1().RadixApplications(appNamespace).Update(context.Background(), ra, metav1.UpdateOptions{}) + s.Require().NoError(err) + s.WaitForSynced("Sync should be called on added alias") + + // Sync should trigger when deleted DNSAlias in radix application + s.Handler.EXPECT().Sync("", aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(1) + ra.Spec.DNSAlias = ra.Spec.DNSAlias[1:] + ra.ObjectMeta.ResourceVersion = string(uuid.NewUUID()) + _, err = s.RadixClient.RadixV1().RadixApplications(appNamespace).Update(context.Background(), ra, metav1.UpdateOptions{}) + s.Require().NoError(err) + s.WaitForSynced("Sync should be called on delete alias") + // Delete the RadixDNSAlias should not trigger a sync s.Handler.EXPECT().Sync("", aliasName, s.EventRecorder).DoAndReturn(s.SyncedChannelCallback()).Times(0) err = s.RadixClient.RadixV1().RadixDNSAliases().Delete(context.TODO(), alias.GetName(), metav1.DeleteOptions{})