From 44934a5ca172d2eb0bb1c0a1ea325dadf239f8a4 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Thu, 2 Jan 2025 10:27:46 +0000 Subject: [PATCH 01/33] Add initial Flex types --- api/v1/atlasdeployment_types.go | 35 ++++++++++++ api/v1/zz_generated.deepcopy.go | 51 +++++++++++++++++ .../atlas.mongodb.com_atlasdeployments.yaml | 57 +++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/api/v1/atlasdeployment_types.go b/api/v1/atlasdeployment_types.go index 5ae102ba07..2aba998d47 100644 --- a/api/v1/atlasdeployment_types.go +++ b/api/v1/atlasdeployment_types.go @@ -68,6 +68,9 @@ type AtlasDeploymentSpec struct { // ProcessArgs allows to modify Advanced Configuration Options // +optional ProcessArgs *ProcessArgs `json:"processArgs,omitempty"` + + // Configuration for the Flex cluster API. https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Flex-Clusters + FlexSpec *FlexSpec `json:"flexSpec,omitempty"` } type SearchNode struct { @@ -482,6 +485,10 @@ func (c *AtlasDeployment) IsAdvancedDeployment() bool { return c.Spec.DeploymentSpec != nil } +func (c *AtlasDeployment) IsFlex() bool { + return c.Spec.FlexSpec != nil +} + func (c *AtlasDeployment) GetReplicationSetID() string { if len(c.Status.ReplicaSets) > 0 { return c.Status.ReplicaSets[0].ID @@ -530,6 +537,34 @@ func (c *AtlasDeployment) ProjectDualRef() *ProjectDualReference { return &c.Spec.ProjectDualReference } +type FlexSpec struct { + // Human-readable label that identifies the instance. + Name string `json:"name"` + + // List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the instance. + // +kubebuilder:validation:MaxItems=50 + // +optional + Tags []*TagSpec `json:"tags,omitempty"` + + // Flag that indicates whether termination protection is enabled on the cluster. + // If set to true, MongoDB Cloud won't delete the cluster. If set to false, MongoDB Cloud will delete the cluster. + // +kubebuilder:default:=false + TerminationProtectionEnabled bool `json:"terminationProtectionEnabled,omitempty"` + + // Group of cloud provider settings that configure the provisioned MongoDB flex cluster. + ProviderSettings *FlexProviderSettings `json:"providerSettings"` +} + +type FlexProviderSettings struct { + // Cloud service provider on which MongoDB Atlas provisions the flex cluster. + // +kubebuilder:validation:Enum=AWS;GCP;AZURE + BackingProviderName string `json:"backingProviderName,omitempty"` + + // Human-readable label that identifies the geographic location of your MongoDB flex cluster. + // The region you choose can affect network latency for clients accessing your databases. + RegionName string `json:"regionName,omitempty"` +} + // ************************************ Builder methods ************************************************* func NewDeployment(namespace, name, nameInAtlas string) *AtlasDeployment { diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index a894e12fac..bbdc8b6ba5 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -896,6 +896,11 @@ func (in *AtlasDeploymentSpec) DeepCopyInto(out *AtlasDeploymentSpec) { *out = new(ProcessArgs) (*in).DeepCopyInto(*out) } + if in.FlexSpec != nil { + in, out := &in.FlexSpec, &out.FlexSpec + *out = new(FlexSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AtlasDeploymentSpec. @@ -2290,6 +2295,52 @@ func (in *ExternalProjectReference) DeepCopy() *ExternalProjectReference { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlexProviderSettings) DeepCopyInto(out *FlexProviderSettings) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlexProviderSettings. +func (in *FlexProviderSettings) DeepCopy() *FlexProviderSettings { + if in == nil { + return nil + } + out := new(FlexProviderSettings) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FlexSpec) DeepCopyInto(out *FlexSpec) { + *out = *in + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]*TagSpec, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(TagSpec) + **out = **in + } + } + } + if in.ProviderSettings != nil { + in, out := &in.ProviderSettings, &out.ProviderSettings + *out = new(FlexProviderSettings) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlexSpec. +func (in *FlexSpec) DeepCopy() *FlexSpec { + if in == nil { + return nil + } + out := new(FlexSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GCPEndpoint) DeepCopyInto(out *GCPEndpoint) { *out = *in diff --git a/config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml b/config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml index 725d658ff4..705e3e4976 100644 --- a/config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml +++ b/config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml @@ -628,6 +628,63 @@ spec: required: - id type: object + flexSpec: + description: Configuration for the Flex cluster API. https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Flex-Clusters + properties: + name: + description: Human-readable label that identifies the instance. + type: string + providerSettings: + description: Group of cloud provider settings that configure the + provisioned MongoDB flex cluster. + properties: + backingProviderName: + description: Cloud service provider on which MongoDB Atlas + provisions the flex cluster. + enum: + - AWS + - GCP + - AZURE + type: string + regionName: + description: |- + Human-readable label that identifies the geographic location of your MongoDB flex cluster. + The region you choose can affect network latency for clients accessing your databases. + type: string + type: object + tags: + description: List that contains key-value pairs between 1 to 255 + characters in length for tagging and categorizing the instance. + items: + description: TagSpec holds a key-value pair for resource tagging + on this deployment. + properties: + key: + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9][a-zA-Z0-9 @_.+`;`-]*$ + type: string + value: + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9][a-zA-Z0-9@_.+`;`-]*$ + type: string + required: + - key + - value + type: object + maxItems: 50 + type: array + terminationProtectionEnabled: + default: false + description: |- + Flag that indicates whether termination protection is enabled on the cluster. + If set to true, MongoDB Cloud won't delete the cluster. If set to false, MongoDB Cloud will delete the cluster. + type: boolean + required: + - name + - providerSettings + type: object processArgs: description: ProcessArgs allows to modify Advanced Configuration Options properties: From 285b047c2e63061373a9189b34868c2ae2abba19 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 6 Jan 2025 11:00:27 +0000 Subject: [PATCH 02/33] Add Flex to translation layer --- internal/translation/deployment/conversion.go | 123 ++++++++++++++++++ internal/translation/deployment/deployment.go | 27 ++++ internal/translation/tag/tag.go | 17 +++ 3 files changed, 167 insertions(+) diff --git a/internal/translation/deployment/conversion.go b/internal/translation/deployment/conversion.go index ddc38964dc..c6b3c2eff3 100644 --- a/internal/translation/deployment/conversion.go +++ b/internal/translation/deployment/conversion.go @@ -6,6 +6,7 @@ import ( "strings" "go.mongodb.org/atlas-sdk/v20231115008/admin" + adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/common" @@ -25,6 +26,7 @@ type Deployment interface { GetConnection() *status.ConnectionStrings GetReplicaSet() []status.ReplicaSet IsServerless() bool + IsFlex() bool } type Cluster struct { @@ -74,6 +76,10 @@ func (c *Cluster) IsServerless() bool { return false } +func (c *Cluster) IsFlex() bool { + return false +} + func (c *Cluster) IsTenant() bool { return c.isTenant } @@ -120,6 +126,56 @@ func (s *Serverless) IsServerless() bool { return true } +func (s *Serverless) IsFlex() bool { + return false +} + +type Flex struct { + *akov2.FlexSpec + ProjectID string + State string + MongoDBVersion string + Connection *status.ConnectionStrings + + customResource *akov2.AtlasDeployment +} + +func (f *Flex) GetName() string { + return f.Name +} + +func (f *Flex) GetProjectID() string { + return f.ProjectID +} + +func (f *Flex) GetState() string { + return f.State +} + +func (f *Flex) GetMongoDBVersion() string { + return f.MongoDBVersion +} + +func (f *Flex) GetConnection() *status.ConnectionStrings { + return f.Connection +} + +func (f *Flex) GetReplicaSet() []status.ReplicaSet { + return nil +} + +func (f *Flex) GetCustomResource() *akov2.AtlasDeployment { + return f.customResource +} + +func (f *Flex) IsServerless() bool { + return false +} + +func (f *Flex) IsFlex() bool { + return true +} + type Connection struct { Name string ConnURL string @@ -177,6 +233,15 @@ func normalizeServerlessDeployment(serverless *Serverless) { }) } +func normalizeFlexDeployment(flex *Flex) { + if flex.FlexSpec.Tags == nil { + flex.FlexSpec.Tags = []*akov2.TagSpec{} + } + cmp.NormalizeSlice(flex.Tags, func(a, b *akov2.TagSpec) int { + return strings.Compare(a.Key, b.Key) + }) +} + func normalizeClusterDeployment(cluster *Cluster) { isTenant, computeAutoscalingEnabled, instanceSizeOverride := getAutoscalingOverride(cluster.ReplicationSpecs) cluster.computeAutoscalingEnabled = computeAutoscalingEnabled @@ -975,3 +1040,61 @@ func managedNamespaceToAtlas(in *akov2.ManagedNamespace) *admin.ManagedNamespace PresplitHashedZones: in.PresplitHashedZones, } } + +func flexFromAtlas(instance *adminv20241113001.FlexClusterDescription20241113) *Flex { + connectionStrings := instance.GetConnectionStrings() + providerSettings := instance.GetProviderSettings() + + // Copying this because the existing tags.FromAtlas uses a different SDK version + t := instance.GetTags() + tags := make([]*akov2.TagSpec, 0, len(t)) + for _, rTag := range t { + tags = append( + tags, + &akov2.TagSpec{ + Key: rTag.GetKey(), + Value: rTag.GetValue(), + }, + ) + } + + f := &Flex{ + ProjectID: instance.GetGroupId(), + FlexSpec: &akov2.FlexSpec{ + Name: instance.GetName(), + Tags: tags, + TerminationProtectionEnabled: instance.GetTerminationProtectionEnabled(), + ProviderSettings: &akov2.FlexProviderSettings{ + BackingProviderName: providerSettings.GetBackingProviderName(), + RegionName: providerSettings.GetRegionName(), + }, + }, + State: instance.GetStateName(), + MongoDBVersion: instance.GetMongoDBVersion(), + Connection: &status.ConnectionStrings{ + StandardSrv: connectionStrings.GetStandardSrv(), + }, + } + normalizeFlexDeployment(f) + + return f +} + +func flexCreateToAtlas(flex *Flex) *adminv20241113001.FlexClusterDescriptionCreate20241113 { + return &adminv20241113001.FlexClusterDescriptionCreate20241113{ + Name: flex.Name, + Tags: tag.FlexToAtlas(flex.Tags), + TerminationProtectionEnabled: &flex.TerminationProtectionEnabled, + ProviderSettings: adminv20241113001.FlexProviderSettingsCreate20241113{ + BackingProviderName: flex.ProviderSettings.BackingProviderName, + RegionName: flex.ProviderSettings.RegionName, + }, + } +} + +func flexUpdateToAtlas(flex *Flex) *adminv20241113001.FlexClusterDescriptionUpdate20241113 { + return &adminv20241113001.FlexClusterDescriptionUpdate20241113{ + Tags: tag.FlexToAtlas(flex.Tags), + TerminationProtectionEnabled: &flex.TerminationProtectionEnabled, + } +} diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index 8c2b25d098..6471e75083 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -6,6 +6,8 @@ import ( "fmt" "go.mongodb.org/atlas-sdk/v20231115008/admin" + adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" + "go.mongodb.org/atlas/mongodbatlas" "go.uber.org/zap" "k8s.io/apimachinery/pkg/types" @@ -48,6 +50,7 @@ type GlobalClusterService interface { type ProductionAtlasDeployments struct { clustersAPI admin.ClustersApi serverlessAPI admin.ServerlessInstancesApi + flexAPI adminv20241113001.FlexClustersApi globalClusterAPI admin.GlobalClustersApi isGov bool } @@ -155,6 +158,15 @@ func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, project return nil, err } + flex, _, err := ds.flexAPI.GetFlexCluster(ctx, projectID, name).Execute() + if err == nil { + return flexFromAtlas(flex), err + } + + if !admin.IsErrorCode(err, atlas.ClusterNotFound) { + return nil, err + } + return nil, nil } @@ -174,6 +186,12 @@ func (ds *ProductionAtlasDeployments) CreateDeployment(ctx context.Context, depl } return serverlessFromAtlas(serverless), nil + case *Flex: + flex, _, err := ds.flexAPI.CreateFlexCluster(ctx, deployment.GetProjectID(), flexCreateToAtlas(d)).Execute() + if err != nil { + return nil, err + } + return flexFromAtlas(flex), nil } return nil, errors.New("unable to create deployment: unknown type") @@ -195,6 +213,13 @@ func (ds *ProductionAtlasDeployments) UpdateDeployment(ctx context.Context, depl } return serverlessFromAtlas(serverless), nil + case *Flex: + flex, _, err := ds.flexAPI.UpdateFlexCluster(ctx, deployment.GetProjectID(), deployment.GetName(), flexUpdateToAtlas(d)).Execute() + if err != nil { + return nil, err + } + + return flexFromAtlas(flex), nil } return nil, errors.New("unable to create deployment: unknown type") @@ -208,6 +233,8 @@ func (ds *ProductionAtlasDeployments) DeleteDeployment(ctx context.Context, depl _, err = ds.clustersAPI.DeleteCluster(ctx, deployment.GetProjectID(), deployment.GetName()).Execute() case *Serverless: _, _, err = ds.serverlessAPI.DeleteServerlessInstance(ctx, deployment.GetProjectID(), deployment.GetName()).Execute() + case *Flex: + _, _, err = ds.flexAPI.DeleteFlexCluster(ctx, deployment.GetProjectID(), deployment.GetName()).Execute() } if err != nil { diff --git a/internal/translation/tag/tag.go b/internal/translation/tag/tag.go index 61192ebca6..97fb9f7ab4 100644 --- a/internal/translation/tag/tag.go +++ b/internal/translation/tag/tag.go @@ -2,6 +2,7 @@ package tag import ( "go.mongodb.org/atlas-sdk/v20231115008/admin" + adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" ) @@ -40,3 +41,19 @@ func ToAtlas(tags []*akov2.TagSpec) *[]admin.ResourceTag { return &rTags } + +func FlexToAtlas(tags []*akov2.TagSpec) *[]adminv20241113001.ResourceTag { + if tags == nil { + return nil + } + + rTags := make([]adminv20241113001.ResourceTag, 0, len(tags)) + for _, tag := range tags { + rTags = append( + rTags, + *adminv20241113001.NewResourceTag(tag.Key, tag.Value), + ) + } + + return &rTags +} From 41c53787eb1e308a226f2698f8b37227013da76b Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 6 Jan 2025 11:00:45 +0000 Subject: [PATCH 03/33] Add Flex to Deployment controller --- .../atlasdeployment_controller.go | 7 +++ .../atlasdeployment/flex_deployment.go | 59 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 internal/controller/atlasdeployment/flex_deployment.go diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller.go b/internal/controller/atlasdeployment/atlasdeployment_controller.go index 5feb9274b4..42d6053b5c 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller.go @@ -169,6 +169,7 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ } isServerless := atlasDeployment.IsServerless() + isFlex := atlasDeployment.IsFlex() wasDeleted := !atlasDeployment.GetDeletionTimestamp().IsZero() existsInAtlas := deploymentInAtlas != nil @@ -187,6 +188,12 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ serverlessDeployment = deploymentInAtlas.(*deployment.Serverless) } return r.handleServerlessInstance(workflowCtx, projectService, deploymentService, deploymentInAKO.(*deployment.Serverless), serverlessDeployment) + case !wasDeleted && isFlex: + var flexDeployment *deployment.Flex + if existsInAtlas { + flexDeployment = deploymentInAtlas.(*deployment.Flex) + } + return r.handleFlexInstance(workflowCtx, projectService, deploymentService, deploymentInAKO.(*deployment.Flex), flexDeployment) case !wasDeleted && !isServerless: var clusterDeployment *deployment.Cluster if existsInAtlas { diff --git a/internal/controller/atlasdeployment/flex_deployment.go b/internal/controller/atlasdeployment/flex_deployment.go new file mode 100644 index 0000000000..5c7c167995 --- /dev/null +++ b/internal/controller/atlasdeployment/flex_deployment.go @@ -0,0 +1,59 @@ +package atlasdeployment + +import ( + "fmt" + "reflect" + + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/status" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/customresource" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/workflow" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/deployment" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/project" +) + +func (r *AtlasDeploymentReconciler) handleFlexInstance(ctx *workflow.Context, projectService project.ProjectService, deploymentService deployment.AtlasDeploymentsService, deploymentInAKO, deploymentInAtlas *deployment.Flex) (ctrl.Result, error) { + if deploymentInAtlas == nil { + ctx.Log.Infof("Flex Instance %s doesn't exist in Atlas - creating", deploymentInAKO.GetName()) + newFlexDeployment, err := deploymentService.CreateDeployment(ctx.Context, deploymentInAKO) + if err != nil { + return r.terminate(ctx, workflow.DeploymentNotCreatedInAtlas, err) + } + + deploymentInAtlas = newFlexDeployment.(*deployment.Flex) + } + + switch deploymentInAtlas.GetState() { + case status.StateIDLE: + if !reflect.DeepEqual(deploymentInAKO.FlexSpec, deploymentInAtlas.FlexSpec) { + _, err := deploymentService.UpdateDeployment(ctx.Context, deploymentInAKO) + if err != nil { + return r.terminate(ctx, workflow.DeploymentNotUpdatedInAtlas, err) + } + + return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") + } + + err := r.ensureConnectionSecrets(ctx, projectService, deploymentInAKO, deploymentInAtlas.GetConnection()) + if err != nil { + return r.terminate(ctx, workflow.DeploymentConnectionSecretsNotCreated, err) + } + + err = customresource.ApplyLastConfigApplied(ctx.Context, deploymentInAKO.GetCustomResource(), r.Client) + if err != nil { + return r.terminate(ctx, workflow.Internal, err) + } + + return r.ready(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas) + + case status.StateCREATING: + return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentCreating, "deployment is provisioning") + case status.StateUPDATING, status.StateREPAIRING: + return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") + case status.StateDELETING, status.StateDELETED: + return workflow.OK().ReconcileResult(), nil + default: + return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", deploymentInAtlas.GetState())) + } +} From c67934dd0ab94fcbf8dda2df252288e133995948 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 6 Jan 2025 11:12:58 +0000 Subject: [PATCH 04/33] Generate mocks --- internal/mocks/translation/deployment.go | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/internal/mocks/translation/deployment.go b/internal/mocks/translation/deployment.go index 9ba9f4ee0e..0bcf111014 100644 --- a/internal/mocks/translation/deployment.go +++ b/internal/mocks/translation/deployment.go @@ -343,6 +343,51 @@ func (_c *DeploymentMock_GetState_Call) RunAndReturn(run func() string) *Deploym return _c } +// IsFlex provides a mock function with given fields: +func (_m *DeploymentMock) IsFlex() bool { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for IsFlex") + } + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// DeploymentMock_IsFlex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsFlex' +type DeploymentMock_IsFlex_Call struct { + *mock.Call +} + +// IsFlex is a helper method to define mock.On call +func (_e *DeploymentMock_Expecter) IsFlex() *DeploymentMock_IsFlex_Call { + return &DeploymentMock_IsFlex_Call{Call: _e.mock.On("IsFlex")} +} + +func (_c *DeploymentMock_IsFlex_Call) Run(run func()) *DeploymentMock_IsFlex_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *DeploymentMock_IsFlex_Call) Return(_a0 bool) *DeploymentMock_IsFlex_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *DeploymentMock_IsFlex_Call) RunAndReturn(run func() bool) *DeploymentMock_IsFlex_Call { + _c.Call.Return(run) + return _c +} + // IsServerless provides a mock function with given fields: func (_m *DeploymentMock) IsServerless() bool { ret := _m.Called() From 1b63909fa0a73faa7283c3226eef86745c3f3c0a Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Thu, 9 Jan 2025 15:12:38 +0000 Subject: [PATCH 05/33] Correctly propogate Flex API to controllers --- internal/controller/atlas/api_error.go | 3 +++ .../atlasdeployment/atlasdeployment_controller.go | 5 +++-- internal/translation/deployment/deployment.go | 12 ++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/internal/controller/atlas/api_error.go b/internal/controller/atlas/api_error.go index d2f0c008fa..87e8d23cff 100644 --- a/internal/controller/atlas/api_error.go +++ b/internal/controller/atlas/api_error.go @@ -37,4 +37,7 @@ const ( BackupComplianceNotMet = "BACKUP_POLICIES_NOT_MEETING_BACKUP_COMPLIANCE_POLICY_REQUIREMENTS" ProviderUnsupported = "PROVIDER_UNSUPPORTED" + + // Cannot use the Flex API to interact with non-Flex clusters + NonFlexInFlexAPI = "CANNOT_USE_NON_FLEX_CLUSTER_IN_FLEX_API" ) diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller.go b/internal/controller/atlasdeployment/atlasdeployment_controller.go index 42d6053b5c..ec76a3892f 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller.go @@ -140,16 +140,17 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ return r.terminate(workflowCtx, workflow.AtlasAPIAccessNotConfigured, err) } workflowCtx.SdkClient = sdkClient - workflowCtx.SdkClientSet, _, err = r.AtlasProvider.SdkClientSet(workflowCtx.Context, credentials, r.Log) + sdkClientSet, _, err := r.AtlasProvider.SdkClientSet(workflowCtx.Context, credentials, r.Log) if err != nil { return r.terminate(workflowCtx, workflow.AtlasAPIAccessNotConfigured, err) } + workflowCtx.SdkClientSet = sdkClientSet workflowCtx.Client, _, err = r.AtlasProvider.Client(workflowCtx.Context, credentials, r.Log) if err != nil { return r.terminate(workflowCtx, workflow.AtlasAPIAccessNotConfigured, err) } projectService := project.NewProjectAPIService(sdkClient.ProjectsApi) - deploymentService := deployment.NewAtlasDeployments(sdkClient.ClustersApi, sdkClient.ServerlessInstancesApi, sdkClient.GlobalClustersApi, r.AtlasProvider.IsCloudGov()) + deploymentService := deployment.NewAtlasDeployments(sdkClient.ClustersApi, sdkClient.ServerlessInstancesApi, sdkClient.GlobalClustersApi, sdkClientSet.SdkClient20241113001.FlexClustersApi, r.AtlasProvider.IsCloudGov()) atlasProject, err := r.ResolveProject(workflowCtx.Context, sdkClient, atlasDeployment, orgID) if err != nil { return r.terminate(workflowCtx, workflow.AtlasAPIAccessNotConfigured, err) diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index 6471e75083..ed07f31e28 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -60,11 +60,15 @@ func NewAtlasDeploymentsService(ctx context.Context, provider atlas.Provider, se if err != nil { return nil, fmt.Errorf("failed to create versioned client: %w", err) } - return NewAtlasDeployments(client.ClustersApi, client.ServerlessInstancesApi, client.GlobalClustersApi, isGov), nil + clientSet, _, err := provider.SdkClientSet(ctx, secretRef, log) + if err != nil { + return nil, fmt.Errorf("failed to instantiate Versioned Atlas client: %w", err) + } + return NewAtlasDeployments(client.ClustersApi, client.ServerlessInstancesApi, client.GlobalClustersApi, clientSet.SdkClient20241113001.FlexClustersApi, isGov), nil } -func NewAtlasDeployments(clusterService admin.ClustersApi, serverlessAPI admin.ServerlessInstancesApi, globalClusterAPI admin.GlobalClustersApi, isGov bool) *ProductionAtlasDeployments { - return &ProductionAtlasDeployments{clustersAPI: clusterService, serverlessAPI: serverlessAPI, globalClusterAPI: globalClusterAPI, isGov: isGov} +func NewAtlasDeployments(clusterService admin.ClustersApi, serverlessAPI admin.ServerlessInstancesApi, globalClusterAPI admin.GlobalClustersApi, flexAPI adminv20241113001.FlexClustersApi, isGov bool) *ProductionAtlasDeployments { + return &ProductionAtlasDeployments{clustersAPI: clusterService, serverlessAPI: serverlessAPI, globalClusterAPI: globalClusterAPI, flexAPI: flexAPI, isGov: isGov} } func (ds *ProductionAtlasDeployments) ListDeploymentNames(ctx context.Context, projectID string) ([]string, error) { @@ -163,7 +167,7 @@ func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, project return flexFromAtlas(flex), err } - if !admin.IsErrorCode(err, atlas.ClusterNotFound) { + if !admin.IsErrorCode(err, atlas.ClusterNotFound) && !admin.IsErrorCode(err, atlas.NonFlexInFlexAPI) { return nil, err } From cd636a05d740a91b7b936434db3bfd668f9f5c78 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Thu, 9 Jan 2025 15:13:39 +0000 Subject: [PATCH 06/33] fix tests --- .../atlasdatabaseuser/databaseuser_test.go | 8 + .../atlasdeployment_controller_test.go | 8 +- .../translation/deployment/deployment_test.go | 250 ++++++++++++------ 3 files changed, 182 insertions(+), 84 deletions(-) diff --git a/internal/controller/atlasdatabaseuser/databaseuser_test.go b/internal/controller/atlasdatabaseuser/databaseuser_test.go index 42eb8e8cd8..0f2017786a 100644 --- a/internal/controller/atlasdatabaseuser/databaseuser_test.go +++ b/internal/controller/atlasdatabaseuser/databaseuser_test.go @@ -12,6 +12,8 @@ import ( "github.com/stretchr/testify/mock" "go.mongodb.org/atlas-sdk/v20231115008/admin" "go.mongodb.org/atlas-sdk/v20231115008/mockadmin" + adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" + //mockadminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/mockadmin" "go.uber.org/zap" "go.uber.org/zap/zaptest" corev1 "k8s.io/api/core/v1" @@ -191,6 +193,9 @@ func TestHandleDatabaseUser(t *testing.T) { return &admin.APIClient{ProjectsApi: projectAPI, ClustersApi: clusterAPI, DatabaseUsersApi: userAPI}, "", nil }, + SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { + return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{}}, "", nil + }, }, expectedResult: ctrl.Result{RequeueAfter: workflow.DefaultRetry}, expectedConditions: []api.Condition{ @@ -2247,5 +2252,8 @@ func DefaultTestProvider(t *testing.T) *atlasmock.TestProvider { DatabaseUsersApi: userAPI, }, "", nil }, + SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { + return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{}}, "", nil + }, } } diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go index ee21bed7ed..e4b0a42691 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go @@ -31,6 +31,7 @@ import ( "go.mongodb.org/atlas-sdk/v20231115008/admin" "go.mongodb.org/atlas-sdk/v20231115008/mockadmin" adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" + mockadminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/mockadmin" "go.mongodb.org/atlas/mongodbatlas" "go.uber.org/zap" "go.uber.org/zap/zaptest" @@ -1237,7 +1238,12 @@ func TestChangeDeploymentType(t *testing.T) { return true }, SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { - return &atlas.ClientSet{}, "", nil + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + return &atlas.ClientSet{ + SdkClient20241113001: &adminv20241113001.APIClient{ + FlexClustersApi: flexAPI, + }, + }, "", nil }, ClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*mongodbatlas.Client, string, error) { return &mongodbatlas.Client{}, "org-id", nil diff --git a/internal/translation/deployment/deployment_test.go b/internal/translation/deployment/deployment_test.go index 3643bc5af7..aac85ce058 100644 --- a/internal/translation/deployment/deployment_test.go +++ b/internal/translation/deployment/deployment_test.go @@ -12,6 +12,8 @@ import ( "github.com/stretchr/testify/require" "go.mongodb.org/atlas-sdk/v20231115008/admin" "go.mongodb.org/atlas-sdk/v20231115008/mockadmin" + adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" + mockadminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/mockadmin" akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/common" @@ -67,14 +69,14 @@ func TestProductionAtlasDeployments_ListDeploymentConnections(t *testing.T) { func TestClusterExists(t *testing.T) { tests := map[string]struct { deployment Deployment - apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi) + apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) gov bool result bool err error }{ "should fail to assert a cluster exists in atlas": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -82,14 +84,15 @@ func TestClusterExists(t *testing.T) { Return(nil, nil, errors.New("failed to get cluster from atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to get cluster from atlas"), }, "should fail to assert a serverless instance exists in atlas": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -102,13 +105,19 @@ func TestClusterExists(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, errors.New("failed to get serverless instance from atlas")) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.ClusterNotFound)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to get serverless instance from atlas"), }, "should return false when cluster doesn't exist": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -121,12 +130,18 @@ func TestClusterExists(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ProviderUnsupported)) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, }, "should return false when serverless instance doesn't exist": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -139,12 +154,18 @@ func TestClusterExists(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceNotFound)) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, }, "should return a cluster exists": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -156,14 +177,15 @@ func TestClusterExists(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: true, }, "should return a serverless instance exists": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -180,13 +202,19 @@ func TestClusterExists(t *testing.T) { nil, ) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: true, }, "should return false when asserting serverless instance exists in gov": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -195,7 +223,13 @@ func TestClusterExists(t *testing.T) { serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, gov: true, result: false, @@ -204,8 +238,8 @@ func TestClusterExists(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { - clusterAPI, serverlessInstanceAPI := tt.apiMocker() - service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, tt.gov) + clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() + service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, tt.gov) result, err := service.ClusterExists(context.Background(), tt.deployment.GetProjectID(), tt.deployment.GetName()) require.Equal(t, tt.err, err) @@ -217,13 +251,13 @@ func TestClusterExists(t *testing.T) { func TestGetDeployment(t *testing.T) { tests := map[string]struct { deployment Deployment - apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi) + apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error }{ "should fail to retrieve cluster from atlas": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -231,14 +265,15 @@ func TestGetDeployment(t *testing.T) { Return(nil, nil, errors.New("failed to get cluster from atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to get cluster from atlas"), }, "should fail to retrieve serverless instance from atlas": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -251,13 +286,19 @@ func TestGetDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, errors.New("failed to get serverless instance from atlas")) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.ClusterNotFound)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to get serverless instance from atlas"), }, "should return nil when cluster doesn't exist": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -270,12 +311,18 @@ func TestGetDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ProviderUnsupported)) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, }, "should return nil when serverless instance doesn't exist": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -288,12 +335,18 @@ func TestGetDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceNotFound)) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, }, "should return a cluster": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -305,14 +358,15 @@ func TestGetDeployment(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedGeoShardedCluster(), }, "should return a serverless instance": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) @@ -329,7 +383,13 @@ func TestGetDeployment(t *testing.T) { nil, ) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedServerlessInstance(), }, @@ -337,8 +397,8 @@ func TestGetDeployment(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { - clusterAPI, serverlessInstanceAPI := tt.apiMocker() - service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, false) + clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() + service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) result, err := service.GetDeployment(context.Background(), tt.deployment.GetProjectID(), tt.deployment.GetName()) require.Equal(t, tt.err, err) @@ -350,13 +410,13 @@ func TestGetDeployment(t *testing.T) { func TestCreateDeployment(t *testing.T) { tests := map[string]struct { deployment Deployment - apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi) + apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error }{ "should fail to create cluster in atlas": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().CreateCluster(context.Background(), "project-id", mock.AnythingOfType("*admin.AdvancedClusterDescription")). Return(admin.CreateClusterApiRequest{ApiService: clusterAPI}) @@ -364,14 +424,15 @@ func TestCreateDeployment(t *testing.T) { Return(nil, nil, errors.New("failed to create cluster in atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to create cluster in atlas"), }, "should fail to create serverless instance in atlas": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) @@ -380,13 +441,15 @@ func TestCreateDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().CreateServerlessInstanceExecute(mock.AnythingOfType("admin.CreateServerlessInstanceApiRequest")). Return(nil, nil, errors.New("failed to create serverless instance in atlas")) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to create serverless instance in atlas"), }, "should create a cluster": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().CreateCluster(context.Background(), "project-id", mock.AnythingOfType("*admin.AdvancedClusterDescription")). Return(admin.CreateClusterApiRequest{ApiService: clusterAPI}) @@ -398,14 +461,15 @@ func TestCreateDeployment(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedGeoShardedCluster(), }, "should create a serverless instance": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) @@ -418,7 +482,9 @@ func TestCreateDeployment(t *testing.T) { nil, ) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedServerlessInstance(), }, @@ -426,8 +492,8 @@ func TestCreateDeployment(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { - clusterAPI, serverlessInstanceAPI := tt.apiMocker() - service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, false) + clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() + service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) result, err := service.CreateDeployment(context.Background(), tt.deployment) require.Equal(t, tt.err, err) @@ -439,13 +505,13 @@ func TestCreateDeployment(t *testing.T) { func TestUpdateDeployment(t *testing.T) { tests := map[string]struct { deployment Deployment - apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi) + apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error }{ "should fail to update cluster in atlas": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().UpdateCluster(context.Background(), "project-id", "cluster0", mock.AnythingOfType("*admin.AdvancedClusterDescription")). Return(admin.UpdateClusterApiRequest{ApiService: clusterAPI}) @@ -453,14 +519,15 @@ func TestUpdateDeployment(t *testing.T) { Return(nil, nil, errors.New("failed to update cluster in atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to update cluster in atlas"), }, "should fail to update serverless instance in atlas": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) @@ -469,13 +536,15 @@ func TestUpdateDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().UpdateServerlessInstanceExecute(mock.AnythingOfType("admin.UpdateServerlessInstanceApiRequest")). Return(nil, nil, errors.New("failed to update serverless instance in atlas")) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to update serverless instance in atlas"), }, "should update a cluster": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().UpdateCluster(context.Background(), "project-id", "cluster0", mock.AnythingOfType("*admin.AdvancedClusterDescription")). Return(admin.UpdateClusterApiRequest{ApiService: clusterAPI}) @@ -487,14 +556,15 @@ func TestUpdateDeployment(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedGeoShardedCluster(), }, "should update a serverless instance": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) @@ -507,7 +577,9 @@ func TestUpdateDeployment(t *testing.T) { nil, ) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedServerlessInstance(), }, @@ -515,8 +587,8 @@ func TestUpdateDeployment(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { - clusterAPI, serverlessInstanceAPI := tt.apiMocker() - service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, false) + clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() + service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) result, err := service.UpdateDeployment(context.Background(), tt.deployment) require.Equal(t, tt.err, err) @@ -528,13 +600,13 @@ func TestUpdateDeployment(t *testing.T) { func TestDeleteDeployment(t *testing.T) { tests := map[string]struct { deployment Deployment - apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi) + apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error }{ "should fail to delete cluster in atlas": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().DeleteCluster(context.Background(), "project-id", "cluster0"). Return(admin.DeleteClusterApiRequest{ApiService: clusterAPI}) @@ -542,14 +614,15 @@ func TestDeleteDeployment(t *testing.T) { Return(nil, errors.New("failed to delete cluster in atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to delete cluster in atlas"), }, "should fail to delete serverless instance in atlas": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) @@ -558,13 +631,15 @@ func TestDeleteDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().DeleteServerlessInstanceExecute(mock.AnythingOfType("admin.DeleteServerlessInstanceApiRequest")). Return(nil, nil, errors.New("failed to delete serverless instance in atlas")) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to delete serverless instance in atlas"), }, "should delete a cluster": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().DeleteCluster(context.Background(), "project-id", "cluster0"). Return(admin.DeleteClusterApiRequest{ApiService: clusterAPI}) @@ -572,14 +647,15 @@ func TestDeleteDeployment(t *testing.T) { Return(nil, nil) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedGeoShardedCluster(), }, "should delete a serverless instance": { deployment: serverlessInstance(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) @@ -588,7 +664,9 @@ func TestDeleteDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().DeleteServerlessInstanceExecute(mock.AnythingOfType("admin.DeleteServerlessInstanceApiRequest")). Return(nil, nil, nil) - return clusterAPI, serverlessInstanceAPI + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedServerlessInstance(), }, @@ -596,8 +674,8 @@ func TestDeleteDeployment(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { - clusterAPI, serverlessInstanceAPI := tt.apiMocker() - service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, false) + clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() + service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) err := service.DeleteDeployment(context.Background(), tt.deployment) require.Equal(t, tt.err, err) @@ -608,13 +686,13 @@ func TestDeleteDeployment(t *testing.T) { func TestClusterWithProcessArgs(t *testing.T) { tests := map[string]struct { deployment Deployment - apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi) + apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error }{ "should fail to retrieve cluster process args from atlas": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI}) @@ -622,14 +700,15 @@ func TestClusterWithProcessArgs(t *testing.T) { Return(nil, nil, errors.New("failed to get cluster process args from atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to get cluster process args from atlas"), }, "should return process args with default settings": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI}) @@ -645,8 +724,9 @@ func TestClusterWithProcessArgs(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: &Cluster{ ProcessArgs: &akov2.ProcessArgs{ @@ -658,7 +738,7 @@ func TestClusterWithProcessArgs(t *testing.T) { }, "should return process args": { deployment: geoShardedCluster(), - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().GetClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0"). Return(admin.GetClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI}) @@ -681,8 +761,9 @@ func TestClusterWithProcessArgs(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: &Cluster{ ProcessArgs: &akov2.ProcessArgs{ @@ -703,8 +784,8 @@ func TestClusterWithProcessArgs(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { - clusterAPI, serverlessInstanceAPI := tt.apiMocker() - service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, false) + clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() + service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) cluster := tt.deployment.(*Cluster) err := service.ClusterWithProcessArgs(context.Background(), cluster) @@ -719,7 +800,7 @@ func TestClusterWithProcessArgs(t *testing.T) { func TestUpdateProcessArgs(t *testing.T) { tests := map[string]struct { deployment Deployment - apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi) + apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error }{ @@ -733,11 +814,12 @@ func TestUpdateProcessArgs(t *testing.T) { OplogMinRetentionHours: "wrong", }, }, - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: &strconv.NumError{Func: "ParseFloat", Num: "wrong", Err: errors.New("invalid syntax")}, }, @@ -757,7 +839,7 @@ func TestUpdateProcessArgs(t *testing.T) { OplogMinRetentionHours: "12.0", }, }, - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().UpdateClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0", mock.AnythingOfType("*admin.ClusterDescriptionProcessArgs")). Return(admin.UpdateClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI}) @@ -765,8 +847,9 @@ func TestUpdateProcessArgs(t *testing.T) { Return(nil, nil, errors.New("failed to update cluster process args in atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to update cluster process args in atlas"), }, @@ -786,7 +869,7 @@ func TestUpdateProcessArgs(t *testing.T) { OplogMinRetentionHours: "12.0", }, }, - apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi) { + apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) clusterAPI.EXPECT().UpdateClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0", mock.AnythingOfType("*admin.ClusterDescriptionProcessArgs")). Return(admin.UpdateClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI}) @@ -809,8 +892,9 @@ func TestUpdateProcessArgs(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI + return clusterAPI, serverlessInstanceAPI, flexAPI }, result: &Cluster{ ProcessArgs: &akov2.ProcessArgs{ @@ -831,8 +915,8 @@ func TestUpdateProcessArgs(t *testing.T) { for name, tt := range tests { t.Run(name, func(t *testing.T) { - clusterAPI, serverlessInstanceAPI := tt.apiMocker() - service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, false) + clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() + service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) cluster := tt.deployment.(*Cluster) err := service.UpdateProcessArgs(context.Background(), cluster) From cb528477f069b3f448dcbcdb3ebbc15613338b8e Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Thu, 9 Jan 2025 15:14:07 +0000 Subject: [PATCH 07/33] Add SDK Client Set to Contract tests --- test/contract/deployment/deployment_test.go | 2 +- test/helper/contract/ako.go | 22 +++++++++++++++++ test/helper/contract/contract.go | 26 ++++++++++++++------- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/test/contract/deployment/deployment_test.go b/test/contract/deployment/deployment_test.go index 692b20e45e..ffe71ed9c0 100644 --- a/test/contract/deployment/deployment_test.go +++ b/test/contract/deployment/deployment_test.go @@ -35,7 +35,7 @@ func TestListDeployments(t *testing.T) { WithName(serverlessName).WithAtlasName(serverlessName))) testProjectID, err := ch.ProjectID(ctx, projectName) require.NoError(t, err) - ds := deployment.NewAtlasDeployments(ch.AtlasClient().ClustersApi, ch.AtlasClient().ServerlessInstancesApi, nil, false) + ds := deployment.NewAtlasDeployments(ch.AtlasClient().ClustersApi, ch.AtlasClient().ServerlessInstancesApi, nil, ch.AtlasClientSet().SdkClient20241113001.FlexClustersApi, false) names, err := ds.ListDeploymentNames(ctx, testProjectID) require.NoError(t, err) diff --git a/test/helper/contract/ako.go b/test/helper/contract/ako.go index bbcb26433e..6f8b01a365 100644 --- a/test/helper/contract/ako.go +++ b/test/helper/contract/ako.go @@ -12,6 +12,7 @@ import ( akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/atlas" + adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" ) func DefaultAtlasProject(name string) client.Object { @@ -44,6 +45,27 @@ func mustCreateVersionedAtlasClient(ctx context.Context) *admin.APIClient { return client } +func mustCreateVersionedAtlasClientSet(ctx context.Context) *atlas.ClientSet { + domain := os.Getenv("MCLI_OPS_MANAGER_URL") + pubKey := os.Getenv("MCLI_PUBLIC_API_KEY") + prvKey := os.Getenv("MCLI_PRIVATE_API_KEY") + c2024, err := adminv20241113001.NewClient( + adminv20241113001.UseBaseURL(domain), + adminv20241113001.UseDigestAuth(pubKey, prvKey), + ) + if err != nil { + panic(fmt.Sprintf("Failed to create an Atlas versioned client: %v", err)) + } + _, _, err = c2024.ProjectsApi.ListProjects(ctx).Execute() + if err != nil { + panic(fmt.Sprintf("non working Atlas Client: %v", err)) + } + + return &atlas.ClientSet{ + SdkClient20241113001: c2024, + } +} + func globalSecret(namespace string) client.Object { return &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ diff --git a/test/helper/contract/contract.go b/test/helper/contract/contract.go index f88024ad33..7c18cdf88b 100644 --- a/test/helper/contract/contract.go +++ b/test/helper/contract/contract.go @@ -15,22 +15,25 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/atlas" "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/control" "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/e2e/utils" ) type ContractHelper interface { AtlasClient() *admin.APIClient + AtlasClientSet() *atlas.ClientSet AddResources(ctx context.Context, timeout time.Duration, resources ...client.Object) error ProjectID(ctx context.Context, projectName string) (string, error) } type contractTest struct { - credentials bool - namespace string - resources []client.Object - k8sClient client.Client - atlasClient *admin.APIClient + credentials bool + namespace string + resources []client.Object + k8sClient client.Client + atlasClient *admin.APIClient + atlasClientSet *atlas.ClientSet } func (ct *contractTest) cleanup(ctx context.Context) error { @@ -74,10 +77,11 @@ func skipCheck(name, focus string, enabled bool) error { func newContractTest(ctx context.Context) *contractTest { return &contractTest{ - k8sClient: mustCreateK8sClient(), - credentials: false, - resources: []client.Object{}, - atlasClient: mustCreateVersionedAtlasClient(ctx), + k8sClient: mustCreateK8sClient(), + credentials: false, + resources: []client.Object{}, + atlasClient: mustCreateVersionedAtlasClient(ctx), + atlasClientSet: mustCreateVersionedAtlasClientSet(ctx), } } @@ -85,6 +89,10 @@ func (ct *contractTest) AtlasClient() *admin.APIClient { return ct.atlasClient } +func (ct *contractTest) AtlasClientSet() *atlas.ClientSet { + return ct.atlasClientSet +} + func (ct *contractTest) AddResources(ctx context.Context, timeout time.Duration, resources ...client.Object) error { if !ct.credentials { akoTestNamespace := os.Getenv("HELM_AKO_NAMESPACE") From fcfa362d3cf4a88064010182a727fc8e7691b50b Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 13 Jan 2025 10:58:18 +0000 Subject: [PATCH 08/33] fix int tests --- test/int/deployment_test.go | 68 +++++++++++++++++++++++++++++- test/int/integration_suite_test.go | 13 +++++- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/test/int/deployment_test.go b/test/int/deployment_test.go index 82b2065d81..e4a8baaead 100644 --- a/test/int/deployment_test.go +++ b/test/int/deployment_test.go @@ -65,7 +65,7 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- BeforeEach(func() { prepareControllers(false) - deploymentService = deployment.NewAtlasDeployments(atlasClient.ClustersApi, atlasClient.ServerlessInstancesApi, atlasClient.GlobalClustersApi, false) + deploymentService = deployment.NewAtlasDeployments(atlasClient.ClustersApi, atlasClient.ServerlessInstancesApi, atlasClient.GlobalClustersApi, atlasClientv20241113001.FlexClustersApi, false) createdDeployment = &akov2.AtlasDeployment{} manualDeletion = false @@ -147,6 +147,26 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- }) } + doFlexDeploymentStatusChecks := func() { + By("Checking observed Flex state", func() { + atlasDeployment, _, err := atlasClientv20241113001.FlexClustersApi.GetFlexCluster(context.Background(), createdProject.Status.ID, createdDeployment.GetDeploymentName()).Execute() + Expect(err).ToNot(HaveOccurred()) + + Expect(createdDeployment.Status.ConnectionStrings).NotTo(BeNil()) + Expect(createdDeployment.Status.ConnectionStrings.StandardSrv).To(Equal(atlasDeployment.ConnectionStrings.GetStandardSrv())) + Expect(createdDeployment.Status.MongoDBVersion).To(Not(BeEmpty())) + Expect(createdDeployment.Status.StateName).To(Equal("IDLE")) + Expect(createdDeployment.Status.Conditions).To(HaveLen(4)) + Expect(createdDeployment.Status.Conditions).To(ConsistOf(conditions.MatchConditions( + api.TrueCondition(api.DeploymentReadyType), + api.TrueCondition(api.ReadyType), + api.TrueCondition(api.ValidationSucceeded), + api.TrueCondition(api.ResourceVersionStatus), + ))) + Expect(createdDeployment.Status.ObservedGeneration).To(Equal(createdDeployment.Generation)) + }) + } + checkAtlasState := func(additionalChecks ...func(c *admin.AdvancedClusterDescription)) { By("Verifying Deployment state in Atlas", func() { atlasDeploymentAsAtlas, _, err := atlasClient.ClustersApi. @@ -1288,6 +1308,52 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- }) }) }) + + Describe("Create Flex instance", func() { + It("Should Succeed", func(ctx context.Context) { + createdDeployment = akov2.NewDefaultAWSFlexInstance(namespace.Name, createdProject.Name) + createdDeployment.Spec.FlexSpec.Tags = []*akov2.TagSpec{} + By(fmt.Sprintf("Creating the Flex Instance %s", kube.ObjectKeyFromObject(createdDeployment)), func() { + performCreate(createdDeployment, 30*time.Minute) + doFlexDeploymentStatusChecks() + }) + + //nolint:dupl + By("Updating the Instance tags", func() { + createdDeployment = performUpdate(ctx, 20*time.Minute, client.ObjectKeyFromObject(createdDeployment), func(deployment *akov2.AtlasDeployment) { + deployment.Spec.FlexSpec.Tags = []*akov2.TagSpec{{Key: "test-1", Value: "value-1"}, {Key: "test-2", Value: "value-2"}} + }) + + doServerlessDeploymentStatusChecks() + atlasDeployment, _, _ := atlasClientv20241113001.FlexClustersApi. + GetFlexCluster(context.Background(), createdProject.Status.ID, createdDeployment.Spec.FlexSpec.Name). + Execute() + if createdDeployment != nil { + for i, tag := range createdDeployment.Spec.FlexSpec.Tags { + Expect(atlasDeployment.GetTags()[i].GetKey() == tag.Key).To(BeTrue()) + Expect(atlasDeployment.GetTags()[i].GetValue() == tag.Value).To(BeTrue()) + } + } + }) + + //nolint:dupl + By("Updating the Instance tags with a duplicate key and removing all tags", func() { + var err error + createdDeployment, err = akoretry.RetryUpdateOnConflict(ctx, k8sClient, client.ObjectKeyFromObject(createdDeployment), func(deployment *akov2.AtlasDeployment) { + deployment.Spec.FlexSpec.Tags = []*akov2.TagSpec{{Key: "test-1", Value: "value-1"}, {Key: "test-1", Value: "value-2"}} + }) + Expect(err).To(BeNil()) + + Eventually(func() bool { + return resources.CheckCondition(k8sClient, createdDeployment, api.FalseCondition(api.ValidationSucceeded)) + }).WithTimeout(DeploymentUpdateTimeout).Should(BeTrue()) + createdDeployment = performUpdate(ctx, 20*time.Minute, client.ObjectKeyFromObject(createdDeployment), func(deployment *akov2.AtlasDeployment) { + // Removing tags + deployment.Spec.FlexSpec.Tags = []*akov2.TagSpec{} + }) + }) + }) + }) }) var _ = Describe("AtlasDeployment", Ordered, Label("int", "AtlasDeployment", "deployment-backups"), func() { diff --git a/test/int/integration_suite_test.go b/test/int/integration_suite_test.go index 9d64eb2852..c2241111b8 100644 --- a/test/int/integration_suite_test.go +++ b/test/int/integration_suite_test.go @@ -30,6 +30,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "go.mongodb.org/atlas-sdk/v20231115008/admin" + adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -62,8 +63,9 @@ var ( testEnv *envtest.Environment // These variables are initialized once per each node - k8sClient client.Client - atlasClient *admin.APIClient + k8sClient client.Client + atlasClient *admin.APIClient + atlasClientv20241113001 *adminv20241113001.APIClient // These variables are per each test and are changed by each BeforeRun namespace corev1.Namespace @@ -144,6 +146,13 @@ var _ = SynchronizedBeforeSuite(func() []byte { atlasClient, err = atlas.NewClient(atlasDomain, publicKey, privateKey) Expect(err).ToNot(HaveOccurred()) + + atlasClientv20241113001, err = adminv20241113001.NewClient( + adminv20241113001.UseBaseURL(atlasDomain), + adminv20241113001.UseDigestAuth(publicKey, privateKey), + ) + Expect(err).ToNot(HaveOccurred()) + defaultTimeouts() }) }) From a3e1c00c41a9f8259abdc9ecd375932f8d5e8480 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 13 Jan 2025 10:59:03 +0000 Subject: [PATCH 09/33] check for flex before normal cluster --- internal/translation/deployment/conversion.go | 10 ++++++++++ internal/translation/deployment/deployment.go | 18 +++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/internal/translation/deployment/conversion.go b/internal/translation/deployment/conversion.go index c6b3c2eff3..c8aa7a11bc 100644 --- a/internal/translation/deployment/conversion.go +++ b/internal/translation/deployment/conversion.go @@ -211,6 +211,16 @@ func NewDeployment(projectID string, atlasDeployment *akov2.AtlasDeployment) Dep return serverless } + if atlasDeployment.IsFlex() { + flex := &Flex{ + customResource: atlasDeployment, + ProjectID: projectID, + FlexSpec: atlasDeployment.Spec.FlexSpec.DeepCopy(), + } + normalizeFlexDeployment(flex) + return flex + } + cluster := &Cluster{ customResource: atlasDeployment, ProjectID: projectID, diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index ed07f31e28..21240519ea 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -140,6 +140,15 @@ func (ds *ProductionAtlasDeployments) DeploymentIsReady(ctx context.Context, pro } func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, projectID, name string) (Deployment, error) { + flex, _, err := ds.flexAPI.GetFlexCluster(ctx, projectID, name).Execute() + if err == nil { + return flexFromAtlas(flex), err + } + + if !adminv20241113001.IsErrorCode(err, atlas.ClusterNotFound) && !adminv20241113001.IsErrorCode(err, atlas.NonFlexInFlexAPI) { + return nil, err + } + cluster, _, err := ds.clustersAPI.GetCluster(ctx, projectID, name).Execute() if err == nil { return clusterFromAtlas(cluster), nil @@ -162,15 +171,6 @@ func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, project return nil, err } - flex, _, err := ds.flexAPI.GetFlexCluster(ctx, projectID, name).Execute() - if err == nil { - return flexFromAtlas(flex), err - } - - if !admin.IsErrorCode(err, atlas.ClusterNotFound) && !admin.IsErrorCode(err, atlas.NonFlexInFlexAPI) { - return nil, err - } - return nil, nil } From f72fb2fa6f8f7753a686f7adb27783615314001d Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 13 Jan 2025 11:01:17 +0000 Subject: [PATCH 10/33] Add flex helper funcs --- api/v1/atlasdeployment_types.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/api/v1/atlasdeployment_types.go b/api/v1/atlasdeployment_types.go index 2aba998d47..d4a34d9aeb 100644 --- a/api/v1/atlasdeployment_types.go +++ b/api/v1/atlasdeployment_types.go @@ -468,6 +468,9 @@ func (c *AtlasDeployment) GetDeploymentName() string { if c.IsServerless() { return c.Spec.ServerlessSpec.Name } + if c.IsFlex() { + return c.Spec.FlexSpec.Name + } if c.IsAdvancedDeployment() { return c.Spec.DeploymentSpec.Name } @@ -618,6 +621,24 @@ func newServerlessInstance(namespace, name, nameInAtlas, backingProviderName, re } } +func newFlexInstance(namespace, name, nameInAtlas, backingProviderName, regionName string) *AtlasDeployment { + return &AtlasDeployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: AtlasDeploymentSpec{ + FlexSpec: &FlexSpec{ + Name: nameInAtlas, + ProviderSettings: &FlexProviderSettings{ + BackingProviderName: backingProviderName, + RegionName: regionName, + }, + }, + }, + } +} + func addReplicaIfNotAdded(deployment *AtlasDeployment) { if deployment == nil { return @@ -802,6 +823,16 @@ func NewDefaultAWSServerlessInstance(namespace, projectName string) *AtlasDeploy ).WithProjectName(projectName) } +func NewDefaultAWSFlexInstance(namespace, projectName string) *AtlasDeployment { + return newFlexInstance( + namespace, + "test-flex-instance-k8s", + "test-flex-instance", + "AWS", + "US_EAST_1", + ).WithProjectName(projectName) +} + func (c *AtlasDeployment) AtlasName() string { if c.Spec.DeploymentSpec != nil { return c.Spec.DeploymentSpec.Name From 4084f7e91059bda72ed35cbbcc5ec6407fe594e1 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 13 Jan 2025 11:01:52 +0000 Subject: [PATCH 11/33] Update deployment validation to account for flex --- .../atlasdatabaseuser/databaseuser_test.go | 1 + .../atlasdeployment_controller.go | 1 + internal/controller/validate/deployment.go | 23 +++++++++++++------ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/internal/controller/atlasdatabaseuser/databaseuser_test.go b/internal/controller/atlasdatabaseuser/databaseuser_test.go index 0f2017786a..0595a1a72a 100644 --- a/internal/controller/atlasdatabaseuser/databaseuser_test.go +++ b/internal/controller/atlasdatabaseuser/databaseuser_test.go @@ -13,6 +13,7 @@ import ( "go.mongodb.org/atlas-sdk/v20231115008/admin" "go.mongodb.org/atlas-sdk/v20231115008/mockadmin" adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" + //mockadminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/mockadmin" "go.uber.org/zap" "go.uber.org/zap/zaptest" diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller.go b/internal/controller/atlasdeployment/atlasdeployment_controller.go index ec76a3892f..b06242b276 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller.go @@ -171,6 +171,7 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ isServerless := atlasDeployment.IsServerless() isFlex := atlasDeployment.IsFlex() + wasDeleted := !atlasDeployment.GetDeletionTimestamp().IsZero() existsInAtlas := deploymentInAtlas != nil diff --git a/internal/controller/validate/deployment.go b/internal/controller/validate/deployment.go index bea5aeff31..0cac450728 100644 --- a/internal/controller/validate/deployment.go +++ b/internal/controller/validate/deployment.go @@ -14,20 +14,24 @@ import ( func AtlasDeployment(atlasDeployment *akov2.AtlasDeployment, isGov bool, regionUsageRestrictions string) error { isRegularDeployment := atlasDeployment.Spec.DeploymentSpec != nil isServerlessDeployment := atlasDeployment.Spec.ServerlessSpec != nil + isFlexDeployment := atlasDeployment.Spec.FlexSpec != nil var err error var tagsSpec []*akov2.TagSpec switch { - case !isRegularDeployment && !isServerlessDeployment: - return errors.New("expected exactly one of spec.deploymentSpec or spec.serverlessSpec to be present, but none were") - case isRegularDeployment && isServerlessDeployment: - return errors.New("expected exactly one of spec.deploymentSpec or spec.serverlessSpec to be present, but none were") - case !isRegularDeployment && isServerlessDeployment: + case !isRegularDeployment && !isServerlessDeployment && !isFlexDeployment: + return errors.New("expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were") + case isRegularDeployment && !isServerlessDeployment && !isFlexDeployment: + tagsSpec = atlasDeployment.Spec.DeploymentSpec.Tags + err = regularDeployment(atlasDeployment.Spec.DeploymentSpec, isGov, regionUsageRestrictions) + case !isRegularDeployment && isServerlessDeployment && !isFlexDeployment: tagsSpec = atlasDeployment.Spec.ServerlessSpec.Tags err = serverlessDeployment(atlasDeployment.Spec.ServerlessSpec) + case !isRegularDeployment && !isServerlessDeployment && isFlexDeployment: + tagsSpec = atlasDeployment.Spec.FlexSpec.Tags + err = flexDeployment(atlasDeployment.Spec.FlexSpec) default: - tagsSpec = atlasDeployment.Spec.DeploymentSpec.Tags - err = regularDeployment(atlasDeployment.Spec.DeploymentSpec, isGov, regionUsageRestrictions) + return errors.New("expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were") } if err != nil { @@ -265,3 +269,8 @@ func serverlessPrivateEndpoints(privateEndpoints []akov2.ServerlessPrivateEndpoi return nil } + +func flexDeployment(spec *akov2.FlexSpec) error { + // TODO + return nil +} From 9729e1985a37da50f51b05ea459b70d0b45dadf5 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 13 Jan 2025 11:49:49 +0000 Subject: [PATCH 12/33] small fixes after rebase --- internal/controller/atlasdatabaseuser/databaseuser.go | 6 +++++- test/helper/contract/ako.go | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/controller/atlasdatabaseuser/databaseuser.go b/internal/controller/atlasdatabaseuser/databaseuser.go index b8bbe52e9f..f24aa719ec 100644 --- a/internal/controller/atlasdatabaseuser/databaseuser.go +++ b/internal/controller/atlasdatabaseuser/databaseuser.go @@ -52,8 +52,12 @@ func (r *AtlasDatabaseUserReconciler) handleDatabaseUser(ctx *workflow.Context, if err != nil { return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.AtlasAPIAccessNotConfigured, true, err) } + sdkClientSet, _, err := r.AtlasProvider.SdkClientSet(ctx.Context, credentials, r.Log) + if err != nil { + return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.AtlasAPIAccessNotConfigured, true, err) + } dbUserService := dbuser.NewAtlasUsers(sdkClient.DatabaseUsersApi) - deploymentService := deployment.NewAtlasDeployments(sdkClient.ClustersApi, sdkClient.ServerlessInstancesApi, sdkClient.GlobalClustersApi, r.AtlasProvider.IsCloudGov()) + deploymentService := deployment.NewAtlasDeployments(sdkClient.ClustersApi, sdkClient.ServerlessInstancesApi, sdkClient.GlobalClustersApi, sdkClientSet.SdkClient20241113001.FlexClustersApi, r.AtlasProvider.IsCloudGov()) atlasProject, err := r.ResolveProject(ctx.Context, sdkClient, atlasDatabaseUser, orgID) if err != nil { return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.AtlasAPIAccessNotConfigured, true, err) diff --git a/test/helper/contract/ako.go b/test/helper/contract/ako.go index 6f8b01a365..88eb79869e 100644 --- a/test/helper/contract/ako.go +++ b/test/helper/contract/ako.go @@ -10,9 +10,10 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" + adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" + akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/atlas" - adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" ) func DefaultAtlasProject(name string) client.Object { From 935f65d16551138e0251cf9467b2ee4d3f0a1162 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 13 Jan 2025 15:47:05 +0000 Subject: [PATCH 13/33] Fix remaining broken tests --- .../atlasdeployment_controller_test.go | 43 +++++++++-- internal/controller/validate/deployment.go | 11 ++- .../controller/validate/deployment_test.go | 57 +++++++++++++- .../translation/deployment/deployment_test.go | 77 ++++++++++++++++--- 4 files changed, 166 insertions(+), 22 deletions(-) diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go index e4b0a42691..3ff896fbf2 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go @@ -398,7 +398,15 @@ func TestRegularClusterReconciliation(t *testing.T) { orgID := "0987654321" atlasProvider := &atlasmock.TestProvider{ SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { - return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{}}, "", nil + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(mock.Anything, project.ID(), d.GetDeploymentName()). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, &http.Response{}, err) + return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil }, SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { clusterAPI := mockadmin.NewClustersApi(t) @@ -621,7 +629,15 @@ func TestServerlessInstanceReconciliation(t *testing.T) { orgID := "0987654321" atlasProvider := &atlasmock.TestProvider{ SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { - return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{}}, "", nil + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(mock.Anything, project.ID(), d.GetDeploymentName()). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, &http.Response{}, err) + return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil }, SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { err := &admin.GenericOpenAPIError{} @@ -795,7 +811,15 @@ func TestDeletionReconciliation(t *testing.T) { logger := zaptest.NewLogger(t).Sugar() atlasProvider := &atlasmock.TestProvider{ SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { - return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{}}, "", nil + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(mock.Anything, project.ID(), d.GetDeploymentName()). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, &http.Response{}, err) + return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil }, SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { clusterAPI := mockadmin.NewClustersApi(t) @@ -1238,12 +1262,15 @@ func TestChangeDeploymentType(t *testing.T) { return true }, SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return &atlas.ClientSet{ - SdkClient20241113001: &adminv20241113001.APIClient{ - FlexClustersApi: flexAPI, - }, - }, "", nil + flexAPI.EXPECT().GetFlexCluster(mock.Anything, "abc123", "cluster0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, &http.Response{}, err) + return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil }, ClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*mongodbatlas.Client, string, error) { return &mongodbatlas.Client{}, "org-id", nil diff --git a/internal/controller/validate/deployment.go b/internal/controller/validate/deployment.go index 0cac450728..496abbc93b 100644 --- a/internal/controller/validate/deployment.go +++ b/internal/controller/validate/deployment.go @@ -271,6 +271,15 @@ func serverlessPrivateEndpoints(privateEndpoints []akov2.ServerlessPrivateEndpoi } func flexDeployment(spec *akov2.FlexSpec) error { - // TODO + supportedProviders := provider.SupportedProviders() + switch { + case spec.ProviderSettings == nil: + return errors.New("provider settings cannot be empty") + case !supportedProviders.IsSupported(provider.ProviderName(spec.ProviderSettings.BackingProviderName)): + return errors.New("backing provider name is not supported") + case spec.ProviderSettings.RegionName == "": + return errors.New("regionName cannot be empty") + } + return nil } diff --git a/internal/controller/validate/deployment_test.go b/internal/controller/validate/deployment_test.go index 94a409ba76..02fde2184b 100644 --- a/internal/controller/validate/deployment_test.go +++ b/internal/controller/validate/deployment_test.go @@ -17,24 +17,58 @@ func TestAtlasDeployment(t *testing.T) { regionUsageRestrictions string expectedError string }{ - "Both specs present": { + "All specs present": { atlasDeployment: &akov2.AtlasDeployment{ Spec: akov2.AtlasDeploymentSpec{ DeploymentSpec: &akov2.AdvancedDeploymentSpec{}, ServerlessSpec: &akov2.ServerlessSpec{}, + FlexSpec: &akov2.FlexSpec{}, }, }, isGov: false, regionUsageRestrictions: "", - expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec to be present, but none were", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", }, - "Neither spec present": { + "Advanced & Serverless specs present": { + atlasDeployment: &akov2.AtlasDeployment{ + Spec: akov2.AtlasDeploymentSpec{ + DeploymentSpec: &akov2.AdvancedDeploymentSpec{}, + ServerlessSpec: &akov2.ServerlessSpec{}, + }, + }, + isGov: false, + regionUsageRestrictions: "", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", + }, + "Advanced & Flex specs present": { + atlasDeployment: &akov2.AtlasDeployment{ + Spec: akov2.AtlasDeploymentSpec{ + DeploymentSpec: &akov2.AdvancedDeploymentSpec{}, + FlexSpec: &akov2.FlexSpec{}, + }, + }, + isGov: false, + regionUsageRestrictions: "", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", + }, + "Serverless & Flex specs present": { + atlasDeployment: &akov2.AtlasDeployment{ + Spec: akov2.AtlasDeploymentSpec{ + ServerlessSpec: &akov2.ServerlessSpec{}, + FlexSpec: &akov2.FlexSpec{}, + }, + }, + isGov: false, + regionUsageRestrictions: "", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", + }, + "No spec present": { atlasDeployment: &akov2.AtlasDeployment{ Spec: akov2.AtlasDeploymentSpec{}, }, isGov: false, regionUsageRestrictions: "", - expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec to be present, but none were", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", }, "Only DeploymentSpec present": { atlasDeployment: &akov2.AtlasDeployment{ @@ -72,6 +106,21 @@ func TestAtlasDeployment(t *testing.T) { regionUsageRestrictions: "", expectedError: "", }, + "Only FlexSpec present": { + atlasDeployment: &akov2.AtlasDeployment{ + Spec: akov2.AtlasDeploymentSpec{ + FlexSpec: &akov2.FlexSpec{ + ProviderSettings: &akov2.FlexProviderSettings{ + BackingProviderName: "AWS", + RegionName: "US_EAST_1", + }, + }, + }, + }, + isGov: false, + regionUsageRestrictions: "", + expectedError: "", + }, "ServerlessSpec with provider config error": { atlasDeployment: &akov2.AtlasDeployment{ Spec: akov2.AtlasDeploymentSpec{ diff --git a/internal/translation/deployment/deployment_test.go b/internal/translation/deployment/deployment_test.go index aac85ce058..ad430c0374 100644 --- a/internal/translation/deployment/deployment_test.go +++ b/internal/translation/deployment/deployment_test.go @@ -84,7 +84,15 @@ func TestClusterExists(t *testing.T) { Return(nil, nil, errors.New("failed to get cluster from atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -105,11 +113,14 @@ func TestClusterExists(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, errors.New("failed to get serverless instance from atlas")) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.ClusterNotFound)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -130,11 +141,14 @@ func TestClusterExists(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ProviderUnsupported)) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -154,11 +168,14 @@ func TestClusterExists(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceNotFound)) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -177,7 +194,15 @@ func TestClusterExists(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(mock.Anything, "project-id", "cluster0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, &http.Response{}, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -202,11 +227,14 @@ func TestClusterExists(t *testing.T) { nil, ) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -223,11 +251,14 @@ func TestClusterExists(t *testing.T) { serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -265,7 +296,15 @@ func TestGetDeployment(t *testing.T) { Return(nil, nil, errors.New("failed to get cluster from atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -286,11 +325,14 @@ func TestGetDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, errors.New("failed to get serverless instance from atlas")) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.ClusterNotFound)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -311,11 +353,14 @@ func TestGetDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ProviderUnsupported)) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -335,11 +380,14 @@ func TestGetDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceNotFound)) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -358,7 +406,15 @@ func TestGetDeployment(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) + + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) + flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). + Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) + flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, @@ -383,11 +439,14 @@ func TestGetDeployment(t *testing.T) { nil, ) + err := &adminv20241113001.GenericOpenAPIError{} + err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) + flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI)) + Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, From 91f259bd816252c3205952032c6f31a85686ec81 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Thu, 16 Jan 2025 09:35:11 +0000 Subject: [PATCH 14/33] add e2e test --- test/e2e/flex_deployment_test.go | 134 +++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 test/e2e/flex_deployment_test.go diff --git a/test/e2e/flex_deployment_test.go b/test/e2e/flex_deployment_test.go new file mode 100644 index 0000000000..2fc59432e0 --- /dev/null +++ b/test/e2e/flex_deployment_test.go @@ -0,0 +1,134 @@ +package e2e_test + +import ( + "context" + "fmt" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "go.mongodb.org/atlas-sdk/v20241113001/admin" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/mongodb/mongodb-atlas-kubernetes/v2/api" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/e2e/actions" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/e2e/data" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/e2e/model" + akoretry "github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/retry" + + akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/common" +) + +var _ = Describe("Flex", Label("flex"), func() { + var testData *model.TestDataProvider + var flexDeployment *akov2.AtlasDeployment + var apiClient *admin.APIClient + + _ = AfterEach(func() { + GinkgoWriter.Write([]byte("\n")) + GinkgoWriter.Write([]byte("===============================================\n")) + GinkgoWriter.Write([]byte("Flex test\n")) + GinkgoWriter.Write([]byte("Operator namespace: " + testData.Resources.Namespace + "\n")) + GinkgoWriter.Write([]byte("===============================================\n")) + if CurrentSpecReport().Failed() { + Expect(actions.SaveProjectsToFile(testData.Context, testData.K8SClient, testData.Resources.Namespace)).Should(Succeed()) + Expect(actions.SaveDeploymentsToFile(testData.Context, testData.K8SClient, testData.Resources.Namespace)).Should(Succeed()) + } + By("Delete Resources", func() { + actions.DeleteTestDataDeployments(testData) + actions.DeleteTestDataProject(testData) + actions.AfterEachFinalCleanup([]model.TestDataProvider{*testData}) + }) + }) + + BeforeEach(func() { + By("Setting up cloud environment", func() { + testData = model.DataProvider( + "atlas-flex", + model.NewEmptyAtlasKeyType().UseDefaultFullAccess(), + 30005, + []func(*model.TestDataProvider){}, + ). + WithProject(data.DefaultProject()) + actions.ProjectCreationFlow(testData) + }) + By("Creating the API Client", func() { + var err error + domain := os.Getenv("MCLI_OPS_MANAGER_URL") + pubKey := os.Getenv("MCLI_PUBLIC_API_KEY") + prvKey := os.Getenv("MCLI_PRIVATE_API_KEY") + apiClient, err = admin.NewClient( + admin.UseBaseURL(domain), + admin.UseDigestAuth(pubKey, prvKey), + ) + Expect(err).To(BeNil()) + + }) + }) + + It("Creates a Flex Cluster", func(ctx context.Context) { + name := fmt.Sprintf("%s-flex", testData.Project.Name) + + By("Creating an AtlasDeployment CR with a Flex cluster defined", func() { + flexDeployment = &akov2.AtlasDeployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: testData.Resources.Namespace, + }, + Spec: akov2.AtlasDeploymentSpec{ + ProjectDualReference: akov2.ProjectDualReference{ + ProjectRef: &common.ResourceRefNamespaced{ + Name: testData.Project.Name, + }, + }, + FlexSpec: &akov2.FlexSpec{ + Name: name, + ProviderSettings: &akov2.FlexProviderSettings{ + BackingProviderName: "AWS", + RegionName: "EU_WEST_1", + }, + }, + }, + } + Expect(testData.K8SClient.Create(testData.Context, flexDeployment)).Should(Succeed()) + actions.WaitForConditionsToBecomeTrue(testData, api.DeploymentReadyType, api.ReadyType) + }) + By("Checking the Flex cluster is ready in Atlas", func() { + + Eventually(func(g Gomega) { + flex, _, err := apiClient.FlexClustersApi.GetFlexCluster(testData.Context, testData.Project.ID(), name).Execute() + g.Expect(err).To(BeNil()) + g.Expect(flex.GetStateName()).To(Equal("IDLE")) + }).WithTimeout(1 * time.Minute).WithPolling(PollingInterval).Should(Succeed()) + + }) + By("Adding tags to the Flex cluster", func() { + tags := []*akov2.TagSpec{ + {Key: "test-key", Value: "test-value"}, + {Key: "another-test-key", Value: "test-value-2"}, + } + _, err := akoretry.RetryUpdateOnConflict( + ctx, + testData.K8SClient, + client.ObjectKeyFromObject(flexDeployment), + func(flex *akov2.AtlasDeployment) { + flex.Spec.FlexSpec.Tags = tags + }) + Expect(err).To(BeNil()) + }) + By("Deleting the AtlasDeployment CR", func() { + Expect(testData.K8SClient.Delete(ctx, flexDeployment)).Should(Succeed()) + }) + By("Checking the Flex cluster is deleted in Atlas", func() { + Eventually(func(g Gomega) { + _, resp, err := apiClient.FlexClustersApi.GetFlexCluster(testData.Context, testData.Project.ID(), name).Execute() + g.Expect(err).ToNot(BeNil()) + g.Expect(resp).ToNot(BeNil()) + g.Expect(resp.StatusCode).Should(Equal(404)) + }).WithTimeout(5 * time.Minute).WithPolling(PollingInterval).Should(Succeed()) + }) + }) +}) From bdabc78a75012851b61397bfc202afa8dcde75cc Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Thu, 16 Jan 2025 09:38:57 +0000 Subject: [PATCH 15/33] changes per reviews --- api/v1/atlasdeployment_types.go | 7 ++++ .../atlas.mongodb.com_atlasdeployments.yaml | 10 ++++++ .../atlasdatabaseuser/databaseuser_test.go | 1 - internal/controller/validate/deployment.go | 36 +++++++++++++------ .../controller/validate/deployment_test.go | 8 ++--- test/helper/contract/ako.go | 15 ++++---- 6 files changed, 56 insertions(+), 21 deletions(-) diff --git a/api/v1/atlasdeployment_types.go b/api/v1/atlasdeployment_types.go index d4a34d9aeb..259d36ecbc 100644 --- a/api/v1/atlasdeployment_types.go +++ b/api/v1/atlasdeployment_types.go @@ -542,6 +542,7 @@ func (c *AtlasDeployment) ProjectDualRef() *ProjectDualReference { type FlexSpec struct { // Human-readable label that identifies the instance. + // +required Name string `json:"name"` // List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the instance. @@ -552,19 +553,25 @@ type FlexSpec struct { // Flag that indicates whether termination protection is enabled on the cluster. // If set to true, MongoDB Cloud won't delete the cluster. If set to false, MongoDB Cloud will delete the cluster. // +kubebuilder:default:=false + // +optional TerminationProtectionEnabled bool `json:"terminationProtectionEnabled,omitempty"` // Group of cloud provider settings that configure the provisioned MongoDB flex cluster. + // +required ProviderSettings *FlexProviderSettings `json:"providerSettings"` } type FlexProviderSettings struct { // Cloud service provider on which MongoDB Atlas provisions the flex cluster. // +kubebuilder:validation:Enum=AWS;GCP;AZURE + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Backing Provider cannot be modified after cluster creation" + // +required BackingProviderName string `json:"backingProviderName,omitempty"` // Human-readable label that identifies the geographic location of your MongoDB flex cluster. // The region you choose can affect network latency for clients accessing your databases. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Region Name cannot be modified after cluster creation" + // +required RegionName string `json:"regionName,omitempty"` } diff --git a/config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml b/config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml index 705e3e4976..10f08c3958 100644 --- a/config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml +++ b/config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml @@ -646,11 +646,21 @@ spec: - GCP - AZURE type: string + x-kubernetes-validations: + - message: Backing Provider cannot be modified after cluster + creation + rule: self == oldSelf regionName: description: |- Human-readable label that identifies the geographic location of your MongoDB flex cluster. The region you choose can affect network latency for clients accessing your databases. type: string + x-kubernetes-validations: + - message: Region Name cannot be modified after cluster creation + rule: self == oldSelf + required: + - backingProviderName + - regionName type: object tags: description: List that contains key-value pairs between 1 to 255 diff --git a/internal/controller/atlasdatabaseuser/databaseuser_test.go b/internal/controller/atlasdatabaseuser/databaseuser_test.go index 0595a1a72a..03d26ce8c7 100644 --- a/internal/controller/atlasdatabaseuser/databaseuser_test.go +++ b/internal/controller/atlasdatabaseuser/databaseuser_test.go @@ -14,7 +14,6 @@ import ( "go.mongodb.org/atlas-sdk/v20231115008/mockadmin" adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" - //mockadminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/mockadmin" "go.uber.org/zap" "go.uber.org/zap/zaptest" corev1 "k8s.io/api/core/v1" diff --git a/internal/controller/validate/deployment.go b/internal/controller/validate/deployment.go index 496abbc93b..1abad1e415 100644 --- a/internal/controller/validate/deployment.go +++ b/internal/controller/validate/deployment.go @@ -11,27 +11,43 @@ import ( "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/provider" ) +const ( + DeploymentSet = 1 << iota + ServerlessSet + FlexSet +) + +func deploymentSpecMask(atlasDeployment *akov2.AtlasDeployment) int { + mask := 0 + if atlasDeployment.Spec.DeploymentSpec != nil { + mask = mask + DeploymentSet + } + if atlasDeployment.Spec.ServerlessSpec != nil { + mask = mask + ServerlessSet + } + if atlasDeployment.Spec.FlexSpec != nil { + mask = mask + FlexSet + } + return mask +} + func AtlasDeployment(atlasDeployment *akov2.AtlasDeployment, isGov bool, regionUsageRestrictions string) error { - isRegularDeployment := atlasDeployment.Spec.DeploymentSpec != nil - isServerlessDeployment := atlasDeployment.Spec.ServerlessSpec != nil - isFlexDeployment := atlasDeployment.Spec.FlexSpec != nil var err error var tagsSpec []*akov2.TagSpec - - switch { - case !isRegularDeployment && !isServerlessDeployment && !isFlexDeployment: + switch deploymentSpecMask(atlasDeployment) { + case 0: return errors.New("expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were") - case isRegularDeployment && !isServerlessDeployment && !isFlexDeployment: + case DeploymentSet: tagsSpec = atlasDeployment.Spec.DeploymentSpec.Tags err = regularDeployment(atlasDeployment.Spec.DeploymentSpec, isGov, regionUsageRestrictions) - case !isRegularDeployment && isServerlessDeployment && !isFlexDeployment: + case ServerlessSet: tagsSpec = atlasDeployment.Spec.ServerlessSpec.Tags err = serverlessDeployment(atlasDeployment.Spec.ServerlessSpec) - case !isRegularDeployment && !isServerlessDeployment && isFlexDeployment: + case FlexSet: tagsSpec = atlasDeployment.Spec.FlexSpec.Tags err = flexDeployment(atlasDeployment.Spec.FlexSpec) default: - return errors.New("expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were") + return errors.New("expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but multiple were") } if err != nil { diff --git a/internal/controller/validate/deployment_test.go b/internal/controller/validate/deployment_test.go index 02fde2184b..485cefe44a 100644 --- a/internal/controller/validate/deployment_test.go +++ b/internal/controller/validate/deployment_test.go @@ -27,7 +27,7 @@ func TestAtlasDeployment(t *testing.T) { }, isGov: false, regionUsageRestrictions: "", - expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but multiple were", }, "Advanced & Serverless specs present": { atlasDeployment: &akov2.AtlasDeployment{ @@ -38,7 +38,7 @@ func TestAtlasDeployment(t *testing.T) { }, isGov: false, regionUsageRestrictions: "", - expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but multiple were", }, "Advanced & Flex specs present": { atlasDeployment: &akov2.AtlasDeployment{ @@ -49,7 +49,7 @@ func TestAtlasDeployment(t *testing.T) { }, isGov: false, regionUsageRestrictions: "", - expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but multiple were", }, "Serverless & Flex specs present": { atlasDeployment: &akov2.AtlasDeployment{ @@ -60,7 +60,7 @@ func TestAtlasDeployment(t *testing.T) { }, isGov: false, regionUsageRestrictions: "", - expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but none were", + expectedError: "expected exactly one of spec.deploymentSpec or spec.serverlessSpec or spec.flexSpec to be present, but multiple were", }, "No spec present": { atlasDeployment: &akov2.AtlasDeployment{ diff --git a/test/helper/contract/ako.go b/test/helper/contract/ako.go index 88eb79869e..efc3109a35 100644 --- a/test/helper/contract/ako.go +++ b/test/helper/contract/ako.go @@ -24,9 +24,7 @@ func DefaultAtlasProject(name string) client.Object { } func newVersionedClient(ctx context.Context) (*admin.APIClient, error) { - domain := os.Getenv("MCLI_OPS_MANAGER_URL") - pubKey := os.Getenv("MCLI_PUBLIC_API_KEY") - prvKey := os.Getenv("MCLI_PRIVATE_API_KEY") + domain, pubKey, prvKey := getEnvSecrets() client, err := atlas.NewClient(domain, pubKey, prvKey) if err != nil { return nil, fmt.Errorf("failed to setup Atlas Client: %w", err) @@ -47,9 +45,7 @@ func mustCreateVersionedAtlasClient(ctx context.Context) *admin.APIClient { } func mustCreateVersionedAtlasClientSet(ctx context.Context) *atlas.ClientSet { - domain := os.Getenv("MCLI_OPS_MANAGER_URL") - pubKey := os.Getenv("MCLI_PUBLIC_API_KEY") - prvKey := os.Getenv("MCLI_PRIVATE_API_KEY") + domain, pubKey, prvKey := getEnvSecrets() c2024, err := adminv20241113001.NewClient( adminv20241113001.UseBaseURL(domain), adminv20241113001.UseDigestAuth(pubKey, prvKey), @@ -83,3 +79,10 @@ func globalSecret(namespace string) client.Object { }, } } + +func getEnvSecrets() (string, string, string) { + domain := os.Getenv("MCLI_OPS_MANAGER_URL") + pubKey := os.Getenv("MCLI_PUBLIC_API_KEY") + prvKey := os.Getenv("MCLI_PRIVATE_API_KEY") + return domain, pubKey, prvKey +} From fe948eaf41bd87f644bd4a3d49ac30b8881837ce Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Thu, 16 Jan 2025 13:32:41 +0000 Subject: [PATCH 16/33] Ignore dupl in _test.go files --- internal/translation/deployment/deployment_test.go | 5 +---- test/int/deployment_test.go | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/internal/translation/deployment/deployment_test.go b/internal/translation/deployment/deployment_test.go index ad430c0374..c4c28aaa9d 100644 --- a/internal/translation/deployment/deployment_test.go +++ b/internal/translation/deployment/deployment_test.go @@ -1,3 +1,4 @@ +//nolint:dupl package deployment import ( @@ -997,7 +998,6 @@ func atlasAPIError(code string) *admin.GenericOpenAPIError { func geoShardedCluster() *Cluster { return &Cluster{ ProjectID: "project-id", - //nolint:dupl AdvancedDeploymentSpec: &akov2.AdvancedDeploymentSpec{ Name: "cluster0", ClusterType: "GEOSHARDED", @@ -1192,7 +1192,6 @@ func geoShardedCluster() *Cluster { func expectedGeoShardedCluster() *Cluster { return &Cluster{ ProjectID: "project-id", - //nolint:dupl AdvancedDeploymentSpec: &akov2.AdvancedDeploymentSpec{ Name: "cluster0", ClusterType: "GEOSHARDED", @@ -1458,7 +1457,6 @@ func atlasGeoShardedCluster() *admin.AdvancedClusterDescription { }, }, ReplicationSpecs: &[]admin.ReplicationSpec{ - //nolint:dupl { Id: pointer.MakePtr("replication-id-2"), ZoneName: pointer.MakePtr("Zone 2"), @@ -1534,7 +1532,6 @@ func atlasGeoShardedCluster() *admin.AdvancedClusterDescription { }, }, }, - //nolint:dupl { Id: pointer.MakePtr("replication-id-1"), ZoneName: pointer.MakePtr("Zone 1"), diff --git a/test/int/deployment_test.go b/test/int/deployment_test.go index e4a8baaead..1abb6a5f45 100644 --- a/test/int/deployment_test.go +++ b/test/int/deployment_test.go @@ -1,3 +1,4 @@ +//nolint:dupl package int import ( @@ -1272,7 +1273,6 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- doServerlessDeploymentStatusChecks() }) - //nolint:dupl By("Updating the Instance tags", func() { createdDeployment = performUpdate(ctx, 20*time.Minute, client.ObjectKeyFromObject(createdDeployment), func(deployment *akov2.AtlasDeployment) { deployment.Spec.ServerlessSpec.Tags = []*akov2.TagSpec{{Key: "test-1", Value: "value-1"}, {Key: "test-2", Value: "value-2"}} @@ -1290,7 +1290,6 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- } }) - //nolint:dupl By("Updating the Instance tags with a duplicate key and removing all tags", func() { var err error createdDeployment, err = akoretry.RetryUpdateOnConflict(ctx, k8sClient, client.ObjectKeyFromObject(createdDeployment), func(deployment *akov2.AtlasDeployment) { @@ -1318,7 +1317,6 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- doFlexDeploymentStatusChecks() }) - //nolint:dupl By("Updating the Instance tags", func() { createdDeployment = performUpdate(ctx, 20*time.Minute, client.ObjectKeyFromObject(createdDeployment), func(deployment *akov2.AtlasDeployment) { deployment.Spec.FlexSpec.Tags = []*akov2.TagSpec{{Key: "test-1", Value: "value-1"}, {Key: "test-2", Value: "value-2"}} @@ -1336,7 +1334,6 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- } }) - //nolint:dupl By("Updating the Instance tags with a duplicate key and removing all tags", func() { var err error createdDeployment, err = akoretry.RetryUpdateOnConflict(ctx, k8sClient, client.ObjectKeyFromObject(createdDeployment), func(deployment *akov2.AtlasDeployment) { From c05ab5afdd895e6147345dffd2b1cb6f114e804d Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Thu, 16 Jan 2025 17:06:24 +0100 Subject: [PATCH 17/33] api: add optional kubebuilder for flex spec --- api/v1/atlasdeployment_types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/api/v1/atlasdeployment_types.go b/api/v1/atlasdeployment_types.go index 259d36ecbc..b149b0cb25 100644 --- a/api/v1/atlasdeployment_types.go +++ b/api/v1/atlasdeployment_types.go @@ -70,6 +70,7 @@ type AtlasDeploymentSpec struct { ProcessArgs *ProcessArgs `json:"processArgs,omitempty"` // Configuration for the Flex cluster API. https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Flex-Clusters + // +optional FlexSpec *FlexSpec `json:"flexSpec,omitempty"` } From b1b7f77537ec32288b28243c683b8a10f4cdd4f5 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Thu, 16 Jan 2025 17:06:53 +0100 Subject: [PATCH 18/33] be more tolerant for flex API not available --- internal/controller/atlas/api_error.go | 2 ++ .../atlasdeployment/advanced_deployment.go | 2 +- .../atlasdeployment_controller.go | 27 ++++++++++++++++--- .../atlasdeployment/flex_deployment.go | 2 +- internal/translation/deployment/deployment.go | 13 ++++++--- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/internal/controller/atlas/api_error.go b/internal/controller/atlas/api_error.go index 87e8d23cff..6eedc66747 100644 --- a/internal/controller/atlas/api_error.go +++ b/internal/controller/atlas/api_error.go @@ -40,4 +40,6 @@ const ( // Cannot use the Flex API to interact with non-Flex clusters NonFlexInFlexAPI = "CANNOT_USE_NON_FLEX_CLUSTER_IN_FLEX_API" + + FeatureUnsupported = "FEATURE_UNSUPPORTED" ) diff --git a/internal/controller/atlasdeployment/advanced_deployment.go b/internal/controller/atlasdeployment/advanced_deployment.go index 853c744446..821025dc7e 100644 --- a/internal/controller/atlasdeployment/advanced_deployment.go +++ b/internal/controller/atlasdeployment/advanced_deployment.go @@ -109,7 +109,7 @@ func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Conte case status.StateUPDATING, status.StateREPAIRING: return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") case status.StateDELETING, status.StateDELETED: - return workflow.OK().ReconcileResult(), nil + return r.deleted() default: return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", deploymentInAtlas.GetState())) } diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller.go b/internal/controller/atlasdeployment/atlasdeployment_controller.go index b06242b276..6c0f77c22e 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller.go @@ -171,6 +171,7 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ isServerless := atlasDeployment.IsServerless() isFlex := atlasDeployment.IsFlex() + isAdvanced := atlasDeployment.IsAdvancedDeployment() wasDeleted := !atlasDeployment.GetDeletionTimestamp().IsZero() existsInAtlas := deploymentInAtlas != nil @@ -187,20 +188,34 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ case !wasDeleted && isServerless: var serverlessDeployment *deployment.Serverless if existsInAtlas { - serverlessDeployment = deploymentInAtlas.(*deployment.Serverless) + var ok bool + serverlessDeployment, ok = deploymentInAtlas.(*deployment.Serverless) + if !ok { + return r.terminate(workflowCtx, workflow.Internal, errors.New("deployment in Atlas is not a serverless cluster")) + } } return r.handleServerlessInstance(workflowCtx, projectService, deploymentService, deploymentInAKO.(*deployment.Serverless), serverlessDeployment) case !wasDeleted && isFlex: var flexDeployment *deployment.Flex if existsInAtlas { - flexDeployment = deploymentInAtlas.(*deployment.Flex) + var ok bool + flexDeployment, ok = deploymentInAtlas.(*deployment.Flex) + if !ok { + return r.terminate(workflowCtx, workflow.Internal, errors.New("deployment in Atlas is not a flex cluster")) + } } + return r.handleFlexInstance(workflowCtx, projectService, deploymentService, deploymentInAKO.(*deployment.Flex), flexDeployment) - case !wasDeleted && !isServerless: + case !wasDeleted && isAdvanced: var clusterDeployment *deployment.Cluster if existsInAtlas { - clusterDeployment = deploymentInAtlas.(*deployment.Cluster) + var ok bool + clusterDeployment, ok = deploymentInAtlas.(*deployment.Cluster) + if !ok { + return r.terminate(workflowCtx, workflow.Internal, errors.New("deployment in Atlas is not an advanced cluster")) + } } + return r.handleAdvancedDeployment(workflowCtx, projectService, deploymentService, deploymentInAKO.(*deployment.Cluster), clusterDeployment) } @@ -558,3 +573,7 @@ func (r *AtlasDeploymentReconciler) deploymentsForCredentialMapFunc() handler.Ma r.Log, ) } + +func (r *AtlasDeploymentReconciler) deleted() (ctrl.Result, error) { + return workflow.OK().ReconcileResult(), nil +} diff --git a/internal/controller/atlasdeployment/flex_deployment.go b/internal/controller/atlasdeployment/flex_deployment.go index 5c7c167995..e42748819e 100644 --- a/internal/controller/atlasdeployment/flex_deployment.go +++ b/internal/controller/atlasdeployment/flex_deployment.go @@ -52,7 +52,7 @@ func (r *AtlasDeploymentReconciler) handleFlexInstance(ctx *workflow.Context, pr case status.StateUPDATING, status.StateREPAIRING: return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") case status.StateDELETING, status.StateDELETED: - return workflow.OK().ReconcileResult(), nil + return r.deleted() default: return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", deploymentInAtlas.GetState())) } diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index 21240519ea..9825d67245 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -7,7 +7,6 @@ import ( "go.mongodb.org/atlas-sdk/v20231115008/admin" adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" - "go.mongodb.org/atlas/mongodbatlas" "go.uber.org/zap" "k8s.io/apimachinery/pkg/types" @@ -142,11 +141,17 @@ func (ds *ProductionAtlasDeployments) DeploymentIsReady(ctx context.Context, pro func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, projectID, name string) (Deployment, error) { flex, _, err := ds.flexAPI.GetFlexCluster(ctx, projectID, name).Execute() if err == nil { - return flexFromAtlas(flex), err + return flexFromAtlas(flex), nil } - if !adminv20241113001.IsErrorCode(err, atlas.ClusterNotFound) && !adminv20241113001.IsErrorCode(err, atlas.NonFlexInFlexAPI) { - return nil, err + if sdkerr, ok := adminv20241113001.AsError(err); ok { + switch sdkerr.GetErrorCode() { + case atlas.ClusterNotFound: + case atlas.NonFlexInFlexAPI: + case atlas.FeatureUnsupported: + default: + return nil, err + } } cluster, _, err := ds.clustersAPI.GetCluster(ctx, projectID, name).Execute() From c9d0e212b6028a9aba177293655103b97cc2045d Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Thu, 16 Jan 2025 17:09:37 +0100 Subject: [PATCH 19/33] flex: respect gov --- internal/translation/deployment/deployment.go | 24 ++++++++++--------- .../translation/deployment/deployment_test.go | 8 ------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index 9825d67245..4e819e79c2 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -139,18 +139,20 @@ func (ds *ProductionAtlasDeployments) DeploymentIsReady(ctx context.Context, pro } func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, projectID, name string) (Deployment, error) { - flex, _, err := ds.flexAPI.GetFlexCluster(ctx, projectID, name).Execute() - if err == nil { - return flexFromAtlas(flex), nil - } + if !ds.isGov { + flex, _, err := ds.flexAPI.GetFlexCluster(ctx, projectID, name).Execute() + if err == nil { + return flexFromAtlas(flex), nil + } - if sdkerr, ok := adminv20241113001.AsError(err); ok { - switch sdkerr.GetErrorCode() { - case atlas.ClusterNotFound: - case atlas.NonFlexInFlexAPI: - case atlas.FeatureUnsupported: - default: - return nil, err + if sdkerr, ok := adminv20241113001.AsError(err); ok { + switch sdkerr.GetErrorCode() { + case atlas.ClusterNotFound: + case atlas.NonFlexInFlexAPI: + case atlas.FeatureUnsupported: + default: + return nil, err + } } } diff --git a/internal/translation/deployment/deployment_test.go b/internal/translation/deployment/deployment_test.go index c4c28aaa9d..0de71275ee 100644 --- a/internal/translation/deployment/deployment_test.go +++ b/internal/translation/deployment/deployment_test.go @@ -251,15 +251,7 @@ func TestClusterExists(t *testing.T) { Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceFromClusterAPI)) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) - - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, err) return clusterAPI, serverlessInstanceAPI, flexAPI }, From cf56013349f6d19183225c39ae65f0c3d34e0133 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 09:42:42 +0100 Subject: [PATCH 20/33] address linter comments --- .../atlasdeployment/advanced_deployment.go | 67 ++++++++++--------- .../atlasdeployment_controller.go | 57 +++++----------- .../atlasdeployment/flex_deployment.go | 39 ++++++----- .../atlasdeployment/serverless_deployment.go | 40 ++++++----- 4 files changed, 98 insertions(+), 105 deletions(-) diff --git a/internal/controller/atlasdeployment/advanced_deployment.go b/internal/controller/atlasdeployment/advanced_deployment.go index 821025dc7e..a0477baeb4 100644 --- a/internal/controller/atlasdeployment/advanced_deployment.go +++ b/internal/controller/atlasdeployment/advanced_deployment.go @@ -1,6 +1,7 @@ package atlasdeployment import ( + "errors" "fmt" "reflect" "strings" @@ -25,93 +26,99 @@ import ( const FreeTier = "M0" -func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Context, projectService project.ProjectService, deploymentService deployment.AtlasDeploymentsService, deploymentInAKO, deploymentInAtlas *deployment.Cluster) (ctrl.Result, error) { - if deploymentInAtlas == nil { - ctx.Log.Infof("Advanced Deployment %s doesn't exist in Atlas - creating", deploymentInAKO.GetName()) - newDeployment, err := deploymentService.CreateDeployment(ctx.Context, deploymentInAKO) +func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Context, projectService project.ProjectService, deploymentService deployment.AtlasDeploymentsService, akoDeployment, atlasDeployment deployment.Deployment) (ctrl.Result, error) { + akoCluster, ok := akoDeployment.(*deployment.Cluster) + if !ok { + return r.terminate(ctx, workflow.Internal, errors.New("deployment in AKO is not a serverless cluster")) + } + atlasCluster, _ := atlasDeployment.(*deployment.Cluster) + + if atlasCluster == nil { + ctx.Log.Infof("Advanced Deployment %s doesn't exist in Atlas - creating", akoCluster.GetName()) + newDeployment, err := deploymentService.CreateDeployment(ctx.Context, akoCluster) if err != nil { return r.terminate(ctx, workflow.DeploymentNotCreatedInAtlas, err) } - deploymentInAtlas = newDeployment.(*deployment.Cluster) + atlasCluster = newDeployment.(*deployment.Cluster) } - switch deploymentInAtlas.GetState() { + switch atlasCluster.GetState() { case status.StateIDLE: - if changes, occurred := deployment.ComputeChanges(deploymentInAKO, deploymentInAtlas); occurred { + if changes, occurred := deployment.ComputeChanges(akoCluster, atlasCluster); occurred { updatedDeployment, err := deploymentService.UpdateDeployment(ctx.Context, changes) if err != nil { return r.terminate(ctx, workflow.DeploymentNotUpdatedInAtlas, err) } - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), updatedDeployment, workflow.DeploymentUpdating, "deployment is updating") + return r.inProgress(ctx, akoCluster.GetCustomResource(), updatedDeployment, workflow.DeploymentUpdating, "deployment is updating") } - transition := r.ensureBackupScheduleAndPolicy(ctx, deploymentService, deploymentInAKO.GetProjectID(), deploymentInAKO.GetCustomResource()) + transition := r.ensureBackupScheduleAndPolicy(ctx, deploymentService, akoCluster.GetProjectID(), akoCluster.GetCustomResource()) if transition != nil { return transition(workflow.Internal) } - transition = r.ensureAdvancedOptions(ctx, deploymentService, deploymentInAKO, deploymentInAtlas) + transition = r.ensureAdvancedOptions(ctx, deploymentService, akoCluster, atlasCluster) if transition != nil { return transition(workflow.DeploymentAdvancedOptionsReady) } - err := r.ensureConnectionSecrets(ctx, projectService, deploymentInAKO, deploymentInAtlas.GetConnection()) + err := r.ensureConnectionSecrets(ctx, projectService, akoCluster, atlasCluster.GetConnection()) if err != nil { return r.terminate(ctx, workflow.DeploymentConnectionSecretsNotCreated, err) } if !r.AtlasProvider.IsCloudGov() { - searchNodeResult := handleSearchNodes(ctx, deploymentInAKO.GetCustomResource(), deploymentInAKO.GetProjectID()) - if transition = r.transitionFromResult(ctx, deploymentService, deploymentInAKO.GetProjectID(), deploymentInAKO.GetCustomResource(), searchNodeResult); transition != nil { + searchNodeResult := handleSearchNodes(ctx, akoCluster.GetCustomResource(), akoCluster.GetProjectID()) + if transition = r.transitionFromResult(ctx, deploymentService, akoCluster.GetProjectID(), akoCluster.GetCustomResource(), searchNodeResult); transition != nil { return transition(workflow.Internal) } } searchService := searchindex.NewSearchIndexes(ctx.SdkClientSet.SdkClient20241113001.AtlasSearchApi) - result := handleSearchIndexes(ctx, r.Client, searchService, deploymentInAKO.GetCustomResource(), deploymentInAKO.GetProjectID()) - if transition = r.transitionFromResult(ctx, deploymentService, deploymentInAKO.GetProjectID(), deploymentInAKO.GetCustomResource(), result); transition != nil { + result := handleSearchIndexes(ctx, r.Client, searchService, akoCluster.GetCustomResource(), akoCluster.GetProjectID()) + if transition = r.transitionFromResult(ctx, deploymentService, akoCluster.GetProjectID(), akoCluster.GetCustomResource(), result); transition != nil { return transition(workflow.Internal) } result = r.ensureCustomZoneMapping( ctx, deploymentService, - deploymentInAKO.GetProjectID(), - deploymentInAKO.GetCustomResource().Spec.DeploymentSpec.CustomZoneMapping, - deploymentInAKO.GetName(), + akoCluster.GetProjectID(), + akoCluster.GetCustomResource().Spec.DeploymentSpec.CustomZoneMapping, + akoCluster.GetName(), ) - if transition = r.transitionFromResult(ctx, deploymentService, deploymentInAKO.GetProjectID(), deploymentInAKO.GetCustomResource(), result); transition != nil { + if transition = r.transitionFromResult(ctx, deploymentService, akoCluster.GetProjectID(), akoCluster.GetCustomResource(), result); transition != nil { return transition(workflow.Internal) } result = r.ensureManagedNamespaces( ctx, deploymentService, - deploymentInAKO.GetProjectID(), - deploymentInAKO.ClusterType, - deploymentInAKO.GetCustomResource().Spec.DeploymentSpec.ManagedNamespaces, - deploymentInAKO.GetName(), + akoCluster.GetProjectID(), + akoCluster.ClusterType, + akoCluster.GetCustomResource().Spec.DeploymentSpec.ManagedNamespaces, + akoCluster.GetName(), ) - if transition = r.transitionFromResult(ctx, deploymentService, deploymentInAKO.GetProjectID(), deploymentInAKO.GetCustomResource(), result); transition != nil { + if transition = r.transitionFromResult(ctx, deploymentService, akoCluster.GetProjectID(), akoCluster.GetCustomResource(), result); transition != nil { return transition(workflow.Internal) } - err = customresource.ApplyLastConfigApplied(ctx.Context, deploymentInAKO.GetCustomResource(), r.Client) + err = customresource.ApplyLastConfigApplied(ctx.Context, akoCluster.GetCustomResource(), r.Client) if err != nil { return r.terminate(ctx, workflow.Internal, err) } - return r.ready(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas) + return r.ready(ctx, akoCluster.GetCustomResource(), atlasCluster) case status.StateCREATING: - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentCreating, "deployment is provisioning") + return r.inProgress(ctx, akoCluster.GetCustomResource(), atlasCluster, workflow.DeploymentCreating, "deployment is provisioning") case status.StateUPDATING, status.StateREPAIRING: - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") + return r.inProgress(ctx, akoCluster.GetCustomResource(), atlasCluster, workflow.DeploymentUpdating, "deployment is updating") case status.StateDELETING, status.StateDELETED: - return r.deleted() + return r.handleDeleted() default: - return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", deploymentInAtlas.GetState())) + return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", atlasCluster.GetState())) } } diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller.go b/internal/controller/atlasdeployment/atlasdeployment_controller.go index 6c0f77c22e..0d0dc5bf6c 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller.go @@ -169,54 +169,27 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ return r.terminate(workflowCtx, workflow.Internal, err) } - isServerless := atlasDeployment.IsServerless() - isFlex := atlasDeployment.IsFlex() - isAdvanced := atlasDeployment.IsAdvancedDeployment() - - wasDeleted := !atlasDeployment.GetDeletionTimestamp().IsZero() existsInAtlas := deploymentInAtlas != nil - if existsInAtlas && deploymentInAKO.IsServerless() != deploymentInAtlas.IsServerless() { return r.terminate(workflowCtx, workflow.Internal, errors.New("regular deployment cannot be converted into a serverless deployment and vice-versa")) } - switch { - case existsInAtlas && wasDeleted: - return r.delete(workflowCtx, deploymentService, deploymentInAKO) - case !existsInAtlas && wasDeleted: - return r.unmanage(workflowCtx, atlasDeployment) - case !wasDeleted && isServerless: - var serverlessDeployment *deployment.Serverless + if !atlasDeployment.GetDeletionTimestamp().IsZero() { if existsInAtlas { - var ok bool - serverlessDeployment, ok = deploymentInAtlas.(*deployment.Serverless) - if !ok { - return r.terminate(workflowCtx, workflow.Internal, errors.New("deployment in Atlas is not a serverless cluster")) - } - } - return r.handleServerlessInstance(workflowCtx, projectService, deploymentService, deploymentInAKO.(*deployment.Serverless), serverlessDeployment) - case !wasDeleted && isFlex: - var flexDeployment *deployment.Flex - if existsInAtlas { - var ok bool - flexDeployment, ok = deploymentInAtlas.(*deployment.Flex) - if !ok { - return r.terminate(workflowCtx, workflow.Internal, errors.New("deployment in Atlas is not a flex cluster")) - } + return r.delete(workflowCtx, deploymentService, deploymentInAKO) } + return r.unmanage(workflowCtx, deploymentInAKO) + } - return r.handleFlexInstance(workflowCtx, projectService, deploymentService, deploymentInAKO.(*deployment.Flex), flexDeployment) - case !wasDeleted && isAdvanced: - var clusterDeployment *deployment.Cluster - if existsInAtlas { - var ok bool - clusterDeployment, ok = deploymentInAtlas.(*deployment.Cluster) - if !ok { - return r.terminate(workflowCtx, workflow.Internal, errors.New("deployment in Atlas is not an advanced cluster")) - } - } + switch { + case atlasDeployment.IsServerless(): + return r.handleServerlessInstance(workflowCtx, projectService, deploymentService, deploymentInAKO, deploymentInAtlas) + + case atlasDeployment.IsFlex(): + return r.handleFlexInstance(workflowCtx, projectService, deploymentService, deploymentInAKO, deploymentInAtlas) - return r.handleAdvancedDeployment(workflowCtx, projectService, deploymentService, deploymentInAKO.(*deployment.Cluster), clusterDeployment) + case atlasDeployment.IsAdvancedDeployment(): + return r.handleAdvancedDeployment(workflowCtx, projectService, deploymentService, deploymentInAKO, deploymentInAtlas) } return workflow.OK().ReconcileResult(), nil @@ -393,8 +366,8 @@ func (r *AtlasDeploymentReconciler) ready(ctx *workflow.Context, atlasDeployment return workflow.OK().ReconcileResult(), nil } -func (r *AtlasDeploymentReconciler) unmanage(ctx *workflow.Context, atlasDeployment *akov2.AtlasDeployment) (ctrl.Result, error) { - err := r.removeDeletionFinalizer(ctx.Context, atlasDeployment) +func (r *AtlasDeploymentReconciler) unmanage(ctx *workflow.Context, atlasDeployment deployment.Deployment) (ctrl.Result, error) { + err := r.removeDeletionFinalizer(ctx.Context, atlasDeployment.GetCustomResource()) if err != nil { return r.terminate(ctx, workflow.AtlasFinalizerNotRemoved, err) } @@ -574,6 +547,6 @@ func (r *AtlasDeploymentReconciler) deploymentsForCredentialMapFunc() handler.Ma ) } -func (r *AtlasDeploymentReconciler) deleted() (ctrl.Result, error) { +func (r *AtlasDeploymentReconciler) handleDeleted() (ctrl.Result, error) { return workflow.OK().ReconcileResult(), nil } diff --git a/internal/controller/atlasdeployment/flex_deployment.go b/internal/controller/atlasdeployment/flex_deployment.go index e42748819e..0618939688 100644 --- a/internal/controller/atlasdeployment/flex_deployment.go +++ b/internal/controller/atlasdeployment/flex_deployment.go @@ -1,6 +1,7 @@ package atlasdeployment import ( + "errors" "fmt" "reflect" @@ -13,47 +14,53 @@ import ( "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/project" ) -func (r *AtlasDeploymentReconciler) handleFlexInstance(ctx *workflow.Context, projectService project.ProjectService, deploymentService deployment.AtlasDeploymentsService, deploymentInAKO, deploymentInAtlas *deployment.Flex) (ctrl.Result, error) { - if deploymentInAtlas == nil { - ctx.Log.Infof("Flex Instance %s doesn't exist in Atlas - creating", deploymentInAKO.GetName()) - newFlexDeployment, err := deploymentService.CreateDeployment(ctx.Context, deploymentInAKO) +func (r *AtlasDeploymentReconciler) handleFlexInstance(ctx *workflow.Context, projectService project.ProjectService, deploymentService deployment.AtlasDeploymentsService, akoDeployment, atlasDeployment deployment.Deployment) (ctrl.Result, error) { + akoFlex, ok := akoDeployment.(*deployment.Flex) + if !ok { + return r.terminate(ctx, workflow.Internal, errors.New("deployment in AKO is not a serverless cluster")) + } + atlasFlex, _ := atlasDeployment.(*deployment.Flex) + + if atlasFlex == nil { + ctx.Log.Infof("Flex Instance %s doesn't exist in Atlas - creating", akoFlex.GetName()) + newFlexDeployment, err := deploymentService.CreateDeployment(ctx.Context, akoFlex) if err != nil { return r.terminate(ctx, workflow.DeploymentNotCreatedInAtlas, err) } - deploymentInAtlas = newFlexDeployment.(*deployment.Flex) + atlasFlex = newFlexDeployment.(*deployment.Flex) } - switch deploymentInAtlas.GetState() { + switch atlasFlex.GetState() { case status.StateIDLE: - if !reflect.DeepEqual(deploymentInAKO.FlexSpec, deploymentInAtlas.FlexSpec) { - _, err := deploymentService.UpdateDeployment(ctx.Context, deploymentInAKO) + if !reflect.DeepEqual(akoFlex.FlexSpec, atlasFlex.FlexSpec) { + _, err := deploymentService.UpdateDeployment(ctx.Context, akoFlex) if err != nil { return r.terminate(ctx, workflow.DeploymentNotUpdatedInAtlas, err) } - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") + return r.inProgress(ctx, akoFlex.GetCustomResource(), atlasFlex, workflow.DeploymentUpdating, "deployment is updating") } - err := r.ensureConnectionSecrets(ctx, projectService, deploymentInAKO, deploymentInAtlas.GetConnection()) + err := r.ensureConnectionSecrets(ctx, projectService, akoFlex, atlasFlex.GetConnection()) if err != nil { return r.terminate(ctx, workflow.DeploymentConnectionSecretsNotCreated, err) } - err = customresource.ApplyLastConfigApplied(ctx.Context, deploymentInAKO.GetCustomResource(), r.Client) + err = customresource.ApplyLastConfigApplied(ctx.Context, akoFlex.GetCustomResource(), r.Client) if err != nil { return r.terminate(ctx, workflow.Internal, err) } - return r.ready(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas) + return r.ready(ctx, akoFlex.GetCustomResource(), atlasFlex) case status.StateCREATING: - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentCreating, "deployment is provisioning") + return r.inProgress(ctx, akoFlex.GetCustomResource(), atlasFlex, workflow.DeploymentCreating, "deployment is provisioning") case status.StateUPDATING, status.StateREPAIRING: - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") + return r.inProgress(ctx, akoFlex.GetCustomResource(), atlasFlex, workflow.DeploymentUpdating, "deployment is updating") case status.StateDELETING, status.StateDELETED: - return r.deleted() + return r.handleDeleted() default: - return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", deploymentInAtlas.GetState())) + return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", atlasFlex.GetState())) } } diff --git a/internal/controller/atlasdeployment/serverless_deployment.go b/internal/controller/atlasdeployment/serverless_deployment.go index 3d87458c08..24d95831bb 100644 --- a/internal/controller/atlasdeployment/serverless_deployment.go +++ b/internal/controller/atlasdeployment/serverless_deployment.go @@ -14,55 +14,61 @@ import ( "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/project" ) -func (r *AtlasDeploymentReconciler) handleServerlessInstance(ctx *workflow.Context, projectService project.ProjectService, deploymentService deployment.AtlasDeploymentsService, deploymentInAKO, deploymentInAtlas *deployment.Serverless) (ctrl.Result, error) { - if deploymentInAtlas == nil { - ctx.Log.Infof("Serverless Instance %s doesn't exist in Atlas - creating", deploymentInAKO.GetName()) - newServerlessDeployment, err := deploymentService.CreateDeployment(ctx.Context, deploymentInAKO) +func (r *AtlasDeploymentReconciler) handleServerlessInstance(ctx *workflow.Context, projectService project.ProjectService, deploymentService deployment.AtlasDeploymentsService, akoDeployment, atlasDeployment deployment.Deployment) (ctrl.Result, error) { + akoServerless, ok := akoDeployment.(*deployment.Serverless) + if !ok { + return r.terminate(ctx, workflow.Internal, errors.New("deployment in AKO is not a serverless cluster")) + } + atlasServerless, _ := atlasDeployment.(*deployment.Serverless) + + if atlasServerless == nil { + ctx.Log.Infof("Serverless Instance %s doesn't exist in Atlas - creating", akoServerless.GetName()) + newServerlessDeployment, err := deploymentService.CreateDeployment(ctx.Context, akoServerless) if err != nil { return r.terminate(ctx, workflow.DeploymentNotCreatedInAtlas, err) } - deploymentInAtlas = newServerlessDeployment.(*deployment.Serverless) + atlasServerless = newServerlessDeployment.(*deployment.Serverless) } - switch deploymentInAtlas.GetState() { + switch atlasServerless.GetState() { case status.StateIDLE: - if !reflect.DeepEqual(deploymentInAKO.ServerlessSpec, deploymentInAtlas.ServerlessSpec) { - _, err := deploymentService.UpdateDeployment(ctx.Context, deploymentInAKO) + if !reflect.DeepEqual(akoServerless.ServerlessSpec, atlasServerless.ServerlessSpec) { + _, err := deploymentService.UpdateDeployment(ctx.Context, akoServerless) if err != nil { return r.terminate(ctx, workflow.DeploymentNotUpdatedInAtlas, err) } - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") + return r.inProgress(ctx, akoServerless.GetCustomResource(), atlasServerless, workflow.DeploymentUpdating, "deployment is updating") } - err := r.ensureConnectionSecrets(ctx, projectService, deploymentInAKO, deploymentInAtlas.GetConnection()) + err := r.ensureConnectionSecrets(ctx, projectService, akoServerless, atlasServerless.GetConnection()) if err != nil { return r.terminate(ctx, workflow.DeploymentConnectionSecretsNotCreated, err) } // Note: Serverless Private endpoints keep theirs flows without translation layer (yet) - result := ensureServerlessPrivateEndpoints(ctx, deploymentInAKO.GetProjectID(), deploymentInAKO.GetCustomResource()) + result := ensureServerlessPrivateEndpoints(ctx, akoServerless.GetProjectID(), akoServerless.GetCustomResource()) switch { case result.IsInProgress(): - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.ServerlessPrivateEndpointInProgress, result.GetMessage()) + return r.inProgress(ctx, akoServerless.GetCustomResource(), atlasServerless, workflow.ServerlessPrivateEndpointInProgress, result.GetMessage()) case !result.IsOk(): return r.terminate(ctx, workflow.ServerlessPrivateEndpointFailed, errors.New(result.GetMessage())) } - err = customresource.ApplyLastConfigApplied(ctx.Context, deploymentInAKO.GetCustomResource(), r.Client) + err = customresource.ApplyLastConfigApplied(ctx.Context, akoServerless.GetCustomResource(), r.Client) if err != nil { return r.terminate(ctx, workflow.Internal, err) } - return r.ready(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas) + return r.ready(ctx, akoServerless.GetCustomResource(), atlasServerless) case status.StateCREATING: - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentCreating, "deployment is provisioning") + return r.inProgress(ctx, akoServerless.GetCustomResource(), atlasServerless, workflow.DeploymentCreating, "deployment is provisioning") case status.StateUPDATING, status.StateREPAIRING: - return r.inProgress(ctx, deploymentInAKO.GetCustomResource(), deploymentInAtlas, workflow.DeploymentUpdating, "deployment is updating") + return r.inProgress(ctx, akoServerless.GetCustomResource(), atlasServerless, workflow.DeploymentUpdating, "deployment is updating") default: - return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", deploymentInAtlas.GetState())) + return r.terminate(ctx, workflow.Internal, fmt.Errorf("unknown deployment state: %s", atlasServerless.GetState())) } } From fd3affaa46c8b1cea74d56597f5e6573e984b0e7 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 10:35:24 +0100 Subject: [PATCH 21/33] enable flex --- .github/workflows/test-e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index b6cc639bcc..d83fe20cea 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -182,6 +182,7 @@ jobs: "reconcile-one", "reconcile-two", "backup-compliance", + "flex", ] steps: - name: Get repo files from cache From 7e23be9b5f3f3ec084583575f989220fc3762412 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 12:29:24 +0100 Subject: [PATCH 22/33] use ako deployment type for retrieving clusters from Atlas --- .../atlasdeployment_controller.go | 6 +- internal/translation/deployment/deployment.go | 103 +++++++++++++++--- 2 files changed, 88 insertions(+), 21 deletions(-) diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller.go b/internal/controller/atlasdeployment/atlasdeployment_controller.go index 0d0dc5bf6c..7a0e96b966 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller.go @@ -164,7 +164,7 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ workflowCtx.SetConditionTrue(api.ValidationSucceeded) deploymentInAKO := deployment.NewDeployment(atlasProject.ID, atlasDeployment) - deploymentInAtlas, err := deploymentService.GetDeployment(workflowCtx.Context, atlasProject.ID, atlasDeployment.GetDeploymentName()) + deploymentInAtlas, err := deploymentService.GetDeployment(workflowCtx.Context, atlasProject.ID, atlasDeployment) if err != nil { return r.terminate(workflowCtx, workflow.Internal, err) } @@ -295,7 +295,7 @@ func (r *AtlasDeploymentReconciler) transitionFromLegacy(ctx *workflow.Context, return r.terminate(ctx, reason, err) } - deploymentInAtlas, err := deploymentService.GetDeployment(ctx.Context, projectID, atlasDeployment.GetDeploymentName()) + deploymentInAtlas, err := deploymentService.GetDeployment(ctx.Context, projectID, atlasDeployment) if err != nil { return r.terminate(ctx, workflow.Internal, err) } @@ -307,7 +307,7 @@ func (r *AtlasDeploymentReconciler) transitionFromLegacy(ctx *workflow.Context, func (r *AtlasDeploymentReconciler) transitionFromResult(ctx *workflow.Context, deploymentService deployment.AtlasDeploymentsService, projectID string, atlasDeployment *akov2.AtlasDeployment, result workflow.Result) transitionFn { if result.IsInProgress() { return func(reason workflow.ConditionReason) (ctrl.Result, error) { - deploymentInAtlas, err := deploymentService.GetDeployment(ctx.Context, projectID, atlasDeployment.GetDeploymentName()) + deploymentInAtlas, err := deploymentService.GetDeployment(ctx.Context, projectID, atlasDeployment) if err != nil { return r.terminate(ctx, workflow.Internal, err) } diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index 4e819e79c2..4f9fc6024d 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -28,7 +28,7 @@ type DeploymentService interface { ClusterExists(ctx context.Context, projectID, clusterName string) (bool, error) DeploymentIsReady(ctx context.Context, projectID, deploymentName string) (bool, error) - GetDeployment(ctx context.Context, projectID, name string) (Deployment, error) + GetDeployment(ctx context.Context, projectID string, deployment *akov2.AtlasDeployment) (Deployment, error) CreateDeployment(ctx context.Context, deployment Deployment) (Deployment, error) UpdateDeployment(ctx context.Context, deployment Deployment) (Deployment, error) DeleteDeployment(ctx context.Context, deployment Deployment) error @@ -120,13 +120,32 @@ func (ds *ProductionAtlasDeployments) ListDeploymentConnections(ctx context.Cont return connectionSet(clusterConns, serverlessConns), nil } -func (ds *ProductionAtlasDeployments) ClusterExists(ctx context.Context, projectID, clusterName string) (bool, error) { - d, err := ds.GetDeployment(ctx, projectID, clusterName) +func (ds *ProductionAtlasDeployments) ClusterExists(ctx context.Context, projectID, name string) (bool, error) { + flex, err := ds.GetFlexCluster(ctx, projectID, name) if err != nil { return false, err } + if flex != nil { + return true, nil + } + + cluster, err := ds.GetCluster(ctx, projectID, name) + if err != nil { + return false, err + } + if cluster != nil { + return true, nil + } - return d != nil, nil + serverless, err := ds.GetServerless(ctx, projectID, name) + if err != nil { + return false, err + } + if serverless != nil { + return true, nil + } + + return false, nil } func (ds *ProductionAtlasDeployments) DeploymentIsReady(ctx context.Context, projectID, deploymentName string) (bool, error) { @@ -138,24 +157,30 @@ func (ds *ProductionAtlasDeployments) DeploymentIsReady(ctx context.Context, pro return clusterStatus.GetChangeStatus() == string(mongodbatlas.ChangeStatusApplied), nil } -func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, projectID, name string) (Deployment, error) { - if !ds.isGov { - flex, _, err := ds.flexAPI.GetFlexCluster(ctx, projectID, name).Execute() - if err == nil { - return flexFromAtlas(flex), nil - } +func (ds *ProductionAtlasDeployments) GetFlexCluster(ctx context.Context, projectID, name string) (*Flex, error) { + if ds.isGov { + return nil, nil + } + + flex, _, err := ds.flexAPI.GetFlexCluster(ctx, projectID, name).Execute() + if err == nil { + return flexFromAtlas(flex), nil + } - if sdkerr, ok := adminv20241113001.AsError(err); ok { - switch sdkerr.GetErrorCode() { - case atlas.ClusterNotFound: - case atlas.NonFlexInFlexAPI: - case atlas.FeatureUnsupported: - default: - return nil, err - } + if sdkerr, ok := adminv20241113001.AsError(err); ok { + switch sdkerr.GetErrorCode() { + case atlas.ClusterNotFound: + case atlas.NonFlexInFlexAPI: + case atlas.FeatureUnsupported: + default: + return nil, err } } + return nil, nil +} + +func (ds *ProductionAtlasDeployments) GetCluster(ctx context.Context, projectID, name string) (*Cluster, error) { cluster, _, err := ds.clustersAPI.GetCluster(ctx, projectID, name).Execute() if err == nil { return clusterFromAtlas(cluster), nil @@ -165,6 +190,10 @@ func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, project return nil, err } + return nil, nil +} + +func (ds *ProductionAtlasDeployments) GetServerless(ctx context.Context, projectID, name string) (*Serverless, error) { if ds.isGov { return nil, nil } @@ -181,6 +210,44 @@ func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, project return nil, nil } +func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, projectID string, deployment *akov2.AtlasDeployment) (Deployment, error) { + if deployment == nil { + return nil, errors.New("deployment is nil") + } + + switch { + case deployment.IsFlex(): + flex, err := ds.GetFlexCluster(ctx, projectID, deployment.Name) + if err != nil { + return nil, err + } + if flex != nil { + return flex, err + } + + case deployment.IsServerless(): + serverless, err := ds.GetServerless(ctx, projectID, deployment.Name) + if err != nil { + return nil, err + } + if serverless != nil { + return serverless, err + } + + case deployment.IsAdvancedDeployment(): + cluster, err := ds.GetCluster(ctx, projectID, deployment.Name) + if err != nil { + return nil, err + } + if cluster != nil { + return cluster, err + } + } + + // not found + return nil, nil +} + func (ds *ProductionAtlasDeployments) CreateDeployment(ctx context.Context, deployment Deployment) (Deployment, error) { switch d := deployment.(type) { case *Cluster: From 395aade65f13549cb2e1f13b53314e151adcd1f3 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 12:29:42 +0100 Subject: [PATCH 23/33] fix unit tests --- .../translation/deployment/deployment_test.go | 487 ++++++++---------- test/int/deployment_test.go | 6 +- 2 files changed, 215 insertions(+), 278 deletions(-) diff --git a/internal/translation/deployment/deployment_test.go b/internal/translation/deployment/deployment_test.go index 0de71275ee..9a5a81e669 100644 --- a/internal/translation/deployment/deployment_test.go +++ b/internal/translation/deployment/deployment_test.go @@ -15,6 +15,7 @@ import ( "go.mongodb.org/atlas-sdk/v20231115008/mockadmin" adminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/admin" mockadminv20241113001 "go.mongodb.org/atlas-sdk/v20241113001/mockadmin" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/common" @@ -69,7 +70,7 @@ func TestProductionAtlasDeployments_ListDeploymentConnections(t *testing.T) { func TestClusterExists(t *testing.T) { tests := map[string]struct { - deployment Deployment + deployment *akov2.AtlasDeployment apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) gov bool result bool @@ -265,7 +266,7 @@ func TestClusterExists(t *testing.T) { clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, tt.gov) - result, err := service.ClusterExists(context.Background(), tt.deployment.GetProjectID(), tt.deployment.GetName()) + result, err := service.ClusterExists(context.Background(), "project-id", tt.deployment.GetName()) require.Equal(t, tt.err, err) assert.Equal(t, tt.result, result) }) @@ -274,7 +275,7 @@ func TestClusterExists(t *testing.T) { func TestGetDeployment(t *testing.T) { tests := map[string]struct { - deployment Deployment + deployment *akov2.AtlasDeployment apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error @@ -289,16 +290,7 @@ func TestGetDeployment(t *testing.T) { Return(nil, nil, errors.New("failed to get cluster from atlas")) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) - - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, err) - return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to get cluster from atlas"), @@ -307,10 +299,6 @@ func TestGetDeployment(t *testing.T) { deployment: serverlessInstance(), apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) - clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). - Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) - clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.ClusterNotFound)) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) serverlessInstanceAPI.EXPECT().GetServerlessInstance(context.Background(), "project-id", "instance0"). @@ -318,15 +306,7 @@ func TestGetDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, errors.New("failed to get serverless instance from atlas")) - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, err) - return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to get serverless instance from atlas"), @@ -341,20 +321,7 @@ func TestGetDeployment(t *testing.T) { Return(nil, nil, atlasAPIError(atlas.ClusterNotFound)) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) - serverlessInstanceAPI.EXPECT().GetServerlessInstance(context.Background(), "project-id", "cluster0"). - Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI}) - serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). - Return(nil, nil, atlasAPIError(atlas.ProviderUnsupported)) - - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, err) - return clusterAPI, serverlessInstanceAPI, flexAPI }, }, @@ -362,10 +329,6 @@ func TestGetDeployment(t *testing.T) { deployment: serverlessInstance(), apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) - clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). - Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) - clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceFromClusterAPI)) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) serverlessInstanceAPI.EXPECT().GetServerlessInstance(context.Background(), "project-id", "instance0"). @@ -373,15 +336,7 @@ func TestGetDeployment(t *testing.T) { serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceNotFound)) - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, err) - return clusterAPI, serverlessInstanceAPI, flexAPI }, }, @@ -399,16 +354,7 @@ func TestGetDeployment(t *testing.T) { ) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) - - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, err) - return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedGeoShardedCluster(), @@ -417,10 +363,6 @@ func TestGetDeployment(t *testing.T) { deployment: serverlessInstance(), apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { clusterAPI := mockadmin.NewClustersApi(t) - clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0"). - Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) - clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). - Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceFromClusterAPI)) serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) serverlessInstanceAPI.EXPECT().GetServerlessInstance(context.Background(), "project-id", "instance0"). @@ -432,15 +374,7 @@ func TestGetDeployment(t *testing.T) { nil, ) - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0"). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, err) - return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedServerlessInstance(), @@ -452,7 +386,7 @@ func TestGetDeployment(t *testing.T) { clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) - result, err := service.GetDeployment(context.Background(), tt.deployment.GetProjectID(), tt.deployment.GetName()) + result, err := service.GetDeployment(context.Background(), "project-id", tt.deployment) require.Equal(t, tt.err, err) assert.Equal(t, tt.result, result) }) @@ -461,7 +395,7 @@ func TestGetDeployment(t *testing.T) { func TestCreateDeployment(t *testing.T) { tests := map[string]struct { - deployment Deployment + deployment *akov2.AtlasDeployment apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error @@ -477,7 +411,6 @@ func TestCreateDeployment(t *testing.T) { serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to create cluster in atlas"), @@ -494,7 +427,6 @@ func TestCreateDeployment(t *testing.T) { Return(nil, nil, errors.New("failed to create serverless instance in atlas")) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to create serverless instance in atlas"), @@ -535,7 +467,6 @@ func TestCreateDeployment(t *testing.T) { ) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedServerlessInstance(), @@ -547,7 +478,7 @@ func TestCreateDeployment(t *testing.T) { clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) - result, err := service.CreateDeployment(context.Background(), tt.deployment) + result, err := service.CreateDeployment(context.Background(), NewDeployment("project-id", tt.deployment)) require.Equal(t, tt.err, err) assert.Equal(t, tt.result, result) }) @@ -556,7 +487,7 @@ func TestCreateDeployment(t *testing.T) { func TestUpdateDeployment(t *testing.T) { tests := map[string]struct { - deployment Deployment + deployment *akov2.AtlasDeployment apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error @@ -572,7 +503,6 @@ func TestUpdateDeployment(t *testing.T) { serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to update cluster in atlas"), @@ -589,7 +519,6 @@ func TestUpdateDeployment(t *testing.T) { Return(nil, nil, errors.New("failed to update serverless instance in atlas")) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to update serverless instance in atlas"), @@ -609,7 +538,6 @@ func TestUpdateDeployment(t *testing.T) { serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return clusterAPI, serverlessInstanceAPI, flexAPI }, result: expectedGeoShardedCluster(), @@ -642,7 +570,7 @@ func TestUpdateDeployment(t *testing.T) { clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) - result, err := service.UpdateDeployment(context.Background(), tt.deployment) + result, err := service.UpdateDeployment(context.Background(), NewDeployment("project-id", tt.deployment)) require.Equal(t, tt.err, err) assert.Equal(t, tt.result, result) }) @@ -651,7 +579,7 @@ func TestUpdateDeployment(t *testing.T) { func TestDeleteDeployment(t *testing.T) { tests := map[string]struct { - deployment Deployment + deployment *akov2.AtlasDeployment apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error @@ -729,7 +657,7 @@ func TestDeleteDeployment(t *testing.T) { clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) - err := service.DeleteDeployment(context.Background(), tt.deployment) + err := service.DeleteDeployment(context.Background(), NewDeployment("project-id", tt.deployment)) require.Equal(t, tt.err, err) }) } @@ -737,7 +665,7 @@ func TestDeleteDeployment(t *testing.T) { func TestClusterWithProcessArgs(t *testing.T) { tests := map[string]struct { - deployment Deployment + deployment *akov2.AtlasDeployment apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) result Deployment err error @@ -839,11 +767,12 @@ func TestClusterWithProcessArgs(t *testing.T) { clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false) - cluster := tt.deployment.(*Cluster) + d := NewDeployment("project-id", tt.deployment) + cluster := d.(*Cluster) err := service.ClusterWithProcessArgs(context.Background(), cluster) require.Equal(t, tt.err, err) - expectedCluster := tt.deployment.(*Cluster) + expectedCluster := d.(*Cluster) assert.Equal(t, expectedCluster.ProcessArgs, cluster.ProcessArgs) }) } @@ -987,190 +916,194 @@ func atlasAPIError(code string) *admin.GenericOpenAPIError { return &err } -func geoShardedCluster() *Cluster { - return &Cluster{ - ProjectID: "project-id", - AdvancedDeploymentSpec: &akov2.AdvancedDeploymentSpec{ - Name: "cluster0", - ClusterType: "GEOSHARDED", - DiskSizeGB: pointer.MakePtr(40), - BackupEnabled: pointer.MakePtr(true), - PitEnabled: pointer.MakePtr(true), - Paused: pointer.MakePtr(false), - TerminationProtectionEnabled: true, - EncryptionAtRestProvider: "AWS", - RootCertType: "ISRGROOTX1", - MongoDBMajorVersion: "7.0", - VersionReleaseSystem: "LTS", - BiConnector: &akov2.BiConnectorSpec{ - Enabled: pointer.MakePtr(true), - ReadPreference: "secondary", - }, - Labels: []common.LabelSpec{ - { - Key: "B", - Value: "B", - }, - { - Key: "A", - Value: "A", +func geoShardedCluster() *akov2.AtlasDeployment { + return &akov2.AtlasDeployment{ + ObjectMeta: v1.ObjectMeta{ + Name: "cluster0", + }, + Spec: akov2.AtlasDeploymentSpec{ + DeploymentSpec: &akov2.AdvancedDeploymentSpec{ + Name: "cluster0", + ClusterType: "GEOSHARDED", + DiskSizeGB: pointer.MakePtr(40), + BackupEnabled: pointer.MakePtr(true), + PitEnabled: pointer.MakePtr(true), + Paused: pointer.MakePtr(false), + TerminationProtectionEnabled: true, + EncryptionAtRestProvider: "AWS", + RootCertType: "ISRGROOTX1", + MongoDBMajorVersion: "7.0", + VersionReleaseSystem: "LTS", + BiConnector: &akov2.BiConnectorSpec{ + Enabled: pointer.MakePtr(true), + ReadPreference: "secondary", }, - }, - Tags: []*akov2.TagSpec{ - { - Key: "B", - Value: "B", + Labels: []common.LabelSpec{ + { + Key: "B", + Value: "B", + }, + { + Key: "A", + Value: "A", + }, }, - { - Key: "A", - Value: "A", + Tags: []*akov2.TagSpec{ + { + Key: "B", + Value: "B", + }, + { + Key: "A", + Value: "A", + }, }, - }, - MongoDBVersion: "7.3.3", - ReplicationSpecs: []*akov2.AdvancedReplicationSpec{ - { - ZoneName: "Zone 1", - NumShards: 1, - RegionConfigs: []*akov2.AdvancedRegionConfig{ - { - ProviderName: "AWS", - RegionName: "EU_WEST_1", - Priority: pointer.MakePtr(5), - ElectableSpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(3), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - ReadOnlySpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(3), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - AnalyticsSpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(1), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - AutoScaling: &akov2.AdvancedAutoScalingSpec{ - DiskGB: &akov2.DiskGB{ - Enabled: pointer.MakePtr(true), + MongoDBVersion: "7.3.3", + ReplicationSpecs: []*akov2.AdvancedReplicationSpec{ + { + ZoneName: "Zone 1", + NumShards: 1, + RegionConfigs: []*akov2.AdvancedRegionConfig{ + { + ProviderName: "AWS", + RegionName: "EU_WEST_1", + Priority: pointer.MakePtr(5), + ElectableSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(3), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), }, - Compute: &akov2.ComputeSpec{ - Enabled: pointer.MakePtr(true), - ScaleDownEnabled: pointer.MakePtr(true), - MinInstanceSize: "M30", - MaxInstanceSize: "M60", + ReadOnlySpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(3), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), + }, + AnalyticsSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(1), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), + }, + AutoScaling: &akov2.AdvancedAutoScalingSpec{ + DiskGB: &akov2.DiskGB{ + Enabled: pointer.MakePtr(true), + }, + Compute: &akov2.ComputeSpec{ + Enabled: pointer.MakePtr(true), + ScaleDownEnabled: pointer.MakePtr(true), + MinInstanceSize: "M30", + MaxInstanceSize: "M60", + }, }, }, - }, - { - ProviderName: "AWS", - RegionName: "US_EAST_1", - Priority: pointer.MakePtr(7), - ElectableSpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(3), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - ReadOnlySpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(3), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - AnalyticsSpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(1), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - AutoScaling: &akov2.AdvancedAutoScalingSpec{ - DiskGB: &akov2.DiskGB{ - Enabled: pointer.MakePtr(true), + { + ProviderName: "AWS", + RegionName: "US_EAST_1", + Priority: pointer.MakePtr(7), + ElectableSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(3), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), }, - Compute: &akov2.ComputeSpec{ - Enabled: pointer.MakePtr(true), - ScaleDownEnabled: pointer.MakePtr(true), - MinInstanceSize: "M30", - MaxInstanceSize: "M60", + ReadOnlySpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(3), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), + }, + AnalyticsSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(1), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), + }, + AutoScaling: &akov2.AdvancedAutoScalingSpec{ + DiskGB: &akov2.DiskGB{ + Enabled: pointer.MakePtr(true), + }, + Compute: &akov2.ComputeSpec{ + Enabled: pointer.MakePtr(true), + ScaleDownEnabled: pointer.MakePtr(true), + MinInstanceSize: "M30", + MaxInstanceSize: "M60", + }, }, }, }, }, - }, - { - ZoneName: "Zone 2", - NumShards: 1, - RegionConfigs: []*akov2.AdvancedRegionConfig{ - { - ProviderName: "AWS", - RegionName: "EU_CENTRAL_1", - Priority: pointer.MakePtr(6), - ElectableSpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(2), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - ReadOnlySpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(3), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - AnalyticsSpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(1), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - AutoScaling: &akov2.AdvancedAutoScalingSpec{ - DiskGB: &akov2.DiskGB{ - Enabled: pointer.MakePtr(true), + { + ZoneName: "Zone 2", + NumShards: 1, + RegionConfigs: []*akov2.AdvancedRegionConfig{ + { + ProviderName: "AWS", + RegionName: "EU_CENTRAL_1", + Priority: pointer.MakePtr(6), + ElectableSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(2), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), }, - Compute: &akov2.ComputeSpec{ - Enabled: pointer.MakePtr(true), - ScaleDownEnabled: pointer.MakePtr(true), - MinInstanceSize: "M30", - MaxInstanceSize: "M60", + ReadOnlySpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(3), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), + }, + AnalyticsSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(1), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), + }, + AutoScaling: &akov2.AdvancedAutoScalingSpec{ + DiskGB: &akov2.DiskGB{ + Enabled: pointer.MakePtr(true), + }, + Compute: &akov2.ComputeSpec{ + Enabled: pointer.MakePtr(true), + ScaleDownEnabled: pointer.MakePtr(true), + MinInstanceSize: "M30", + MaxInstanceSize: "M60", + }, }, }, - }, - { - ProviderName: "AWS", - RegionName: "EU_WEST_1", - Priority: pointer.MakePtr(4), - ElectableSpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(3), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - ReadOnlySpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(3), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - AnalyticsSpecs: &akov2.Specs{ - InstanceSize: "M30", - NodeCount: pointer.MakePtr(1), - EbsVolumeType: "STANDARD", - DiskIOPS: pointer.MakePtr(int64(3000)), - }, - AutoScaling: &akov2.AdvancedAutoScalingSpec{ - DiskGB: &akov2.DiskGB{ - Enabled: pointer.MakePtr(true), + { + ProviderName: "AWS", + RegionName: "EU_WEST_1", + Priority: pointer.MakePtr(4), + ElectableSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(3), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), }, - Compute: &akov2.ComputeSpec{ - Enabled: pointer.MakePtr(true), - ScaleDownEnabled: pointer.MakePtr(true), - MinInstanceSize: "M30", - MaxInstanceSize: "M60", + ReadOnlySpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(3), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), + }, + AnalyticsSpecs: &akov2.Specs{ + InstanceSize: "M30", + NodeCount: pointer.MakePtr(1), + EbsVolumeType: "STANDARD", + DiskIOPS: pointer.MakePtr(int64(3000)), + }, + AutoScaling: &akov2.AdvancedAutoScalingSpec{ + DiskGB: &akov2.DiskGB{ + Enabled: pointer.MakePtr(true), + }, + Compute: &akov2.ComputeSpec{ + Enabled: pointer.MakePtr(true), + ScaleDownEnabled: pointer.MakePtr(true), + MinInstanceSize: "M30", + MaxInstanceSize: "M60", + }, }, }, }, @@ -1626,28 +1559,32 @@ func atlasGeoShardedCluster() *admin.AdvancedClusterDescription { } } -func serverlessInstance() *Serverless { - return &Serverless{ - ProjectID: "project-id", - ServerlessSpec: &akov2.ServerlessSpec{ +func serverlessInstance() *akov2.AtlasDeployment { + return &akov2.AtlasDeployment{ + ObjectMeta: v1.ObjectMeta{ Name: "instance0", - ProviderSettings: &akov2.ServerlessProviderSettingsSpec{ - ProviderName: "SERVERLESS", - BackingProviderName: "AWS", - RegionName: "US_EAST_1", - }, - BackupOptions: akov2.ServerlessBackupOptions{ - ServerlessContinuousBackupEnabled: true, - }, - TerminationProtectionEnabled: true, - Tags: []*akov2.TagSpec{ - { - Key: "B", - Value: "B", + }, + Spec: akov2.AtlasDeploymentSpec{ + ServerlessSpec: &akov2.ServerlessSpec{ + Name: "instance0", + ProviderSettings: &akov2.ServerlessProviderSettingsSpec{ + ProviderName: "SERVERLESS", + BackingProviderName: "AWS", + RegionName: "US_EAST_1", }, - { - Key: "A", - Value: "A", + BackupOptions: akov2.ServerlessBackupOptions{ + ServerlessContinuousBackupEnabled: true, + }, + TerminationProtectionEnabled: true, + Tags: []*akov2.TagSpec{ + { + Key: "B", + Value: "B", + }, + { + Key: "A", + Value: "A", + }, }, }, }, diff --git a/test/int/deployment_test.go b/test/int/deployment_test.go index 1abb6a5f45..c45c6db701 100644 --- a/test/int/deployment_test.go +++ b/test/int/deployment_test.go @@ -183,10 +183,10 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- checkAdvancedAtlasState := func() { By("Verifying Advanced Deployment state in Atlas", func() { - deploymentInAKO := deployment.NewDeployment(createdProject.ID(), createdDeployment) - deploymentInAtlas, err := deploymentService.GetDeployment(context.Background(), createdProject.ID(), deploymentInAKO.GetName()) + deploymentInAtlas, err := deploymentService.GetDeployment(context.Background(), createdProject.ID(), createdDeployment) Expect(err).ToNot(HaveOccurred()) + deploymentInAKO := deployment.NewDeployment(createdProject.ID(), createdDeployment) _, hasChanges := deployment.ComputeChanges(deploymentInAKO.(*deployment.Cluster), deploymentInAtlas.(*deployment.Cluster)) Expect(hasChanges).ShouldNot(BeTrue()) }) @@ -195,7 +195,7 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- checkAdvancedDeploymentOptions := func(ctx context.Context, projectID string, atlasDeployment *akov2.AtlasDeployment) { By("Checking that Atlas Advanced Options are equal to the Spec Options", func() { deploymentInAKO := deployment.NewDeployment(projectID, atlasDeployment).(*deployment.Cluster) - deploymentInAtlas, err := deploymentService.GetDeployment(ctx, projectID, atlasDeployment.GetDeploymentName()) + deploymentInAtlas, err := deploymentService.GetDeployment(ctx, projectID, atlasDeployment) Expect(err).ToNot(HaveOccurred()) cluster := deploymentInAtlas.(*deployment.Cluster) From 64572eac8561bbebb541fb3cdcece2a6680e31bd Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 14:18:29 +0100 Subject: [PATCH 24/33] fix unit tests --- .../advanced_deployment_test.go | 6 +- .../atlasdeployment_controller_test.go | 56 +++++++------------ 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/internal/controller/atlasdeployment/advanced_deployment_test.go b/internal/controller/atlasdeployment/advanced_deployment_test.go index 424f41aa5a..d077fd970e 100644 --- a/internal/controller/atlasdeployment/advanced_deployment_test.go +++ b/internal/controller/atlasdeployment/advanced_deployment_test.go @@ -654,7 +654,7 @@ func TestHandleAdvancedDeployment(t *testing.T) { }, deploymentService: func() deployment.AtlasDeploymentsService { service := translation.NewAtlasDeploymentsServiceMock(t) - service.EXPECT().ClusterWithProcessArgs(context.Background(), mock.AnythingOfType("*deployment.Cluster")). + service.EXPECT().ClusterWithProcessArgs(context.Background(), mock.Anything). RunAndReturn(func(_ context.Context, cluster *deployment.Cluster) error { cluster.ProcessArgs = &akov2.ProcessArgs{ JavascriptEnabled: pointer.MakePtr(true), @@ -664,7 +664,7 @@ func TestHandleAdvancedDeployment(t *testing.T) { } return nil }) - service.EXPECT().UpdateProcessArgs(context.Background(), mock.AnythingOfType("*deployment.Cluster")). + service.EXPECT().UpdateProcessArgs(context.Background(), mock.Anything). RunAndReturn(func(_ context.Context, cluster *deployment.Cluster) error { cluster.ProcessArgs = &akov2.ProcessArgs{ JavascriptEnabled: pointer.MakePtr(true), @@ -673,7 +673,7 @@ func TestHandleAdvancedDeployment(t *testing.T) { } return nil }) - service.EXPECT().GetDeployment(context.Background(), "project-id", "cluster0"). + service.EXPECT().GetDeployment(context.Background(), mock.Anything, mock.Anything). Return( &deployment.Cluster{ ProjectID: "project-id", diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go index 3ff896fbf2..c3768e671a 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go @@ -402,15 +402,11 @@ func TestRegularClusterReconciliation(t *testing.T) { err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(mock.Anything, project.ID(), d.GetDeploymentName()). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, &http.Response{}, err) return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil }, SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { clusterAPI := mockadmin.NewClustersApi(t) - clusterAPI.EXPECT().GetCluster(mock.Anything, project.ID(), d.GetDeploymentName()). + clusterAPI.EXPECT().GetCluster(mock.Anything, project.ID(), mock.Anything). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). Return( @@ -633,23 +629,15 @@ func TestServerlessInstanceReconciliation(t *testing.T) { err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(mock.Anything, project.ID(), d.GetDeploymentName()). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, &http.Response{}, err) return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil }, SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { err := &admin.GenericOpenAPIError{} err.SetModel(admin.ApiError{ErrorCode: pointer.MakePtr(atlas.ServerlessInstanceFromClusterAPI)}) clusterAPI := mockadmin.NewClustersApi(t) - clusterAPI.EXPECT().GetCluster(mock.Anything, project.ID(), d.GetDeploymentName()). - Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) - clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). - Return(nil, nil, err) serverlessAPI := mockadmin.NewServerlessInstancesApi(t) - serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, project.ID(), d.GetDeploymentName()). + serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, project.ID(), mock.Anything). Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI}) serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). Return( @@ -815,15 +803,11 @@ func TestDeletionReconciliation(t *testing.T) { err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(mock.Anything, project.ID(), d.GetDeploymentName()). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, &http.Response{}, err) return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil }, SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { clusterAPI := mockadmin.NewClustersApi(t) - clusterAPI.EXPECT().GetCluster(mock.Anything, project.ID(), d.GetDeploymentName()). + clusterAPI.EXPECT().GetCluster(mock.Anything, project.ID(), mock.Anything). Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). Return( @@ -1266,10 +1250,6 @@ func TestChangeDeploymentType(t *testing.T) { err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - flexAPI.EXPECT().GetFlexCluster(mock.Anything, "abc123", "cluster0"). - Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) - flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, &http.Response{}, err) return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil }, ClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*mongodbatlas.Client, string, error) { @@ -1277,22 +1257,24 @@ func TestChangeDeploymentType(t *testing.T) { }, SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { clusterAPI := mockadmin.NewClustersApi(t) - clusterAPI.EXPECT().GetCluster(mock.Anything, "abc123", "cluster0"). - Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) - clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). - RunAndReturn( - func(request admin.GetClusterApiRequest) (*admin.AdvancedClusterDescription, *http.Response, error) { - if !tt.deployment.IsServerless() { - err := &admin.GenericOpenAPIError{} - err.SetModel(admin.ApiError{ErrorCode: pointer.MakePtr(atlas.ServerlessInstanceFromClusterAPI)}) - return nil, nil, err - } - return &admin.AdvancedClusterDescription{Name: pointer.MakePtr("cluster0")}, nil, nil - }, - ) + if tt.deployment.IsAdvancedDeployment() { + clusterAPI.EXPECT().GetCluster(mock.Anything, "abc123", "cluster0"). + Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) + clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). + RunAndReturn( + func(request admin.GetClusterApiRequest) (*admin.AdvancedClusterDescription, *http.Response, error) { + if !tt.deployment.IsServerless() { + err := &admin.GenericOpenAPIError{} + err.SetModel(admin.ApiError{ErrorCode: pointer.MakePtr(atlas.ServerlessInstanceFromClusterAPI)}) + return nil, nil, err + } + return &admin.AdvancedClusterDescription{Name: pointer.MakePtr("cluster0")}, nil, nil + }, + ) + } serverlessAPI := mockadmin.NewServerlessInstancesApi(t) - if !tt.deployment.IsServerless() { + if tt.deployment.IsServerless() { serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "abc123", "cluster0"). Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI}) serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). From 32c5ba682c655f7c62acc9bf2ceb0c5b29fbe865 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 14:18:49 +0100 Subject: [PATCH 25/33] regenerate mocks --- .../translation/atlas_deployments_service.go | 30 +- internal/mocks/translation/deployment.go | 20 +- .../mocks/translation/deployment_service.go | 32 +- .../mocks/translation/endpoint_interface.go | 6 +- .../mocks/translation/endpoint_service.go | 12 +- .../mocks/translation/project_referrer.go | 83 + .../translation/project_referrer_object.go | 1369 +++++++++++++++++ 7 files changed, 1503 insertions(+), 49 deletions(-) create mode 100644 internal/mocks/translation/project_referrer.go create mode 100644 internal/mocks/translation/project_referrer_object.go diff --git a/internal/mocks/translation/atlas_deployments_service.go b/internal/mocks/translation/atlas_deployments_service.go index c7a93365c8..b79f3bc8d6 100644 --- a/internal/mocks/translation/atlas_deployments_service.go +++ b/internal/mocks/translation/atlas_deployments_service.go @@ -560,9 +560,9 @@ func (_c *AtlasDeploymentsServiceMock_GetCustomZones_Call) RunAndReturn(run func return _c } -// GetDeployment provides a mock function with given fields: ctx, projectID, name -func (_m *AtlasDeploymentsServiceMock) GetDeployment(ctx context.Context, projectID string, name string) (deployment.Deployment, error) { - ret := _m.Called(ctx, projectID, name) +// GetDeployment provides a mock function with given fields: ctx, projectID, _a2 +func (_m *AtlasDeploymentsServiceMock) GetDeployment(ctx context.Context, projectID string, _a2 *v1.AtlasDeployment) (deployment.Deployment, error) { + ret := _m.Called(ctx, projectID, _a2) if len(ret) == 0 { panic("no return value specified for GetDeployment") @@ -570,19 +570,19 @@ func (_m *AtlasDeploymentsServiceMock) GetDeployment(ctx context.Context, projec var r0 deployment.Deployment var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (deployment.Deployment, error)); ok { - return rf(ctx, projectID, name) + if rf, ok := ret.Get(0).(func(context.Context, string, *v1.AtlasDeployment) (deployment.Deployment, error)); ok { + return rf(ctx, projectID, _a2) } - if rf, ok := ret.Get(0).(func(context.Context, string, string) deployment.Deployment); ok { - r0 = rf(ctx, projectID, name) + if rf, ok := ret.Get(0).(func(context.Context, string, *v1.AtlasDeployment) deployment.Deployment); ok { + r0 = rf(ctx, projectID, _a2) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(deployment.Deployment) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, projectID, name) + if rf, ok := ret.Get(1).(func(context.Context, string, *v1.AtlasDeployment) error); ok { + r1 = rf(ctx, projectID, _a2) } else { r1 = ret.Error(1) } @@ -598,14 +598,14 @@ type AtlasDeploymentsServiceMock_GetDeployment_Call struct { // GetDeployment is a helper method to define mock.On call // - ctx context.Context // - projectID string -// - name string -func (_e *AtlasDeploymentsServiceMock_Expecter) GetDeployment(ctx interface{}, projectID interface{}, name interface{}) *AtlasDeploymentsServiceMock_GetDeployment_Call { - return &AtlasDeploymentsServiceMock_GetDeployment_Call{Call: _e.mock.On("GetDeployment", ctx, projectID, name)} +// - _a2 *v1.AtlasDeployment +func (_e *AtlasDeploymentsServiceMock_Expecter) GetDeployment(ctx interface{}, projectID interface{}, _a2 interface{}) *AtlasDeploymentsServiceMock_GetDeployment_Call { + return &AtlasDeploymentsServiceMock_GetDeployment_Call{Call: _e.mock.On("GetDeployment", ctx, projectID, _a2)} } -func (_c *AtlasDeploymentsServiceMock_GetDeployment_Call) Run(run func(ctx context.Context, projectID string, name string)) *AtlasDeploymentsServiceMock_GetDeployment_Call { +func (_c *AtlasDeploymentsServiceMock_GetDeployment_Call) Run(run func(ctx context.Context, projectID string, _a2 *v1.AtlasDeployment)) *AtlasDeploymentsServiceMock_GetDeployment_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) + run(args[0].(context.Context), args[1].(string), args[2].(*v1.AtlasDeployment)) }) return _c } @@ -615,7 +615,7 @@ func (_c *AtlasDeploymentsServiceMock_GetDeployment_Call) Return(_a0 deployment. return _c } -func (_c *AtlasDeploymentsServiceMock_GetDeployment_Call) RunAndReturn(run func(context.Context, string, string) (deployment.Deployment, error)) *AtlasDeploymentsServiceMock_GetDeployment_Call { +func (_c *AtlasDeploymentsServiceMock_GetDeployment_Call) RunAndReturn(run func(context.Context, string, *v1.AtlasDeployment) (deployment.Deployment, error)) *AtlasDeploymentsServiceMock_GetDeployment_Call { _c.Call.Return(run) return _c } diff --git a/internal/mocks/translation/deployment.go b/internal/mocks/translation/deployment.go index 0bcf111014..9647094a8f 100644 --- a/internal/mocks/translation/deployment.go +++ b/internal/mocks/translation/deployment.go @@ -6,7 +6,7 @@ import ( mock "github.com/stretchr/testify/mock" v1 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/status" + status "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/status" ) // DeploymentMock is an autogenerated mock type for the Deployment type @@ -22,7 +22,7 @@ func (_m *DeploymentMock) EXPECT() *DeploymentMock_Expecter { return &DeploymentMock_Expecter{mock: &_m.Mock} } -// GetConnection provides a mock function with given fields: +// GetConnection provides a mock function with no fields func (_m *DeploymentMock) GetConnection() *status.ConnectionStrings { ret := _m.Called() @@ -69,7 +69,7 @@ func (_c *DeploymentMock_GetConnection_Call) RunAndReturn(run func() *status.Con return _c } -// GetCustomResource provides a mock function with given fields: +// GetCustomResource provides a mock function with no fields func (_m *DeploymentMock) GetCustomResource() *v1.AtlasDeployment { ret := _m.Called() @@ -116,7 +116,7 @@ func (_c *DeploymentMock_GetCustomResource_Call) RunAndReturn(run func() *v1.Atl return _c } -// GetMongoDBVersion provides a mock function with given fields: +// GetMongoDBVersion provides a mock function with no fields func (_m *DeploymentMock) GetMongoDBVersion() string { ret := _m.Called() @@ -161,7 +161,7 @@ func (_c *DeploymentMock_GetMongoDBVersion_Call) RunAndReturn(run func() string) return _c } -// GetName provides a mock function with given fields: +// GetName provides a mock function with no fields func (_m *DeploymentMock) GetName() string { ret := _m.Called() @@ -206,7 +206,7 @@ func (_c *DeploymentMock_GetName_Call) RunAndReturn(run func() string) *Deployme return _c } -// GetProjectID provides a mock function with given fields: +// GetProjectID provides a mock function with no fields func (_m *DeploymentMock) GetProjectID() string { ret := _m.Called() @@ -251,7 +251,7 @@ func (_c *DeploymentMock_GetProjectID_Call) RunAndReturn(run func() string) *Dep return _c } -// GetReplicaSet provides a mock function with given fields: +// GetReplicaSet provides a mock function with no fields func (_m *DeploymentMock) GetReplicaSet() []status.ReplicaSet { ret := _m.Called() @@ -298,7 +298,7 @@ func (_c *DeploymentMock_GetReplicaSet_Call) RunAndReturn(run func() []status.Re return _c } -// GetState provides a mock function with given fields: +// GetState provides a mock function with no fields func (_m *DeploymentMock) GetState() string { ret := _m.Called() @@ -343,7 +343,7 @@ func (_c *DeploymentMock_GetState_Call) RunAndReturn(run func() string) *Deploym return _c } -// IsFlex provides a mock function with given fields: +// IsFlex provides a mock function with no fields func (_m *DeploymentMock) IsFlex() bool { ret := _m.Called() @@ -388,7 +388,7 @@ func (_c *DeploymentMock_IsFlex_Call) RunAndReturn(run func() bool) *DeploymentM return _c } -// IsServerless provides a mock function with given fields: +// IsServerless provides a mock function with no fields func (_m *DeploymentMock) IsServerless() bool { ret := _m.Called() diff --git a/internal/mocks/translation/deployment_service.go b/internal/mocks/translation/deployment_service.go index 58aa572125..06756db53a 100644 --- a/internal/mocks/translation/deployment_service.go +++ b/internal/mocks/translation/deployment_service.go @@ -8,6 +8,8 @@ import ( mock "github.com/stretchr/testify/mock" deployment "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/deployment" + + v1 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" ) // DeploymentServiceMock is an autogenerated mock type for the DeploymentService type @@ -292,9 +294,9 @@ func (_c *DeploymentServiceMock_DeploymentIsReady_Call) RunAndReturn(run func(co return _c } -// GetDeployment provides a mock function with given fields: ctx, projectID, name -func (_m *DeploymentServiceMock) GetDeployment(ctx context.Context, projectID string, name string) (deployment.Deployment, error) { - ret := _m.Called(ctx, projectID, name) +// GetDeployment provides a mock function with given fields: ctx, projectID, _a2 +func (_m *DeploymentServiceMock) GetDeployment(ctx context.Context, projectID string, _a2 *v1.AtlasDeployment) (deployment.Deployment, error) { + ret := _m.Called(ctx, projectID, _a2) if len(ret) == 0 { panic("no return value specified for GetDeployment") @@ -302,19 +304,19 @@ func (_m *DeploymentServiceMock) GetDeployment(ctx context.Context, projectID st var r0 deployment.Deployment var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) (deployment.Deployment, error)); ok { - return rf(ctx, projectID, name) + if rf, ok := ret.Get(0).(func(context.Context, string, *v1.AtlasDeployment) (deployment.Deployment, error)); ok { + return rf(ctx, projectID, _a2) } - if rf, ok := ret.Get(0).(func(context.Context, string, string) deployment.Deployment); ok { - r0 = rf(ctx, projectID, name) + if rf, ok := ret.Get(0).(func(context.Context, string, *v1.AtlasDeployment) deployment.Deployment); ok { + r0 = rf(ctx, projectID, _a2) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(deployment.Deployment) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, projectID, name) + if rf, ok := ret.Get(1).(func(context.Context, string, *v1.AtlasDeployment) error); ok { + r1 = rf(ctx, projectID, _a2) } else { r1 = ret.Error(1) } @@ -330,14 +332,14 @@ type DeploymentServiceMock_GetDeployment_Call struct { // GetDeployment is a helper method to define mock.On call // - ctx context.Context // - projectID string -// - name string -func (_e *DeploymentServiceMock_Expecter) GetDeployment(ctx interface{}, projectID interface{}, name interface{}) *DeploymentServiceMock_GetDeployment_Call { - return &DeploymentServiceMock_GetDeployment_Call{Call: _e.mock.On("GetDeployment", ctx, projectID, name)} +// - _a2 *v1.AtlasDeployment +func (_e *DeploymentServiceMock_Expecter) GetDeployment(ctx interface{}, projectID interface{}, _a2 interface{}) *DeploymentServiceMock_GetDeployment_Call { + return &DeploymentServiceMock_GetDeployment_Call{Call: _e.mock.On("GetDeployment", ctx, projectID, _a2)} } -func (_c *DeploymentServiceMock_GetDeployment_Call) Run(run func(ctx context.Context, projectID string, name string)) *DeploymentServiceMock_GetDeployment_Call { +func (_c *DeploymentServiceMock_GetDeployment_Call) Run(run func(ctx context.Context, projectID string, _a2 *v1.AtlasDeployment)) *DeploymentServiceMock_GetDeployment_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string)) + run(args[0].(context.Context), args[1].(string), args[2].(*v1.AtlasDeployment)) }) return _c } @@ -347,7 +349,7 @@ func (_c *DeploymentServiceMock_GetDeployment_Call) Return(_a0 deployment.Deploy return _c } -func (_c *DeploymentServiceMock_GetDeployment_Call) RunAndReturn(run func(context.Context, string, string) (deployment.Deployment, error)) *DeploymentServiceMock_GetDeployment_Call { +func (_c *DeploymentServiceMock_GetDeployment_Call) RunAndReturn(run func(context.Context, string, *v1.AtlasDeployment) (deployment.Deployment, error)) *DeploymentServiceMock_GetDeployment_Call { _c.Call.Return(run) return _c } diff --git a/internal/mocks/translation/endpoint_interface.go b/internal/mocks/translation/endpoint_interface.go index 579694d16c..039ef80d80 100644 --- a/internal/mocks/translation/endpoint_interface.go +++ b/internal/mocks/translation/endpoint_interface.go @@ -17,7 +17,7 @@ func (_m *EndpointInterfaceMock) EXPECT() *EndpointInterfaceMock_Expecter { return &EndpointInterfaceMock_Expecter{mock: &_m.Mock} } -// ErrorMessage provides a mock function with given fields: +// ErrorMessage provides a mock function with no fields func (_m *EndpointInterfaceMock) ErrorMessage() string { ret := _m.Called() @@ -62,7 +62,7 @@ func (_c *EndpointInterfaceMock_ErrorMessage_Call) RunAndReturn(run func() strin return _c } -// InterfaceID provides a mock function with given fields: +// InterfaceID provides a mock function with no fields func (_m *EndpointInterfaceMock) InterfaceID() string { ret := _m.Called() @@ -107,7 +107,7 @@ func (_c *EndpointInterfaceMock_InterfaceID_Call) RunAndReturn(run func() string return _c } -// Status provides a mock function with given fields: +// Status provides a mock function with no fields func (_m *EndpointInterfaceMock) Status() string { ret := _m.Called() diff --git a/internal/mocks/translation/endpoint_service.go b/internal/mocks/translation/endpoint_service.go index 9f42d39e48..5dfff04caa 100644 --- a/internal/mocks/translation/endpoint_service.go +++ b/internal/mocks/translation/endpoint_service.go @@ -21,7 +21,7 @@ func (_m *EndpointServiceMock) EXPECT() *EndpointServiceMock_Expecter { return &EndpointServiceMock_Expecter{mock: &_m.Mock} } -// EndpointInterfaces provides a mock function with given fields: +// EndpointInterfaces provides a mock function with no fields func (_m *EndpointServiceMock) EndpointInterfaces() privateendpoint.EndpointInterfaces { ret := _m.Called() @@ -68,7 +68,7 @@ func (_c *EndpointServiceMock_EndpointInterfaces_Call) RunAndReturn(run func() p return _c } -// ErrorMessage provides a mock function with given fields: +// ErrorMessage provides a mock function with no fields func (_m *EndpointServiceMock) ErrorMessage() string { ret := _m.Called() @@ -113,7 +113,7 @@ func (_c *EndpointServiceMock_ErrorMessage_Call) RunAndReturn(run func() string) return _c } -// Provider provides a mock function with given fields: +// Provider provides a mock function with no fields func (_m *EndpointServiceMock) Provider() string { ret := _m.Called() @@ -158,7 +158,7 @@ func (_c *EndpointServiceMock_Provider_Call) RunAndReturn(run func() string) *En return _c } -// Region provides a mock function with given fields: +// Region provides a mock function with no fields func (_m *EndpointServiceMock) Region() string { ret := _m.Called() @@ -203,7 +203,7 @@ func (_c *EndpointServiceMock_Region_Call) RunAndReturn(run func() string) *Endp return _c } -// ServiceID provides a mock function with given fields: +// ServiceID provides a mock function with no fields func (_m *EndpointServiceMock) ServiceID() string { ret := _m.Called() @@ -248,7 +248,7 @@ func (_c *EndpointServiceMock_ServiceID_Call) RunAndReturn(run func() string) *E return _c } -// Status provides a mock function with given fields: +// Status provides a mock function with no fields func (_m *EndpointServiceMock) Status() string { ret := _m.Called() diff --git a/internal/mocks/translation/project_referrer.go b/internal/mocks/translation/project_referrer.go new file mode 100644 index 0000000000..0ec9ad8d37 --- /dev/null +++ b/internal/mocks/translation/project_referrer.go @@ -0,0 +1,83 @@ +// Code generated by mockery. DO NOT EDIT. + +package translation + +import ( + mock "github.com/stretchr/testify/mock" + + v1 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" +) + +// ProjectReferrerMock is an autogenerated mock type for the ProjectReferrer type +type ProjectReferrerMock struct { + mock.Mock +} + +type ProjectReferrerMock_Expecter struct { + mock *mock.Mock +} + +func (_m *ProjectReferrerMock) EXPECT() *ProjectReferrerMock_Expecter { + return &ProjectReferrerMock_Expecter{mock: &_m.Mock} +} + +// ProjectDualRef provides a mock function with no fields +func (_m *ProjectReferrerMock) ProjectDualRef() *v1.ProjectDualReference { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ProjectDualRef") + } + + var r0 *v1.ProjectDualReference + if rf, ok := ret.Get(0).(func() *v1.ProjectDualReference); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v1.ProjectDualReference) + } + } + + return r0 +} + +// ProjectReferrerMock_ProjectDualRef_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProjectDualRef' +type ProjectReferrerMock_ProjectDualRef_Call struct { + *mock.Call +} + +// ProjectDualRef is a helper method to define mock.On call +func (_e *ProjectReferrerMock_Expecter) ProjectDualRef() *ProjectReferrerMock_ProjectDualRef_Call { + return &ProjectReferrerMock_ProjectDualRef_Call{Call: _e.mock.On("ProjectDualRef")} +} + +func (_c *ProjectReferrerMock_ProjectDualRef_Call) Run(run func()) *ProjectReferrerMock_ProjectDualRef_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerMock_ProjectDualRef_Call) Return(_a0 *v1.ProjectDualReference) *ProjectReferrerMock_ProjectDualRef_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerMock_ProjectDualRef_Call) RunAndReturn(run func() *v1.ProjectDualReference) *ProjectReferrerMock_ProjectDualRef_Call { + _c.Call.Return(run) + return _c +} + +// NewProjectReferrerMock creates a new instance of ProjectReferrerMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProjectReferrerMock(t interface { + mock.TestingT + Cleanup(func()) +}) *ProjectReferrerMock { + mock := &ProjectReferrerMock{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/mocks/translation/project_referrer_object.go b/internal/mocks/translation/project_referrer_object.go new file mode 100644 index 0000000000..6d40c06736 --- /dev/null +++ b/internal/mocks/translation/project_referrer_object.go @@ -0,0 +1,1369 @@ +// Code generated by mockery. DO NOT EDIT. + +package translation + +import ( + mock "github.com/stretchr/testify/mock" + + apiv1 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1" + + runtime "k8s.io/apimachinery/pkg/runtime" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + + types "k8s.io/apimachinery/pkg/types" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ProjectReferrerObjectMock is an autogenerated mock type for the ProjectReferrerObject type +type ProjectReferrerObjectMock struct { + mock.Mock +} + +type ProjectReferrerObjectMock_Expecter struct { + mock *mock.Mock +} + +func (_m *ProjectReferrerObjectMock) EXPECT() *ProjectReferrerObjectMock_Expecter { + return &ProjectReferrerObjectMock_Expecter{mock: &_m.Mock} +} + +// DeepCopyObject provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) DeepCopyObject() runtime.Object { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DeepCopyObject") + } + + var r0 runtime.Object + if rf, ok := ret.Get(0).(func() runtime.Object); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(runtime.Object) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_DeepCopyObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeepCopyObject' +type ProjectReferrerObjectMock_DeepCopyObject_Call struct { + *mock.Call +} + +// DeepCopyObject is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) DeepCopyObject() *ProjectReferrerObjectMock_DeepCopyObject_Call { + return &ProjectReferrerObjectMock_DeepCopyObject_Call{Call: _e.mock.On("DeepCopyObject")} +} + +func (_c *ProjectReferrerObjectMock_DeepCopyObject_Call) Run(run func()) *ProjectReferrerObjectMock_DeepCopyObject_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_DeepCopyObject_Call) Return(_a0 runtime.Object) *ProjectReferrerObjectMock_DeepCopyObject_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_DeepCopyObject_Call) RunAndReturn(run func() runtime.Object) *ProjectReferrerObjectMock_DeepCopyObject_Call { + _c.Call.Return(run) + return _c +} + +// GetAnnotations provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetAnnotations() map[string]string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetAnnotations") + } + + var r0 map[string]string + if rf, ok := ret.Get(0).(func() map[string]string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]string) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_GetAnnotations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAnnotations' +type ProjectReferrerObjectMock_GetAnnotations_Call struct { + *mock.Call +} + +// GetAnnotations is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetAnnotations() *ProjectReferrerObjectMock_GetAnnotations_Call { + return &ProjectReferrerObjectMock_GetAnnotations_Call{Call: _e.mock.On("GetAnnotations")} +} + +func (_c *ProjectReferrerObjectMock_GetAnnotations_Call) Run(run func()) *ProjectReferrerObjectMock_GetAnnotations_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetAnnotations_Call) Return(_a0 map[string]string) *ProjectReferrerObjectMock_GetAnnotations_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetAnnotations_Call) RunAndReturn(run func() map[string]string) *ProjectReferrerObjectMock_GetAnnotations_Call { + _c.Call.Return(run) + return _c +} + +// GetCreationTimestamp provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetCreationTimestamp() v1.Time { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetCreationTimestamp") + } + + var r0 v1.Time + if rf, ok := ret.Get(0).(func() v1.Time); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(v1.Time) + } + + return r0 +} + +// ProjectReferrerObjectMock_GetCreationTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCreationTimestamp' +type ProjectReferrerObjectMock_GetCreationTimestamp_Call struct { + *mock.Call +} + +// GetCreationTimestamp is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetCreationTimestamp() *ProjectReferrerObjectMock_GetCreationTimestamp_Call { + return &ProjectReferrerObjectMock_GetCreationTimestamp_Call{Call: _e.mock.On("GetCreationTimestamp")} +} + +func (_c *ProjectReferrerObjectMock_GetCreationTimestamp_Call) Run(run func()) *ProjectReferrerObjectMock_GetCreationTimestamp_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetCreationTimestamp_Call) Return(_a0 v1.Time) *ProjectReferrerObjectMock_GetCreationTimestamp_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetCreationTimestamp_Call) RunAndReturn(run func() v1.Time) *ProjectReferrerObjectMock_GetCreationTimestamp_Call { + _c.Call.Return(run) + return _c +} + +// GetDeletionGracePeriodSeconds provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetDeletionGracePeriodSeconds() *int64 { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetDeletionGracePeriodSeconds") + } + + var r0 *int64 + if rf, ok := ret.Get(0).(func() *int64); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*int64) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDeletionGracePeriodSeconds' +type ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call struct { + *mock.Call +} + +// GetDeletionGracePeriodSeconds is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetDeletionGracePeriodSeconds() *ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call { + return &ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call{Call: _e.mock.On("GetDeletionGracePeriodSeconds")} +} + +func (_c *ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call) Run(run func()) *ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call) Return(_a0 *int64) *ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call) RunAndReturn(run func() *int64) *ProjectReferrerObjectMock_GetDeletionGracePeriodSeconds_Call { + _c.Call.Return(run) + return _c +} + +// GetDeletionTimestamp provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetDeletionTimestamp() *v1.Time { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetDeletionTimestamp") + } + + var r0 *v1.Time + if rf, ok := ret.Get(0).(func() *v1.Time); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v1.Time) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_GetDeletionTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDeletionTimestamp' +type ProjectReferrerObjectMock_GetDeletionTimestamp_Call struct { + *mock.Call +} + +// GetDeletionTimestamp is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetDeletionTimestamp() *ProjectReferrerObjectMock_GetDeletionTimestamp_Call { + return &ProjectReferrerObjectMock_GetDeletionTimestamp_Call{Call: _e.mock.On("GetDeletionTimestamp")} +} + +func (_c *ProjectReferrerObjectMock_GetDeletionTimestamp_Call) Run(run func()) *ProjectReferrerObjectMock_GetDeletionTimestamp_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetDeletionTimestamp_Call) Return(_a0 *v1.Time) *ProjectReferrerObjectMock_GetDeletionTimestamp_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetDeletionTimestamp_Call) RunAndReturn(run func() *v1.Time) *ProjectReferrerObjectMock_GetDeletionTimestamp_Call { + _c.Call.Return(run) + return _c +} + +// GetFinalizers provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetFinalizers() []string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetFinalizers") + } + + var r0 []string + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_GetFinalizers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFinalizers' +type ProjectReferrerObjectMock_GetFinalizers_Call struct { + *mock.Call +} + +// GetFinalizers is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetFinalizers() *ProjectReferrerObjectMock_GetFinalizers_Call { + return &ProjectReferrerObjectMock_GetFinalizers_Call{Call: _e.mock.On("GetFinalizers")} +} + +func (_c *ProjectReferrerObjectMock_GetFinalizers_Call) Run(run func()) *ProjectReferrerObjectMock_GetFinalizers_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetFinalizers_Call) Return(_a0 []string) *ProjectReferrerObjectMock_GetFinalizers_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetFinalizers_Call) RunAndReturn(run func() []string) *ProjectReferrerObjectMock_GetFinalizers_Call { + _c.Call.Return(run) + return _c +} + +// GetGenerateName provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetGenerateName() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetGenerateName") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// ProjectReferrerObjectMock_GetGenerateName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGenerateName' +type ProjectReferrerObjectMock_GetGenerateName_Call struct { + *mock.Call +} + +// GetGenerateName is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetGenerateName() *ProjectReferrerObjectMock_GetGenerateName_Call { + return &ProjectReferrerObjectMock_GetGenerateName_Call{Call: _e.mock.On("GetGenerateName")} +} + +func (_c *ProjectReferrerObjectMock_GetGenerateName_Call) Run(run func()) *ProjectReferrerObjectMock_GetGenerateName_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetGenerateName_Call) Return(_a0 string) *ProjectReferrerObjectMock_GetGenerateName_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetGenerateName_Call) RunAndReturn(run func() string) *ProjectReferrerObjectMock_GetGenerateName_Call { + _c.Call.Return(run) + return _c +} + +// GetGeneration provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetGeneration() int64 { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetGeneration") + } + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + return r0 +} + +// ProjectReferrerObjectMock_GetGeneration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGeneration' +type ProjectReferrerObjectMock_GetGeneration_Call struct { + *mock.Call +} + +// GetGeneration is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetGeneration() *ProjectReferrerObjectMock_GetGeneration_Call { + return &ProjectReferrerObjectMock_GetGeneration_Call{Call: _e.mock.On("GetGeneration")} +} + +func (_c *ProjectReferrerObjectMock_GetGeneration_Call) Run(run func()) *ProjectReferrerObjectMock_GetGeneration_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetGeneration_Call) Return(_a0 int64) *ProjectReferrerObjectMock_GetGeneration_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetGeneration_Call) RunAndReturn(run func() int64) *ProjectReferrerObjectMock_GetGeneration_Call { + _c.Call.Return(run) + return _c +} + +// GetLabels provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetLabels() map[string]string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetLabels") + } + + var r0 map[string]string + if rf, ok := ret.Get(0).(func() map[string]string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]string) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_GetLabels_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLabels' +type ProjectReferrerObjectMock_GetLabels_Call struct { + *mock.Call +} + +// GetLabels is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetLabels() *ProjectReferrerObjectMock_GetLabels_Call { + return &ProjectReferrerObjectMock_GetLabels_Call{Call: _e.mock.On("GetLabels")} +} + +func (_c *ProjectReferrerObjectMock_GetLabels_Call) Run(run func()) *ProjectReferrerObjectMock_GetLabels_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetLabels_Call) Return(_a0 map[string]string) *ProjectReferrerObjectMock_GetLabels_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetLabels_Call) RunAndReturn(run func() map[string]string) *ProjectReferrerObjectMock_GetLabels_Call { + _c.Call.Return(run) + return _c +} + +// GetManagedFields provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetManagedFields() []v1.ManagedFieldsEntry { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetManagedFields") + } + + var r0 []v1.ManagedFieldsEntry + if rf, ok := ret.Get(0).(func() []v1.ManagedFieldsEntry); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]v1.ManagedFieldsEntry) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_GetManagedFields_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetManagedFields' +type ProjectReferrerObjectMock_GetManagedFields_Call struct { + *mock.Call +} + +// GetManagedFields is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetManagedFields() *ProjectReferrerObjectMock_GetManagedFields_Call { + return &ProjectReferrerObjectMock_GetManagedFields_Call{Call: _e.mock.On("GetManagedFields")} +} + +func (_c *ProjectReferrerObjectMock_GetManagedFields_Call) Run(run func()) *ProjectReferrerObjectMock_GetManagedFields_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetManagedFields_Call) Return(_a0 []v1.ManagedFieldsEntry) *ProjectReferrerObjectMock_GetManagedFields_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetManagedFields_Call) RunAndReturn(run func() []v1.ManagedFieldsEntry) *ProjectReferrerObjectMock_GetManagedFields_Call { + _c.Call.Return(run) + return _c +} + +// GetName provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetName() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetName") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// ProjectReferrerObjectMock_GetName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetName' +type ProjectReferrerObjectMock_GetName_Call struct { + *mock.Call +} + +// GetName is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetName() *ProjectReferrerObjectMock_GetName_Call { + return &ProjectReferrerObjectMock_GetName_Call{Call: _e.mock.On("GetName")} +} + +func (_c *ProjectReferrerObjectMock_GetName_Call) Run(run func()) *ProjectReferrerObjectMock_GetName_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetName_Call) Return(_a0 string) *ProjectReferrerObjectMock_GetName_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetName_Call) RunAndReturn(run func() string) *ProjectReferrerObjectMock_GetName_Call { + _c.Call.Return(run) + return _c +} + +// GetNamespace provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetNamespace() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetNamespace") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// ProjectReferrerObjectMock_GetNamespace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNamespace' +type ProjectReferrerObjectMock_GetNamespace_Call struct { + *mock.Call +} + +// GetNamespace is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetNamespace() *ProjectReferrerObjectMock_GetNamespace_Call { + return &ProjectReferrerObjectMock_GetNamespace_Call{Call: _e.mock.On("GetNamespace")} +} + +func (_c *ProjectReferrerObjectMock_GetNamespace_Call) Run(run func()) *ProjectReferrerObjectMock_GetNamespace_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetNamespace_Call) Return(_a0 string) *ProjectReferrerObjectMock_GetNamespace_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetNamespace_Call) RunAndReturn(run func() string) *ProjectReferrerObjectMock_GetNamespace_Call { + _c.Call.Return(run) + return _c +} + +// GetObjectKind provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetObjectKind() schema.ObjectKind { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetObjectKind") + } + + var r0 schema.ObjectKind + if rf, ok := ret.Get(0).(func() schema.ObjectKind); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(schema.ObjectKind) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_GetObjectKind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetObjectKind' +type ProjectReferrerObjectMock_GetObjectKind_Call struct { + *mock.Call +} + +// GetObjectKind is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetObjectKind() *ProjectReferrerObjectMock_GetObjectKind_Call { + return &ProjectReferrerObjectMock_GetObjectKind_Call{Call: _e.mock.On("GetObjectKind")} +} + +func (_c *ProjectReferrerObjectMock_GetObjectKind_Call) Run(run func()) *ProjectReferrerObjectMock_GetObjectKind_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetObjectKind_Call) Return(_a0 schema.ObjectKind) *ProjectReferrerObjectMock_GetObjectKind_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetObjectKind_Call) RunAndReturn(run func() schema.ObjectKind) *ProjectReferrerObjectMock_GetObjectKind_Call { + _c.Call.Return(run) + return _c +} + +// GetOwnerReferences provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetOwnerReferences() []v1.OwnerReference { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetOwnerReferences") + } + + var r0 []v1.OwnerReference + if rf, ok := ret.Get(0).(func() []v1.OwnerReference); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]v1.OwnerReference) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_GetOwnerReferences_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOwnerReferences' +type ProjectReferrerObjectMock_GetOwnerReferences_Call struct { + *mock.Call +} + +// GetOwnerReferences is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetOwnerReferences() *ProjectReferrerObjectMock_GetOwnerReferences_Call { + return &ProjectReferrerObjectMock_GetOwnerReferences_Call{Call: _e.mock.On("GetOwnerReferences")} +} + +func (_c *ProjectReferrerObjectMock_GetOwnerReferences_Call) Run(run func()) *ProjectReferrerObjectMock_GetOwnerReferences_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetOwnerReferences_Call) Return(_a0 []v1.OwnerReference) *ProjectReferrerObjectMock_GetOwnerReferences_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetOwnerReferences_Call) RunAndReturn(run func() []v1.OwnerReference) *ProjectReferrerObjectMock_GetOwnerReferences_Call { + _c.Call.Return(run) + return _c +} + +// GetResourceVersion provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetResourceVersion() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetResourceVersion") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// ProjectReferrerObjectMock_GetResourceVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetResourceVersion' +type ProjectReferrerObjectMock_GetResourceVersion_Call struct { + *mock.Call +} + +// GetResourceVersion is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetResourceVersion() *ProjectReferrerObjectMock_GetResourceVersion_Call { + return &ProjectReferrerObjectMock_GetResourceVersion_Call{Call: _e.mock.On("GetResourceVersion")} +} + +func (_c *ProjectReferrerObjectMock_GetResourceVersion_Call) Run(run func()) *ProjectReferrerObjectMock_GetResourceVersion_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetResourceVersion_Call) Return(_a0 string) *ProjectReferrerObjectMock_GetResourceVersion_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetResourceVersion_Call) RunAndReturn(run func() string) *ProjectReferrerObjectMock_GetResourceVersion_Call { + _c.Call.Return(run) + return _c +} + +// GetSelfLink provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetSelfLink() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetSelfLink") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// ProjectReferrerObjectMock_GetSelfLink_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSelfLink' +type ProjectReferrerObjectMock_GetSelfLink_Call struct { + *mock.Call +} + +// GetSelfLink is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetSelfLink() *ProjectReferrerObjectMock_GetSelfLink_Call { + return &ProjectReferrerObjectMock_GetSelfLink_Call{Call: _e.mock.On("GetSelfLink")} +} + +func (_c *ProjectReferrerObjectMock_GetSelfLink_Call) Run(run func()) *ProjectReferrerObjectMock_GetSelfLink_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetSelfLink_Call) Return(_a0 string) *ProjectReferrerObjectMock_GetSelfLink_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetSelfLink_Call) RunAndReturn(run func() string) *ProjectReferrerObjectMock_GetSelfLink_Call { + _c.Call.Return(run) + return _c +} + +// GetUID provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) GetUID() types.UID { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetUID") + } + + var r0 types.UID + if rf, ok := ret.Get(0).(func() types.UID); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(types.UID) + } + + return r0 +} + +// ProjectReferrerObjectMock_GetUID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUID' +type ProjectReferrerObjectMock_GetUID_Call struct { + *mock.Call +} + +// GetUID is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) GetUID() *ProjectReferrerObjectMock_GetUID_Call { + return &ProjectReferrerObjectMock_GetUID_Call{Call: _e.mock.On("GetUID")} +} + +func (_c *ProjectReferrerObjectMock_GetUID_Call) Run(run func()) *ProjectReferrerObjectMock_GetUID_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetUID_Call) Return(_a0 types.UID) *ProjectReferrerObjectMock_GetUID_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_GetUID_Call) RunAndReturn(run func() types.UID) *ProjectReferrerObjectMock_GetUID_Call { + _c.Call.Return(run) + return _c +} + +// ProjectDualRef provides a mock function with no fields +func (_m *ProjectReferrerObjectMock) ProjectDualRef() *apiv1.ProjectDualReference { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ProjectDualRef") + } + + var r0 *apiv1.ProjectDualReference + if rf, ok := ret.Get(0).(func() *apiv1.ProjectDualReference); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*apiv1.ProjectDualReference) + } + } + + return r0 +} + +// ProjectReferrerObjectMock_ProjectDualRef_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProjectDualRef' +type ProjectReferrerObjectMock_ProjectDualRef_Call struct { + *mock.Call +} + +// ProjectDualRef is a helper method to define mock.On call +func (_e *ProjectReferrerObjectMock_Expecter) ProjectDualRef() *ProjectReferrerObjectMock_ProjectDualRef_Call { + return &ProjectReferrerObjectMock_ProjectDualRef_Call{Call: _e.mock.On("ProjectDualRef")} +} + +func (_c *ProjectReferrerObjectMock_ProjectDualRef_Call) Run(run func()) *ProjectReferrerObjectMock_ProjectDualRef_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_ProjectDualRef_Call) Return(_a0 *apiv1.ProjectDualReference) *ProjectReferrerObjectMock_ProjectDualRef_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProjectReferrerObjectMock_ProjectDualRef_Call) RunAndReturn(run func() *apiv1.ProjectDualReference) *ProjectReferrerObjectMock_ProjectDualRef_Call { + _c.Call.Return(run) + return _c +} + +// SetAnnotations provides a mock function with given fields: annotations +func (_m *ProjectReferrerObjectMock) SetAnnotations(annotations map[string]string) { + _m.Called(annotations) +} + +// ProjectReferrerObjectMock_SetAnnotations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAnnotations' +type ProjectReferrerObjectMock_SetAnnotations_Call struct { + *mock.Call +} + +// SetAnnotations is a helper method to define mock.On call +// - annotations map[string]string +func (_e *ProjectReferrerObjectMock_Expecter) SetAnnotations(annotations interface{}) *ProjectReferrerObjectMock_SetAnnotations_Call { + return &ProjectReferrerObjectMock_SetAnnotations_Call{Call: _e.mock.On("SetAnnotations", annotations)} +} + +func (_c *ProjectReferrerObjectMock_SetAnnotations_Call) Run(run func(annotations map[string]string)) *ProjectReferrerObjectMock_SetAnnotations_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(map[string]string)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetAnnotations_Call) Return() *ProjectReferrerObjectMock_SetAnnotations_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetAnnotations_Call) RunAndReturn(run func(map[string]string)) *ProjectReferrerObjectMock_SetAnnotations_Call { + _c.Run(run) + return _c +} + +// SetCreationTimestamp provides a mock function with given fields: timestamp +func (_m *ProjectReferrerObjectMock) SetCreationTimestamp(timestamp v1.Time) { + _m.Called(timestamp) +} + +// ProjectReferrerObjectMock_SetCreationTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetCreationTimestamp' +type ProjectReferrerObjectMock_SetCreationTimestamp_Call struct { + *mock.Call +} + +// SetCreationTimestamp is a helper method to define mock.On call +// - timestamp v1.Time +func (_e *ProjectReferrerObjectMock_Expecter) SetCreationTimestamp(timestamp interface{}) *ProjectReferrerObjectMock_SetCreationTimestamp_Call { + return &ProjectReferrerObjectMock_SetCreationTimestamp_Call{Call: _e.mock.On("SetCreationTimestamp", timestamp)} +} + +func (_c *ProjectReferrerObjectMock_SetCreationTimestamp_Call) Run(run func(timestamp v1.Time)) *ProjectReferrerObjectMock_SetCreationTimestamp_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(v1.Time)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetCreationTimestamp_Call) Return() *ProjectReferrerObjectMock_SetCreationTimestamp_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetCreationTimestamp_Call) RunAndReturn(run func(v1.Time)) *ProjectReferrerObjectMock_SetCreationTimestamp_Call { + _c.Run(run) + return _c +} + +// SetDeletionGracePeriodSeconds provides a mock function with given fields: _a0 +func (_m *ProjectReferrerObjectMock) SetDeletionGracePeriodSeconds(_a0 *int64) { + _m.Called(_a0) +} + +// ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDeletionGracePeriodSeconds' +type ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call struct { + *mock.Call +} + +// SetDeletionGracePeriodSeconds is a helper method to define mock.On call +// - _a0 *int64 +func (_e *ProjectReferrerObjectMock_Expecter) SetDeletionGracePeriodSeconds(_a0 interface{}) *ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call { + return &ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call{Call: _e.mock.On("SetDeletionGracePeriodSeconds", _a0)} +} + +func (_c *ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call) Run(run func(_a0 *int64)) *ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*int64)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call) Return() *ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call) RunAndReturn(run func(*int64)) *ProjectReferrerObjectMock_SetDeletionGracePeriodSeconds_Call { + _c.Run(run) + return _c +} + +// SetDeletionTimestamp provides a mock function with given fields: timestamp +func (_m *ProjectReferrerObjectMock) SetDeletionTimestamp(timestamp *v1.Time) { + _m.Called(timestamp) +} + +// ProjectReferrerObjectMock_SetDeletionTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDeletionTimestamp' +type ProjectReferrerObjectMock_SetDeletionTimestamp_Call struct { + *mock.Call +} + +// SetDeletionTimestamp is a helper method to define mock.On call +// - timestamp *v1.Time +func (_e *ProjectReferrerObjectMock_Expecter) SetDeletionTimestamp(timestamp interface{}) *ProjectReferrerObjectMock_SetDeletionTimestamp_Call { + return &ProjectReferrerObjectMock_SetDeletionTimestamp_Call{Call: _e.mock.On("SetDeletionTimestamp", timestamp)} +} + +func (_c *ProjectReferrerObjectMock_SetDeletionTimestamp_Call) Run(run func(timestamp *v1.Time)) *ProjectReferrerObjectMock_SetDeletionTimestamp_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*v1.Time)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetDeletionTimestamp_Call) Return() *ProjectReferrerObjectMock_SetDeletionTimestamp_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetDeletionTimestamp_Call) RunAndReturn(run func(*v1.Time)) *ProjectReferrerObjectMock_SetDeletionTimestamp_Call { + _c.Run(run) + return _c +} + +// SetFinalizers provides a mock function with given fields: finalizers +func (_m *ProjectReferrerObjectMock) SetFinalizers(finalizers []string) { + _m.Called(finalizers) +} + +// ProjectReferrerObjectMock_SetFinalizers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetFinalizers' +type ProjectReferrerObjectMock_SetFinalizers_Call struct { + *mock.Call +} + +// SetFinalizers is a helper method to define mock.On call +// - finalizers []string +func (_e *ProjectReferrerObjectMock_Expecter) SetFinalizers(finalizers interface{}) *ProjectReferrerObjectMock_SetFinalizers_Call { + return &ProjectReferrerObjectMock_SetFinalizers_Call{Call: _e.mock.On("SetFinalizers", finalizers)} +} + +func (_c *ProjectReferrerObjectMock_SetFinalizers_Call) Run(run func(finalizers []string)) *ProjectReferrerObjectMock_SetFinalizers_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]string)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetFinalizers_Call) Return() *ProjectReferrerObjectMock_SetFinalizers_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetFinalizers_Call) RunAndReturn(run func([]string)) *ProjectReferrerObjectMock_SetFinalizers_Call { + _c.Run(run) + return _c +} + +// SetGenerateName provides a mock function with given fields: name +func (_m *ProjectReferrerObjectMock) SetGenerateName(name string) { + _m.Called(name) +} + +// ProjectReferrerObjectMock_SetGenerateName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetGenerateName' +type ProjectReferrerObjectMock_SetGenerateName_Call struct { + *mock.Call +} + +// SetGenerateName is a helper method to define mock.On call +// - name string +func (_e *ProjectReferrerObjectMock_Expecter) SetGenerateName(name interface{}) *ProjectReferrerObjectMock_SetGenerateName_Call { + return &ProjectReferrerObjectMock_SetGenerateName_Call{Call: _e.mock.On("SetGenerateName", name)} +} + +func (_c *ProjectReferrerObjectMock_SetGenerateName_Call) Run(run func(name string)) *ProjectReferrerObjectMock_SetGenerateName_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetGenerateName_Call) Return() *ProjectReferrerObjectMock_SetGenerateName_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetGenerateName_Call) RunAndReturn(run func(string)) *ProjectReferrerObjectMock_SetGenerateName_Call { + _c.Run(run) + return _c +} + +// SetGeneration provides a mock function with given fields: generation +func (_m *ProjectReferrerObjectMock) SetGeneration(generation int64) { + _m.Called(generation) +} + +// ProjectReferrerObjectMock_SetGeneration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetGeneration' +type ProjectReferrerObjectMock_SetGeneration_Call struct { + *mock.Call +} + +// SetGeneration is a helper method to define mock.On call +// - generation int64 +func (_e *ProjectReferrerObjectMock_Expecter) SetGeneration(generation interface{}) *ProjectReferrerObjectMock_SetGeneration_Call { + return &ProjectReferrerObjectMock_SetGeneration_Call{Call: _e.mock.On("SetGeneration", generation)} +} + +func (_c *ProjectReferrerObjectMock_SetGeneration_Call) Run(run func(generation int64)) *ProjectReferrerObjectMock_SetGeneration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int64)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetGeneration_Call) Return() *ProjectReferrerObjectMock_SetGeneration_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetGeneration_Call) RunAndReturn(run func(int64)) *ProjectReferrerObjectMock_SetGeneration_Call { + _c.Run(run) + return _c +} + +// SetLabels provides a mock function with given fields: labels +func (_m *ProjectReferrerObjectMock) SetLabels(labels map[string]string) { + _m.Called(labels) +} + +// ProjectReferrerObjectMock_SetLabels_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetLabels' +type ProjectReferrerObjectMock_SetLabels_Call struct { + *mock.Call +} + +// SetLabels is a helper method to define mock.On call +// - labels map[string]string +func (_e *ProjectReferrerObjectMock_Expecter) SetLabels(labels interface{}) *ProjectReferrerObjectMock_SetLabels_Call { + return &ProjectReferrerObjectMock_SetLabels_Call{Call: _e.mock.On("SetLabels", labels)} +} + +func (_c *ProjectReferrerObjectMock_SetLabels_Call) Run(run func(labels map[string]string)) *ProjectReferrerObjectMock_SetLabels_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(map[string]string)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetLabels_Call) Return() *ProjectReferrerObjectMock_SetLabels_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetLabels_Call) RunAndReturn(run func(map[string]string)) *ProjectReferrerObjectMock_SetLabels_Call { + _c.Run(run) + return _c +} + +// SetManagedFields provides a mock function with given fields: managedFields +func (_m *ProjectReferrerObjectMock) SetManagedFields(managedFields []v1.ManagedFieldsEntry) { + _m.Called(managedFields) +} + +// ProjectReferrerObjectMock_SetManagedFields_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetManagedFields' +type ProjectReferrerObjectMock_SetManagedFields_Call struct { + *mock.Call +} + +// SetManagedFields is a helper method to define mock.On call +// - managedFields []v1.ManagedFieldsEntry +func (_e *ProjectReferrerObjectMock_Expecter) SetManagedFields(managedFields interface{}) *ProjectReferrerObjectMock_SetManagedFields_Call { + return &ProjectReferrerObjectMock_SetManagedFields_Call{Call: _e.mock.On("SetManagedFields", managedFields)} +} + +func (_c *ProjectReferrerObjectMock_SetManagedFields_Call) Run(run func(managedFields []v1.ManagedFieldsEntry)) *ProjectReferrerObjectMock_SetManagedFields_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]v1.ManagedFieldsEntry)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetManagedFields_Call) Return() *ProjectReferrerObjectMock_SetManagedFields_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetManagedFields_Call) RunAndReturn(run func([]v1.ManagedFieldsEntry)) *ProjectReferrerObjectMock_SetManagedFields_Call { + _c.Run(run) + return _c +} + +// SetName provides a mock function with given fields: name +func (_m *ProjectReferrerObjectMock) SetName(name string) { + _m.Called(name) +} + +// ProjectReferrerObjectMock_SetName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetName' +type ProjectReferrerObjectMock_SetName_Call struct { + *mock.Call +} + +// SetName is a helper method to define mock.On call +// - name string +func (_e *ProjectReferrerObjectMock_Expecter) SetName(name interface{}) *ProjectReferrerObjectMock_SetName_Call { + return &ProjectReferrerObjectMock_SetName_Call{Call: _e.mock.On("SetName", name)} +} + +func (_c *ProjectReferrerObjectMock_SetName_Call) Run(run func(name string)) *ProjectReferrerObjectMock_SetName_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetName_Call) Return() *ProjectReferrerObjectMock_SetName_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetName_Call) RunAndReturn(run func(string)) *ProjectReferrerObjectMock_SetName_Call { + _c.Run(run) + return _c +} + +// SetNamespace provides a mock function with given fields: namespace +func (_m *ProjectReferrerObjectMock) SetNamespace(namespace string) { + _m.Called(namespace) +} + +// ProjectReferrerObjectMock_SetNamespace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetNamespace' +type ProjectReferrerObjectMock_SetNamespace_Call struct { + *mock.Call +} + +// SetNamespace is a helper method to define mock.On call +// - namespace string +func (_e *ProjectReferrerObjectMock_Expecter) SetNamespace(namespace interface{}) *ProjectReferrerObjectMock_SetNamespace_Call { + return &ProjectReferrerObjectMock_SetNamespace_Call{Call: _e.mock.On("SetNamespace", namespace)} +} + +func (_c *ProjectReferrerObjectMock_SetNamespace_Call) Run(run func(namespace string)) *ProjectReferrerObjectMock_SetNamespace_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetNamespace_Call) Return() *ProjectReferrerObjectMock_SetNamespace_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetNamespace_Call) RunAndReturn(run func(string)) *ProjectReferrerObjectMock_SetNamespace_Call { + _c.Run(run) + return _c +} + +// SetOwnerReferences provides a mock function with given fields: _a0 +func (_m *ProjectReferrerObjectMock) SetOwnerReferences(_a0 []v1.OwnerReference) { + _m.Called(_a0) +} + +// ProjectReferrerObjectMock_SetOwnerReferences_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetOwnerReferences' +type ProjectReferrerObjectMock_SetOwnerReferences_Call struct { + *mock.Call +} + +// SetOwnerReferences is a helper method to define mock.On call +// - _a0 []v1.OwnerReference +func (_e *ProjectReferrerObjectMock_Expecter) SetOwnerReferences(_a0 interface{}) *ProjectReferrerObjectMock_SetOwnerReferences_Call { + return &ProjectReferrerObjectMock_SetOwnerReferences_Call{Call: _e.mock.On("SetOwnerReferences", _a0)} +} + +func (_c *ProjectReferrerObjectMock_SetOwnerReferences_Call) Run(run func(_a0 []v1.OwnerReference)) *ProjectReferrerObjectMock_SetOwnerReferences_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]v1.OwnerReference)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetOwnerReferences_Call) Return() *ProjectReferrerObjectMock_SetOwnerReferences_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetOwnerReferences_Call) RunAndReturn(run func([]v1.OwnerReference)) *ProjectReferrerObjectMock_SetOwnerReferences_Call { + _c.Run(run) + return _c +} + +// SetResourceVersion provides a mock function with given fields: version +func (_m *ProjectReferrerObjectMock) SetResourceVersion(version string) { + _m.Called(version) +} + +// ProjectReferrerObjectMock_SetResourceVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetResourceVersion' +type ProjectReferrerObjectMock_SetResourceVersion_Call struct { + *mock.Call +} + +// SetResourceVersion is a helper method to define mock.On call +// - version string +func (_e *ProjectReferrerObjectMock_Expecter) SetResourceVersion(version interface{}) *ProjectReferrerObjectMock_SetResourceVersion_Call { + return &ProjectReferrerObjectMock_SetResourceVersion_Call{Call: _e.mock.On("SetResourceVersion", version)} +} + +func (_c *ProjectReferrerObjectMock_SetResourceVersion_Call) Run(run func(version string)) *ProjectReferrerObjectMock_SetResourceVersion_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetResourceVersion_Call) Return() *ProjectReferrerObjectMock_SetResourceVersion_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetResourceVersion_Call) RunAndReturn(run func(string)) *ProjectReferrerObjectMock_SetResourceVersion_Call { + _c.Run(run) + return _c +} + +// SetSelfLink provides a mock function with given fields: selfLink +func (_m *ProjectReferrerObjectMock) SetSelfLink(selfLink string) { + _m.Called(selfLink) +} + +// ProjectReferrerObjectMock_SetSelfLink_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetSelfLink' +type ProjectReferrerObjectMock_SetSelfLink_Call struct { + *mock.Call +} + +// SetSelfLink is a helper method to define mock.On call +// - selfLink string +func (_e *ProjectReferrerObjectMock_Expecter) SetSelfLink(selfLink interface{}) *ProjectReferrerObjectMock_SetSelfLink_Call { + return &ProjectReferrerObjectMock_SetSelfLink_Call{Call: _e.mock.On("SetSelfLink", selfLink)} +} + +func (_c *ProjectReferrerObjectMock_SetSelfLink_Call) Run(run func(selfLink string)) *ProjectReferrerObjectMock_SetSelfLink_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetSelfLink_Call) Return() *ProjectReferrerObjectMock_SetSelfLink_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetSelfLink_Call) RunAndReturn(run func(string)) *ProjectReferrerObjectMock_SetSelfLink_Call { + _c.Run(run) + return _c +} + +// SetUID provides a mock function with given fields: uid +func (_m *ProjectReferrerObjectMock) SetUID(uid types.UID) { + _m.Called(uid) +} + +// ProjectReferrerObjectMock_SetUID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetUID' +type ProjectReferrerObjectMock_SetUID_Call struct { + *mock.Call +} + +// SetUID is a helper method to define mock.On call +// - uid types.UID +func (_e *ProjectReferrerObjectMock_Expecter) SetUID(uid interface{}) *ProjectReferrerObjectMock_SetUID_Call { + return &ProjectReferrerObjectMock_SetUID_Call{Call: _e.mock.On("SetUID", uid)} +} + +func (_c *ProjectReferrerObjectMock_SetUID_Call) Run(run func(uid types.UID)) *ProjectReferrerObjectMock_SetUID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(types.UID)) + }) + return _c +} + +func (_c *ProjectReferrerObjectMock_SetUID_Call) Return() *ProjectReferrerObjectMock_SetUID_Call { + _c.Call.Return() + return _c +} + +func (_c *ProjectReferrerObjectMock_SetUID_Call) RunAndReturn(run func(types.UID)) *ProjectReferrerObjectMock_SetUID_Call { + _c.Run(run) + return _c +} + +// NewProjectReferrerObjectMock creates a new instance of ProjectReferrerObjectMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProjectReferrerObjectMock(t interface { + mock.TestingT + Cleanup(func()) +}) *ProjectReferrerObjectMock { + mock := &ProjectReferrerObjectMock{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From 8545ad405854813af1d5de4a2c6393e8d2ae86dd Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 15:53:16 +0100 Subject: [PATCH 26/33] remove checking for serverless vs. non-serverless constraints as it breaks flex --- .../controller/atlasdeployment/atlasdeployment_controller.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller.go b/internal/controller/atlasdeployment/atlasdeployment_controller.go index 7a0e96b966..710b9dc8ca 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller.go @@ -170,10 +170,6 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ } existsInAtlas := deploymentInAtlas != nil - if existsInAtlas && deploymentInAKO.IsServerless() != deploymentInAtlas.IsServerless() { - return r.terminate(workflowCtx, workflow.Internal, errors.New("regular deployment cannot be converted into a serverless deployment and vice-versa")) - } - if !atlasDeployment.GetDeletionTimestamp().IsZero() { if existsInAtlas { return r.delete(workflowCtx, deploymentService, deploymentInAKO) From 45be1fa1af6e16853b9803798d4a3beb791fa66c Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 15:55:05 +0100 Subject: [PATCH 27/33] check for wrong cluster types explicitely --- internal/translation/deployment/deployment.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index 4f9fc6024d..cef2298013 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -122,7 +122,7 @@ func (ds *ProductionAtlasDeployments) ListDeploymentConnections(ctx context.Cont func (ds *ProductionAtlasDeployments) ClusterExists(ctx context.Context, projectID, name string) (bool, error) { flex, err := ds.GetFlexCluster(ctx, projectID, name) - if err != nil { + if !adminv20241113001.IsErrorCode(err, atlas.NonFlexInFlexAPI) && err != nil { return false, err } if flex != nil { @@ -130,7 +130,7 @@ func (ds *ProductionAtlasDeployments) ClusterExists(ctx context.Context, project } cluster, err := ds.GetCluster(ctx, projectID, name) - if err != nil { + if !admin.IsErrorCode(err, atlas.ServerlessInstanceFromClusterAPI) && err != nil { return false, err } if cluster != nil { @@ -138,7 +138,7 @@ func (ds *ProductionAtlasDeployments) ClusterExists(ctx context.Context, project } serverless, err := ds.GetServerless(ctx, projectID, name) - if err != nil { + if !admin.IsErrorCode(err, atlas.ClusterInstanceFromServerlessAPI) && err != nil { return false, err } if serverless != nil { From 75ec48f48ddd20d59180934e81d74bcafd2e294c Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 16:02:44 +0100 Subject: [PATCH 28/33] act on not found errors only in GetFlexCluster --- internal/translation/deployment/deployment.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index cef2298013..ea91ecb55f 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -167,14 +167,8 @@ func (ds *ProductionAtlasDeployments) GetFlexCluster(ctx context.Context, projec return flexFromAtlas(flex), nil } - if sdkerr, ok := adminv20241113001.AsError(err); ok { - switch sdkerr.GetErrorCode() { - case atlas.ClusterNotFound: - case atlas.NonFlexInFlexAPI: - case atlas.FeatureUnsupported: - default: - return nil, err - } + if !adminv20241113001.IsErrorCode(err, atlas.ClusterNotFound) { + return nil, err } return nil, nil @@ -186,7 +180,7 @@ func (ds *ProductionAtlasDeployments) GetCluster(ctx context.Context, projectID, return clusterFromAtlas(cluster), nil } - if !admin.IsErrorCode(err, atlas.ClusterNotFound) && !admin.IsErrorCode(err, atlas.ServerlessInstanceFromClusterAPI) { + if !admin.IsErrorCode(err, atlas.ClusterNotFound) { return nil, err } From 9f12f2f74033de714b2b3fa02dcadc8839ebdc03 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 16:03:18 +0100 Subject: [PATCH 29/33] use deployment names for getcluster --- internal/translation/deployment/deployment.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go index ea91ecb55f..d8156b8cbf 100644 --- a/internal/translation/deployment/deployment.go +++ b/internal/translation/deployment/deployment.go @@ -211,7 +211,7 @@ func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, project switch { case deployment.IsFlex(): - flex, err := ds.GetFlexCluster(ctx, projectID, deployment.Name) + flex, err := ds.GetFlexCluster(ctx, projectID, deployment.GetDeploymentName()) if err != nil { return nil, err } @@ -220,7 +220,7 @@ func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, project } case deployment.IsServerless(): - serverless, err := ds.GetServerless(ctx, projectID, deployment.Name) + serverless, err := ds.GetServerless(ctx, projectID, deployment.GetDeploymentName()) if err != nil { return nil, err } @@ -229,7 +229,7 @@ func (ds *ProductionAtlasDeployments) GetDeployment(ctx context.Context, project } case deployment.IsAdvancedDeployment(): - cluster, err := ds.GetCluster(ctx, projectID, deployment.Name) + cluster, err := ds.GetCluster(ctx, projectID, deployment.GetDeploymentName()) if err != nil { return nil, err } From d931e1064109b264d01eddeb8d0210466fd71255 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 16:03:46 +0100 Subject: [PATCH 30/33] add error code from Atlas signalling wrong API call --- internal/controller/atlas/api_error.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/controller/atlas/api_error.go b/internal/controller/atlas/api_error.go index 6eedc66747..67c476a22e 100644 --- a/internal/controller/atlas/api_error.go +++ b/internal/controller/atlas/api_error.go @@ -27,6 +27,8 @@ const ( // a serverless instance from the cluster API, which is not allowed ServerlessInstanceFromClusterAPI = "CANNOT_USE_SERVERLESS_INSTANCE_IN_CLUSTER_API" + ClusterInstanceFromServerlessAPI = "CANNOT_USE_CLUSTER_IN_SERVERLESS_INSTANCE_API" + // Resource not found ResourceNotFound = "RESOURCE_NOT_FOUND" From f3a009a1c33e122de781bffbcc14fa06b3633659 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 16:03:57 +0100 Subject: [PATCH 31/33] fix tests --- .../atlasdeployment_controller_test.go | 106 +++++++++--------- .../translation/deployment/deployment_test.go | 17 +-- test/int/deployment_test.go | 2 +- 3 files changed, 61 insertions(+), 64 deletions(-) diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go index c3768e671a..aeb750f925 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go @@ -1140,7 +1140,8 @@ func TestFindDeploymentsForBackupSchedule(t *testing.T) { func TestChangeDeploymentType(t *testing.T) { tests := map[string]struct { - deployment *akov2.AtlasDeployment + deployment *akov2.AtlasDeployment + atlasProvider atlas.Provider }{ "should fail when existing cluster is regular but manifest defines a serverless instance": { deployment: &akov2.AtlasDeployment{ @@ -1167,6 +1168,33 @@ func TestChangeDeploymentType(t *testing.T) { StateName: "IDLE", }, }, + + atlasProvider: &atlasmock.TestProvider{ + IsCloudGovFunc: func() bool { + return false + }, + IsSupportedFunc: func() bool { + return true + }, + SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { + return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{}}, "", nil + }, + ClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*mongodbatlas.Client, string, error) { + return &mongodbatlas.Client{}, "org-id", nil + }, + SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { + serverlessAPI := mockadmin.NewServerlessInstancesApi(t) + serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "abc123", "cluster0"). + Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI}) + + err := &admin.GenericOpenAPIError{} + err.SetModel(admin.ApiError{ErrorCode: pointer.MakePtr(atlas.ClusterInstanceFromServerlessAPI)}) + err.SetError("wrong API") + serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, err) + + return &admin.APIClient{ServerlessInstancesApi: serverlessAPI}, "org-id", nil + }, + }, }, "should fail when existing cluster is serverless instance but manifest defines a regular deployment": { deployment: &akov2.AtlasDeployment{ @@ -1189,6 +1217,31 @@ func TestChangeDeploymentType(t *testing.T) { StateName: "IDLE", }, }, + atlasProvider: &atlasmock.TestProvider{ + IsCloudGovFunc: func() bool { + return false + }, + IsSupportedFunc: func() bool { + return true + }, + SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { + return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{}}, "", nil + }, + ClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*mongodbatlas.Client, string, error) { + return &mongodbatlas.Client{}, "org-id", nil + }, + SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { + clusterAPI := mockadmin.NewClustersApi(t) + clusterAPI.EXPECT().GetCluster(mock.Anything, "abc123", "cluster0"). + Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) + + err := &admin.GenericOpenAPIError{} + err.SetModel(admin.ApiError{ErrorCode: pointer.MakePtr(atlas.ServerlessInstanceFromClusterAPI)}) + err.SetError("wrong API") + clusterAPI.EXPECT().GetClusterExecute(mock.Anything).Return(nil, nil, err) + return &admin.APIClient{ClustersApi: clusterAPI}, "org-id", nil + }, + }, }, } @@ -1238,59 +1291,12 @@ func TestChangeDeploymentType(t *testing.T) { WithIndex(dbUserProjectIndexer.Object(), dbUserProjectIndexer.Name(), dbUserProjectIndexer.Keys). Build() - atlasProvider := &atlasmock.TestProvider{ - IsCloudGovFunc: func() bool { - return false - }, - IsSupportedFunc: func() bool { - return true - }, - SdkSetClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*atlas.ClientSet, string, error) { - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.NonFlexInFlexAPI}) - - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) - return &atlas.ClientSet{SdkClient20241113001: &adminv20241113001.APIClient{FlexClustersApi: flexAPI}}, "", nil - }, - ClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*mongodbatlas.Client, string, error) { - return &mongodbatlas.Client{}, "org-id", nil - }, - SdkClientFunc: func(secretRef *client.ObjectKey, log *zap.SugaredLogger) (*admin.APIClient, string, error) { - clusterAPI := mockadmin.NewClustersApi(t) - if tt.deployment.IsAdvancedDeployment() { - clusterAPI.EXPECT().GetCluster(mock.Anything, "abc123", "cluster0"). - Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) - clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). - RunAndReturn( - func(request admin.GetClusterApiRequest) (*admin.AdvancedClusterDescription, *http.Response, error) { - if !tt.deployment.IsServerless() { - err := &admin.GenericOpenAPIError{} - err.SetModel(admin.ApiError{ErrorCode: pointer.MakePtr(atlas.ServerlessInstanceFromClusterAPI)}) - return nil, nil, err - } - return &admin.AdvancedClusterDescription{Name: pointer.MakePtr("cluster0")}, nil, nil - }, - ) - } - - serverlessAPI := mockadmin.NewServerlessInstancesApi(t) - if tt.deployment.IsServerless() { - serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "abc123", "cluster0"). - Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI}) - serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")). - Return(&admin.ServerlessInstanceDescription{Name: pointer.MakePtr("cluster0")}, nil, nil) - } - - return &admin.APIClient{ClustersApi: clusterAPI, ServerlessInstancesApi: serverlessAPI}, "org-id", nil - }, - } - r := &AtlasDeploymentReconciler{ AtlasReconciler: reconciler.AtlasReconciler{ Client: k8sClient, Log: logger.Sugar(), }, - AtlasProvider: atlasProvider, + AtlasProvider: tt.atlasProvider, EventRecorder: record.NewFakeRecorder(1), } result, err := r.Reconcile( @@ -1315,7 +1321,7 @@ func TestChangeDeploymentType(t *testing.T) { api.TrueCondition(api.ValidationSucceeded), api.FalseCondition(api.DeploymentReadyType). WithReason(string(workflow.Internal)). - WithMessageRegexp("regular deployment cannot be converted into a serverless deployment and vice-versa"), + WithMessageRegexp("wrong API"), }, tt.deployment.Status.Conditions, cmpopts.IgnoreFields(api.Condition{}, "LastTransitionTime"), diff --git a/internal/translation/deployment/deployment_test.go b/internal/translation/deployment/deployment_test.go index 9a5a81e669..f54bd5141d 100644 --- a/internal/translation/deployment/deployment_test.go +++ b/internal/translation/deployment/deployment_test.go @@ -79,23 +79,14 @@ func TestClusterExists(t *testing.T) { "should fail to assert a cluster exists in atlas": { deployment: geoShardedCluster(), apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, adminv20241113001.FlexClustersApi) { - clusterAPI := mockadmin.NewClustersApi(t) - clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0"). - Return(admin.GetClusterApiRequest{ApiService: clusterAPI}) - clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")). - Return(nil, nil, errors.New("failed to get cluster from atlas")) - - serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) - - err := &adminv20241113001.GenericOpenAPIError{} - err.SetModel(adminv20241113001.ApiError{ErrorCode: atlas.ClusterNotFound}) - flexAPI := mockadminv20241113001.NewFlexClustersApi(t) flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0"). Return(adminv20241113001.GetFlexClusterApiRequest{ApiService: flexAPI}) flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")). - Return(nil, nil, err) + Return(nil, nil, errors.New("failed to get cluster from atlas")) + clusterAPI := mockadmin.NewClustersApi(t) + serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t) return clusterAPI, serverlessInstanceAPI, flexAPI }, err: errors.New("failed to get cluster from atlas"), @@ -266,7 +257,7 @@ func TestClusterExists(t *testing.T) { clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker() service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, tt.gov) - result, err := service.ClusterExists(context.Background(), "project-id", tt.deployment.GetName()) + result, err := service.ClusterExists(context.Background(), "project-id", tt.deployment.GetDeploymentName()) require.Equal(t, tt.err, err) assert.Equal(t, tt.result, result) }) diff --git a/test/int/deployment_test.go b/test/int/deployment_test.go index c45c6db701..acb7feac54 100644 --- a/test/int/deployment_test.go +++ b/test/int/deployment_test.go @@ -1322,7 +1322,7 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment- deployment.Spec.FlexSpec.Tags = []*akov2.TagSpec{{Key: "test-1", Value: "value-1"}, {Key: "test-2", Value: "value-2"}} }) - doServerlessDeploymentStatusChecks() + doFlexDeploymentStatusChecks() atlasDeployment, _, _ := atlasClientv20241113001.FlexClustersApi. GetFlexCluster(context.Background(), createdProject.Status.ID, createdDeployment.Spec.FlexSpec.Name). Execute() From 161a172d05a061e9b1a8e753193395555b6c08ea Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Fri, 17 Jan 2025 16:12:17 +0100 Subject: [PATCH 32/33] fix linter --- .../atlasdeployment/atlasdeployment_controller_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go index aeb750f925..eb3d639106 100644 --- a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go +++ b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go @@ -1169,6 +1169,7 @@ func TestChangeDeploymentType(t *testing.T) { }, }, + //nolint:dupl atlasProvider: &atlasmock.TestProvider{ IsCloudGovFunc: func() bool { return false @@ -1217,6 +1218,7 @@ func TestChangeDeploymentType(t *testing.T) { StateName: "IDLE", }, }, + //nolint:dupl atlasProvider: &atlasmock.TestProvider{ IsCloudGovFunc: func() bool { return false From 19e283bb669bf514aac977790b8db8078f28245c Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Fri, 17 Jan 2025 16:14:57 +0000 Subject: [PATCH 33/33] Fix flex e2e --- test/e2e/flex_deployment_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/flex_deployment_test.go b/test/e2e/flex_deployment_test.go index 2fc59432e0..c3381be3a3 100644 --- a/test/e2e/flex_deployment_test.go +++ b/test/e2e/flex_deployment_test.go @@ -88,7 +88,7 @@ var _ = Describe("Flex", Label("flex"), func() { Name: name, ProviderSettings: &akov2.FlexProviderSettings{ BackingProviderName: "AWS", - RegionName: "EU_WEST_1", + RegionName: "US_EAST_1", }, }, },