diff --git a/pkg/controller/atlasdeployment/advanced_deployment.go b/pkg/controller/atlasdeployment/advanced_deployment.go index 61c7237ce8..35aa4029ea 100644 --- a/pkg/controller/atlasdeployment/advanced_deployment.go +++ b/pkg/controller/atlasdeployment/advanced_deployment.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "slices" "strings" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api" @@ -171,9 +172,30 @@ func MergedAdvancedDeployment(atlasDeploymentAsAtlas mongodbatlas.AdvancedCluste atlasDeployment.MongoDBVersion = "" mergedDeployment.MongoDBVersion = "" + atlasDeployment = sortReplicationSpecs(atlasDeployment) + mergedDeployment = sortReplicationSpecs(mergedDeployment) + return } +func sortReplicationSpecs(spec akov2.AdvancedDeploymentSpec) akov2.AdvancedDeploymentSpec { + slices.SortFunc(spec.ReplicationSpecs, func(a, b *akov2.AdvancedReplicationSpec) int { + return strings.Compare(a.ZoneName, b.ZoneName) + }) + for _, r := range spec.ReplicationSpecs { + slices.SortFunc(r.RegionConfigs, func(a, b *akov2.AdvancedRegionConfig) int { + if !(*a.Priority == *b.Priority) { + return *a.Priority - *b.Priority + } else if !strings.EqualFold(a.ProviderName, b.ProviderName) { + return strings.Compare(a.ProviderName, b.ProviderName) + } else { + return strings.Compare(a.RegionName, b.RegionName) + } + }) + } + return spec +} + func IsFreeTierAdvancedDeployment(deployment *mongodbatlas.AdvancedCluster) bool { if deployment != nil && deployment.ReplicationSpecs != nil { for _, replicationSpec := range deployment.ReplicationSpecs { diff --git a/pkg/controller/atlasdeployment/advanced_deployment_test.go b/pkg/controller/atlasdeployment/advanced_deployment_test.go index 0a898be601..d627a8cdb3 100644 --- a/pkg/controller/atlasdeployment/advanced_deployment_test.go +++ b/pkg/controller/atlasdeployment/advanced_deployment_test.go @@ -124,6 +124,129 @@ func TestAdvancedDeploymentsEqual(t *testing.T) { assert.Equal(t, beforeSpec, &merged, "Comparison should not change original spec values") assert.Equal(t, beforeAtlas, &atlas, "Comparison should not change original atlas values") }) + + t.Run("Advanced deployments are the same when region configs are unordered", func(t *testing.T) { + akoDeployment := akov2.DefaultAwsAdvancedDeployment("default", "my-project") + akoDeployment.Spec.DeploymentSpec.ReplicationSpecs[0].RegionConfigs = []*akov2.AdvancedRegionConfig{ + { + ElectableSpecs: &akov2.Specs{ + InstanceSize: "M10", + NodeCount: pointer.MakePtr(1), + }, + ReadOnlySpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(0), + }, + Priority: pointer.MakePtr(7), + ProviderName: "AWS", + RegionName: "US_EAST_1", + }, + { + ElectableSpecs: &akov2.Specs{ + InstanceSize: "M10", + NodeCount: pointer.MakePtr(2), + }, + ReadOnlySpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(0), + }, + Priority: pointer.MakePtr(6), + ProviderName: "AWS", + RegionName: "US_WEST_2", + }, + { + ReadOnlySpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(2), + }, + Priority: pointer.MakePtr(0), + ProviderName: "GCP", + RegionName: "US_WEST_2", + }, + { + AnalyticsSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(2), + }, + Priority: pointer.MakePtr(0), + ProviderName: "AWS", + RegionName: "CA_CENTRAL_1", + }, + { + AnalyticsSpecs: &akov2.Specs{ + InstanceSize: "M10", + NodeCount: pointer.MakePtr(4), + }, + ReadOnlySpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(2), + }, + Priority: pointer.MakePtr(0), + ProviderName: "AWS", + RegionName: "US_WEST_2", + }, + } + + atlasDeployment := makeDefaultAtlasSpec() + atlasDeployment.ReplicationSpecs[0].RegionConfigs = []*mongodbatlas.AdvancedRegionConfig{ + { + AnalyticsSpecs: &mongodbatlas.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(2), + }, + Priority: pointer.MakePtr(0), + ProviderName: "AWS", + RegionName: "CA_CENTRAL_1", + }, + { + ElectableSpecs: &mongodbatlas.Specs{ + InstanceSize: "M10", + NodeCount: pointer.MakePtr(1), + }, + Priority: pointer.MakePtr(7), + ProviderName: "AWS", + RegionName: "US_EAST_1", + }, + { + AnalyticsSpecs: &mongodbatlas.Specs{ + InstanceSize: "M10", + NodeCount: pointer.MakePtr(4), + }, + ReadOnlySpecs: &mongodbatlas.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(2), + }, + Priority: pointer.MakePtr(0), + ProviderName: "AWS", + RegionName: "US_WEST_2", + }, + { + ReadOnlySpecs: &mongodbatlas.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(2), + }, + Priority: pointer.MakePtr(0), + ProviderName: "GCP", + RegionName: "US_WEST_2", + }, + { + ElectableSpecs: &mongodbatlas.Specs{ + InstanceSize: "M10", + NodeCount: pointer.MakePtr(2), + }, + Priority: pointer.MakePtr(6), + ProviderName: "AWS", + RegionName: "US_WEST_2", + }, + } + + merged, atlas, err := MergedAdvancedDeployment(*atlasDeployment, *akoDeployment.Spec.DeploymentSpec) + assert.NoError(t, err) + + logger, _ := zap.NewProduction() + areEqual, _ := AdvancedDeploymentsEqual(logger.Sugar(), &merged, &atlas) + assert.True(t, areEqual, "Deployments should be the same") + }) } func makeDefaultAtlasSpec() *mongodbatlas.AdvancedCluster {