diff --git a/api/v1/atlasdeployment_types.go b/api/v1/atlasdeployment_types.go
index 2e43c26992..340ce79a73 100644
--- a/api/v1/atlasdeployment_types.go
+++ b/api/v1/atlasdeployment_types.go
@@ -43,6 +43,7 @@ const (
// Only one of DeploymentSpec, AdvancedDeploymentSpec and ServerlessSpec should be defined.
// +kubebuilder:validation:XValidation:rule="(has(self.externalProjectRef) && !has(self.projectRef)) || (!has(self.externalProjectRef) && has(self.projectRef))",message="must define only one project reference through externalProjectRef or projectRef"
// +kubebuilder:validation:XValidation:rule="(has(self.externalProjectRef) && has(self.connectionSecret)) || !has(self.externalProjectRef)",message="must define a local connection secret when referencing an external project"
+// +kubebuilder:validation:XValidation:rule="!has(self.serverlessSpec) || (oldSelf.hasValue() && oldSelf.value().serverlessSpec != null)",optionalOldSelf=true,message="serverlessSpec cannot be added - serverless instances are deprecated",fieldPath=.serverlessSpec
type AtlasDeploymentSpec struct {
// ProjectReference is the dual external or kubernetes reference with access credentials
ProjectDualReference `json:",inline"`
diff --git a/api/v1/atlasdeployment_types_test.go b/api/v1/atlasdeployment_types_test.go
index af2576974e..0e942e5f02 100644
--- a/api/v1/atlasdeployment_types_test.go
+++ b/api/v1/atlasdeployment_types_test.go
@@ -49,6 +49,74 @@ func TestDeploymentCELChecks(t *testing.T) {
},
expectedErrors: []string{"spec.deploymentSpec.name: Invalid value: \"string\": Name cannot be modified after deployment creation"},
},
+ {
+ title: "Cannot add a serverless deployment",
+ old: nil,
+ obj: &AtlasDeployment{
+ Spec: AtlasDeploymentSpec{
+ ServerlessSpec: &ServerlessSpec{
+ Name: "my-serverless",
+ },
+ },
+ },
+ expectedErrors: []string{"spec.serverlessSpec: Invalid value: \"object\": serverlessSpec cannot be added - serverless instances are deprecated"},
+ },
+ {
+ title: "Can modify to a serverless deployment",
+ old: &AtlasDeployment{
+ Spec: AtlasDeploymentSpec{
+ ServerlessSpec: &ServerlessSpec{
+ Name: "my-serverless",
+ TerminationProtectionEnabled: false,
+ },
+ },
+ },
+ obj: &AtlasDeployment{
+ Spec: AtlasDeploymentSpec{
+ ServerlessSpec: &ServerlessSpec{
+ Name: "my-serverless",
+ TerminationProtectionEnabled: true,
+ },
+ },
+ },
+ },
+ {
+ title: "Existing serverless deployment can continue existing when not modified",
+ old: &AtlasDeployment{
+ Spec: AtlasDeploymentSpec{
+ ServerlessSpec: &ServerlessSpec{
+ Name: "my-serverless",
+ TerminationProtectionEnabled: false,
+ },
+ },
+ },
+ obj: &AtlasDeployment{
+ Spec: AtlasDeploymentSpec{
+ BackupScheduleRef: common.ResourceRefNamespaced{},
+ ServerlessSpec: &ServerlessSpec{
+ Name: "my-serverless",
+ TerminationProtectionEnabled: false,
+ },
+ },
+ },
+ },
+ {
+ title: "can migrate from serverless to flex cluster",
+ old: &AtlasDeployment{
+ Spec: AtlasDeploymentSpec{
+ ServerlessSpec: &ServerlessSpec{
+ Name: "my-serverless",
+ },
+ },
+ },
+ obj: &AtlasDeployment{
+ Spec: AtlasDeploymentSpec{
+ FlexSpec: &FlexSpec{
+ Name: "my-serverless",
+ },
+ },
+ },
+ },
} {
t.Run(tc.title, func(t *testing.T) {
// inject a project to avoid other CEL validations being hit
diff --git a/devbox.json b/devbox.json
index f649f62389..cb21bd5ed6 100644
--- a/devbox.json
+++ b/devbox.json
@@ -19,7 +19,7 @@
"operator-sdk": "1.36.1",
"shellcheck": "latest",
"golangci-lint": "2",
- "kubernetes-controller-tools": "0.17.2",
+ "kubernetes-controller-tools": "0.19.0",
"setup-envtest": "0.19.0",
"awscli2": "latest",
"docker-sbom": "latest",
diff --git a/devbox.lock b/devbox.lock
index 60f21439b8..237ee9a072 100644
--- a/devbox.lock
+++ b/devbox.lock
@@ -1189,51 +1189,51 @@
}
}
},
- "kubernetes-controller-tools@0.17.2": {
- "last_modified": "2025-03-23T05:31:05Z",
- "resolved": "github:NixOS/nixpkgs/dd613136ee91f67e5dba3f3f41ac99ae89c5406b#kubernetes-controller-tools",
+ "kubernetes-controller-tools@0.19.0": {
+ "last_modified": "2025-11-23T21:50:36Z",
+ "resolved": "github:NixOS/nixpkgs/ee09932cedcef15aaf476f9343d1dea2cb77e261#kubernetes-controller-tools",
"source": "devbox-search",
- "version": "0.17.2",
+ "version": "0.19.0",
"systems": {
"aarch64-darwin": {
"outputs": [
{
"name": "out",
- "path": "/nix/store/x2g121jdk7fdxb7vx964rrhbiwd0g0rm-controller-tools-0.17.2",
+ "path": "/nix/store/brz84pzrcnll7i85bpgil58ldlkwrngp-controller-tools-0.19.0",
"default": true
}
],
- "store_path": "/nix/store/x2g121jdk7fdxb7vx964rrhbiwd0g0rm-controller-tools-0.17.2"
+ "store_path": "/nix/store/brz84pzrcnll7i85bpgil58ldlkwrngp-controller-tools-0.19.0"
},
"aarch64-linux": {
"outputs": [
{
"name": "out",
- "path": "/nix/store/jaz48mw3pinfdw9gd8fng63gn7wwzmxy-controller-tools-0.17.2",
+ "path": "/nix/store/anb3mpv9m3dklylhqbsjh04iv70gn8vj-controller-tools-0.19.0",
"default": true
}
],
- "store_path": "/nix/store/jaz48mw3pinfdw9gd8fng63gn7wwzmxy-controller-tools-0.17.2"
+ "store_path": "/nix/store/anb3mpv9m3dklylhqbsjh04iv70gn8vj-controller-tools-0.19.0"
},
"x86_64-darwin": {
"outputs": [
{
"name": "out",
- "path": "/nix/store/3wdf34xlpff7m01ggzr7pb9f3w3cl95f-controller-tools-0.17.2",
+ "path": "/nix/store/jjm90vri9j4j2zacasrfkhny98vsh10n-controller-tools-0.19.0",
"default": true
}
],
- "store_path": "/nix/store/3wdf34xlpff7m01ggzr7pb9f3w3cl95f-controller-tools-0.17.2"
+ "store_path": "/nix/store/jjm90vri9j4j2zacasrfkhny98vsh10n-controller-tools-0.19.0"
},
"x86_64-linux": {
"outputs": [
{
"name": "out",
- "path": "/nix/store/xgppkdij5f73igwfp5as058fmh21wn9p-controller-tools-0.17.2",
+ "path": "/nix/store/mldi6bp7a0bdq5vjyfahay8h19f0wwch-controller-tools-0.19.0",
"default": true
}
],
- "store_path": "/nix/store/xgppkdij5f73igwfp5as058fmh21wn9p-controller-tools-0.17.2"
+ "store_path": "/nix/store/mldi6bp7a0bdq5vjyfahay8h19f0wwch-controller-tools-0.19.0"
}
}
},
diff --git a/docs/api-docs.md b/docs/api-docs.md
index 12d6b53d22..09a1160935 100644
--- a/docs/api-docs.md
+++ b/docs/api-docs.md
@@ -2755,7 +2755,7 @@ AtlasDeployment is the Schema for the atlasdeployments API
AtlasDeploymentSpec defines the desired state of AtlasDeployment.
Only one of DeploymentSpec, AdvancedDeploymentSpec and ServerlessSpec should be defined.
- Validations:
(has(self.externalProjectRef) && !has(self.projectRef)) || (!has(self.externalProjectRef) && has(self.projectRef)): must define only one project reference through externalProjectRef or projectRef(has(self.externalProjectRef) && has(self.connectionSecret)) || !has(self.externalProjectRef): must define a local connection secret when referencing an external project
+ Validations:(has(self.externalProjectRef) && !has(self.projectRef)) || (!has(self.externalProjectRef) && has(self.projectRef)): must define only one project reference through externalProjectRef or projectRef(has(self.externalProjectRef) && has(self.connectionSecret)) || !has(self.externalProjectRef): must define a local connection secret when referencing an external project!has(self.serverlessSpec) || (oldSelf.hasValue() && oldSelf.value().serverlessSpec != null): serverlessSpec cannot be added - serverless instances are deprecated
false |
diff --git a/internal/controller/atlasdatabaseuser/databaseuser.go b/internal/controller/atlasdatabaseuser/databaseuser.go
index 430d967ea1..7a9c22226a 100644
--- a/internal/controller/atlasdatabaseuser/databaseuser.go
+++ b/internal/controller/atlasdatabaseuser/databaseuser.go
@@ -66,7 +66,7 @@ func (r *AtlasDatabaseUserReconciler) handleDatabaseUser(ctx *workflow.Context,
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.AtlasAPIAccessNotConfigured, true, err)
}
dbUserService := dbuser.NewAtlasUsers(sdkClientSet.SdkClient20250312006.DatabaseUsersApi)
- deploymentService := deployment.NewAtlasDeployments(sdkClientSet.SdkClient20250312006.ClustersApi, sdkClientSet.SdkClient20250312006.ServerlessInstancesApi, sdkClientSet.SdkClient20250312006.GlobalClustersApi, sdkClientSet.SdkClient20250312006.FlexClustersApi, r.AtlasProvider.IsCloudGov())
+ deploymentService := deployment.NewAtlasDeployments(sdkClientSet.SdkClient20250312006.ClustersApi, sdkClientSet.SdkClient20250312006.GlobalClustersApi, sdkClientSet.SdkClient20250312006.FlexClustersApi, r.AtlasProvider.IsCloudGov())
atlasProject, err := r.ResolveProject(ctx.Context, sdkClientSet.SdkClient20250312006, atlasDatabaseUser)
if err != nil {
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.AtlasAPIAccessNotConfigured, true, err)
diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller.go b/internal/controller/atlasdeployment/atlasdeployment_controller.go
index a81e7cb35b..f9e3976cf1 100644
--- a/internal/controller/atlasdeployment/atlasdeployment_controller.go
+++ b/internal/controller/atlasdeployment/atlasdeployment_controller.go
@@ -141,7 +141,7 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ
}
workflowCtx.SdkClientSet = sdkClientSet
projectService := project.NewProjectAPIService(sdkClientSet.SdkClient20250312006.ProjectsApi)
- deploymentService := deployment.NewAtlasDeployments(sdkClientSet.SdkClient20250312006.ClustersApi, sdkClientSet.SdkClient20250312006.ServerlessInstancesApi, sdkClientSet.SdkClient20250312006.GlobalClustersApi, sdkClientSet.SdkClient20250312006.FlexClustersApi, r.AtlasProvider.IsCloudGov())
+ deploymentService := deployment.NewAtlasDeployments(sdkClientSet.SdkClient20250312006.ClustersApi, sdkClientSet.SdkClient20250312006.GlobalClustersApi, sdkClientSet.SdkClient20250312006.FlexClustersApi, r.AtlasProvider.IsCloudGov())
atlasProject, err := r.ResolveProject(workflowCtx.Context, sdkClientSet.SdkClient20250312006, atlasDeployment)
if err != nil {
return r.terminate(workflowCtx, workflow.AtlasAPIAccessNotConfigured, err)
@@ -176,10 +176,7 @@ func (r *AtlasDeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Requ
}
switch {
- case atlasDeployment.IsServerless():
- return r.handleServerlessInstance(workflowCtx, projectService, deploymentService, deploymentInAKO, deploymentInAtlas)
-
- case atlasDeployment.IsFlex():
+ case atlasDeployment.IsServerless(), atlasDeployment.IsFlex():
return r.handleFlexInstance(workflowCtx, projectService, deploymentService, deploymentInAKO, deploymentInAtlas)
case atlasDeployment.IsAdvancedDeployment():
diff --git a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go
index de21d08973..fd577b5132 100644
--- a/internal/controller/atlasdeployment/atlasdeployment_controller_test.go
+++ b/internal/controller/atlasdeployment/atlasdeployment_controller_test.go
@@ -465,13 +465,6 @@ func TestRegularClusterReconciliation(t *testing.T) {
flexAPI := mockadmin.NewFlexClustersApi(t)
- serverlessErr := &admin.GenericOpenAPIError{}
- serverlessErr.SetModel(admin.ApiError{ErrorCode: atlas.ClusterInstanceFromServerlessAPI})
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, project.ID(), mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, serverlessErr)
-
cloudBackupsAPI := mockadmin.NewCloudBackupsApi(t)
cloudBackupsAPI.EXPECT().GetBackupSchedule(mock.Anything, project.ID(), d.Spec.DeploymentSpec.Name).
Return(admin.GetBackupScheduleApiRequest{ApiService: cloudBackupsAPI})
@@ -502,13 +495,12 @@ func TestRegularClusterReconciliation(t *testing.T) {
return &atlas.ClientSet{
SdkClient20250312006: &admin.APIClient{
- FlexClustersApi: flexAPI,
- ClustersApi: clusterAPI,
- AtlasSearchApi: searchAPI,
- ServerlessInstancesApi: serverlessAPI,
- GlobalClustersApi: globalAPI,
- ProjectsApi: projectAPI,
- CloudBackupsApi: cloudBackupsAPI,
+ FlexClustersApi: flexAPI,
+ ClustersApi: clusterAPI,
+ AtlasSearchApi: searchAPI,
+ GlobalClustersApi: globalAPI,
+ ProjectsApi: projectAPI,
+ CloudBackupsApi: cloudBackupsAPI,
},
}, nil
},
@@ -594,38 +586,32 @@ func TestServerlessInstanceReconciliation(t *testing.T) {
Build()
atlasProvider := &atlasmock.TestProvider{
+ //nolint:dupl
SdkClientSetFunc: func(ctx context.Context, creds *atlas.Credentials, log *zap.SugaredLogger) (*atlas.ClientSet, error) {
+ clusterErr := &admin.GenericOpenAPIError{}
+ clusterErr.SetModel(admin.ApiError{ErrorCode: atlas.ServerlessInstanceFromClusterAPI})
clusterAPI := mockadmin.NewClustersApi(t)
+ clusterAPI.EXPECT().GetCluster(mock.Anything, "abc123", mock.Anything).
+ Return(admin.GetClusterApiRequest{ApiService: clusterAPI})
+ clusterAPI.EXPECT().GetClusterExecute(mock.Anything).Return(nil, nil, clusterErr)
flexAPI := mockadmin.NewFlexClustersApi(t)
-
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, project.ID(), mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")).
- Return(
- &admin.ServerlessInstanceDescription{
- GroupId: pointer.MakePtr(project.ID()),
- Name: pointer.MakePtr(d.GetDeploymentName()),
- ProviderSettings: admin.ServerlessProviderSettings{
- BackingProviderName: "AWS",
- ProviderName: pointer.MakePtr("SERVERLESS"),
- RegionName: "US_EAST_1",
- },
- ServerlessBackupOptions: &admin.ClusterServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: pointer.MakePtr(false),
- },
- StateName: pointer.MakePtr("IDLE"),
- TerminationProtectionEnabled: pointer.MakePtr(false),
+ flexAPI.EXPECT().GetFlexCluster(mock.Anything, "abc123", mock.Anything).
+ Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
+ flexAPI.EXPECT().GetFlexClusterExecute(mock.Anything).Return(
+ &admin.FlexClusterDescription20241113{
+ GroupId: pointer.MakePtr("abc123"),
+ Name: pointer.MakePtr("test-serverless-instance"),
+ ProviderSettings: admin.FlexProviderSettings20241113{
+ BackingProviderName: pointer.MakePtr("AWS"),
+ ProviderName: pointer.MakePtr("FLEX"),
+ RegionName: pointer.MakePtr("US_EAST_1"),
},
- &http.Response{},
- nil,
- )
-
- speClient := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speClient.EXPECT().ListServerlessPrivateEndpoints(mock.Anything, project.ID(), d.GetDeploymentName()).
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speClient})
- speClient.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return(nil, &http.Response{}, nil)
+ StateName: pointer.MakePtr("IDLE"),
+ TerminationProtectionEnabled: pointer.MakePtr(false),
+ },
+ nil,
+ nil,
+ )
projectAPI := mockadmin.NewProjectsApi(t)
projectAPI.EXPECT().GetProjectByName(mock.Anything, "MyProject").
@@ -635,11 +621,9 @@ func TestServerlessInstanceReconciliation(t *testing.T) {
return &atlas.ClientSet{
SdkClient20250312006: &admin.APIClient{
- FlexClustersApi: flexAPI,
- ClustersApi: clusterAPI,
- ServerlessInstancesApi: serverlessAPI,
- ServerlessPrivateEndpointsApi: speClient,
- ProjectsApi: projectAPI,
+ FlexClustersApi: flexAPI,
+ ClustersApi: clusterAPI,
+ ProjectsApi: projectAPI,
},
}, nil
},
@@ -755,13 +739,6 @@ func TestFlexClusterReconciliation(t *testing.T) {
clusterAPI.EXPECT().GetClusterExecute(mock.AnythingOfType("admin.GetClusterApiRequest")).
Return(nil, nil, clusterErr)
- serverlessErr := &admin.GenericOpenAPIError{}
- serverlessErr.SetModel(admin.ApiError{ErrorCode: atlas.ClusterInstanceFromServerlessAPI})
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, project.ID(), mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, serverlessErr)
-
projectAPI := mockadmin.NewProjectsApi(t)
projectAPI.EXPECT().GetProjectByName(mock.Anything, "MyProject").
Return(admin.GetProjectByNameApiRequest{ApiService: projectAPI})
@@ -770,10 +747,9 @@ func TestFlexClusterReconciliation(t *testing.T) {
return &atlas.ClientSet{
SdkClient20250312006: &admin.APIClient{
- FlexClustersApi: flexAPI,
- ClustersApi: clusterAPI,
- ServerlessInstancesApi: serverlessAPI,
- ProjectsApi: projectAPI,
+ FlexClustersApi: flexAPI,
+ ClustersApi: clusterAPI,
+ ProjectsApi: projectAPI,
},
}, nil
},
@@ -903,13 +879,6 @@ func TestDeletionReconciliation(t *testing.T) {
SdkClientSetFunc: func(ctx context.Context, creds *atlas.Credentials, log *zap.SugaredLogger) (*atlas.ClientSet, error) {
flexAPI := mockadmin.NewFlexClustersApi(t)
- serverlessErr := &admin.GenericOpenAPIError{}
- serverlessErr.SetModel(admin.ApiError{ErrorCode: atlas.ClusterInstanceFromServerlessAPI})
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, project.ID(), mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, serverlessErr)
-
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetCluster(mock.Anything, project.ID(), mock.Anything).
Return(admin.GetClusterApiRequest{ApiService: clusterAPI})
@@ -954,10 +923,9 @@ func TestDeletionReconciliation(t *testing.T) {
return &atlas.ClientSet{
SdkClient20250312006: &admin.APIClient{
- FlexClustersApi: flexAPI,
- ClustersApi: clusterAPI,
- ServerlessInstancesApi: serverlessAPI,
- ProjectsApi: projectAPI,
+ FlexClustersApi: flexAPI,
+ ClustersApi: clusterAPI,
+ ProjectsApi: projectAPI,
},
}, nil
},
@@ -1288,15 +1256,6 @@ func TestChangeDeploymentType(t *testing.T) {
return true
},
SdkClientSetFunc: func(ctx context.Context, creds *atlas.Credentials, log *zap.SugaredLogger) (*atlas.ClientSet, error) {
- flexAPI := mockadmin.NewFlexClustersApi(t)
-
- serverlessErr := &admin.GenericOpenAPIError{}
- serverlessErr.SetModel(admin.ApiError{ErrorCode: atlas.ClusterInstanceFromServerlessAPI})
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "abc123", mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, serverlessErr)
-
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetCluster(mock.Anything, "abc123", mock.Anything).
Return(admin.GetClusterApiRequest{ApiService: clusterAPI})
@@ -1337,15 +1296,13 @@ func TestChangeDeploymentType(t *testing.T) {
return &atlas.ClientSet{
SdkClient20250312006: &admin.APIClient{
- FlexClustersApi: flexAPI,
- ServerlessInstancesApi: serverlessAPI,
- ClustersApi: clusterAPI,
- ProjectsApi: projectAPI,
+ ClustersApi: clusterAPI,
+ ProjectsApi: projectAPI,
},
}, nil
},
},
- errorMsg: "deployment in Atlas is not a serverless cluster",
+ errorMsg: "deployment in Atlas is not a flex cluster",
},
"should fail when existing cluster is regular but manifest defines a flex instance": { //nolint:dupl
deployment: &akov2.AtlasDeployment{
@@ -1381,15 +1338,6 @@ func TestChangeDeploymentType(t *testing.T) {
return true
},
SdkClientSetFunc: func(ctx context.Context, creds *atlas.Credentials, log *zap.SugaredLogger) (*atlas.ClientSet, error) {
- flexAPI := mockadmin.NewFlexClustersApi(t)
-
- serverlessErr := &admin.GenericOpenAPIError{}
- serverlessErr.SetModel(admin.ApiError{ErrorCode: atlas.ClusterInstanceFromServerlessAPI})
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "abc123", mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, serverlessErr)
-
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetCluster(mock.Anything, "abc123", mock.Anything).
Return(admin.GetClusterApiRequest{ApiService: clusterAPI})
@@ -1430,17 +1378,15 @@ func TestChangeDeploymentType(t *testing.T) {
return &atlas.ClientSet{
SdkClient20250312006: &admin.APIClient{
- FlexClustersApi: flexAPI,
- ServerlessInstancesApi: serverlessAPI,
- ClustersApi: clusterAPI,
- ProjectsApi: projectAPI,
+ ClustersApi: clusterAPI,
+ ProjectsApi: projectAPI,
},
}, nil
},
},
errorMsg: "deployment in Atlas is not a flex cluster",
},
- "should fail when existing cluster is serverless instance but manifest defines a regular deployment": {
+ "should fail when existing cluster is flex instance but manifest defines a regular deployment": {
deployment: &akov2.AtlasDeployment{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster0",
@@ -1470,23 +1416,23 @@ func TestChangeDeploymentType(t *testing.T) {
return true
},
SdkClientSetFunc: func(ctx context.Context, creds *atlas.Credentials, log *zap.SugaredLogger) (*atlas.ClientSet, error) {
+ clusterErr := &admin.GenericOpenAPIError{}
+ clusterErr.SetModel(admin.ApiError{ErrorCode: atlas.FlexFromClusterAPI})
clusterAPI := mockadmin.NewClustersApi(t)
+ clusterAPI.EXPECT().GetCluster(mock.Anything, "abc123", mock.Anything).
+ Return(admin.GetClusterApiRequest{ApiService: clusterAPI})
+ clusterAPI.EXPECT().GetClusterExecute(mock.Anything).Return(nil, nil, clusterErr)
flexAPI := mockadmin.NewFlexClustersApi(t)
-
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "abc123", mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(
- &admin.ServerlessInstanceDescription{
+ flexAPI.EXPECT().GetFlexCluster(mock.Anything, "abc123", mock.Anything).
+ Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
+ flexAPI.EXPECT().GetFlexClusterExecute(mock.Anything).Return(
+ &admin.FlexClusterDescription20241113{
GroupId: pointer.MakePtr("abc123"),
Name: pointer.MakePtr("cluster0"),
- ProviderSettings: admin.ServerlessProviderSettings{
- BackingProviderName: "AWS",
- ProviderName: pointer.MakePtr("SERVERLESS"),
- RegionName: "US_EAST_1",
- },
- ServerlessBackupOptions: &admin.ClusterServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: pointer.MakePtr(false),
+ ProviderSettings: admin.FlexProviderSettings20241113{
+ BackingProviderName: pointer.MakePtr("AWS"),
+ ProviderName: pointer.MakePtr("FLEX"),
+ RegionName: pointer.MakePtr("US_EAST_1"),
},
StateName: pointer.MakePtr("IDLE"),
TerminationProtectionEnabled: pointer.MakePtr(false),
@@ -1503,10 +1449,9 @@ func TestChangeDeploymentType(t *testing.T) {
return &atlas.ClientSet{
SdkClient20250312006: &admin.APIClient{
- ClustersApi: clusterAPI,
- FlexClustersApi: flexAPI,
- ServerlessInstancesApi: serverlessAPI,
- ProjectsApi: projectAPI,
+ ClustersApi: clusterAPI,
+ FlexClustersApi: flexAPI,
+ ProjectsApi: projectAPI,
},
}, nil
},
diff --git a/internal/controller/atlasdeployment/serverless_deployment.go b/internal/controller/atlasdeployment/serverless_deployment.go
deleted file mode 100644
index 420e092bac..0000000000
--- a/internal/controller/atlasdeployment/serverless_deployment.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2025 MongoDB Inc
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package atlasdeployment
-
-import (
- "errors"
- "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) 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"))
- }
-
- var atlasServerless *deployment.Serverless
- if atlasServerless, ok = atlasDeployment.(*deployment.Serverless); atlasDeployment != nil && !ok {
- return r.terminate(ctx, workflow.Internal, errors.New("deployment in Atlas is not a serverless cluster"))
- }
-
- 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)
- }
-
- atlasServerless = newServerlessDeployment.(*deployment.Serverless)
- }
-
- switch atlasServerless.GetState() {
- case status.StateIDLE:
- 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, akoServerless.GetCustomResource(), atlasServerless, workflow.DeploymentUpdating, "deployment is updating")
- }
-
- 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, akoServerless.GetProjectID(), akoServerless.GetCustomResource())
-
- switch {
- case result.IsInProgress():
- 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, akoServerless.GetCustomResource(), r.Client)
- if err != nil {
- return r.terminate(ctx, workflow.Internal, err)
- }
-
- return r.ready(ctx, akoServerless, atlasServerless)
- case status.StateCREATING:
- return r.inProgress(ctx, akoServerless.GetCustomResource(), atlasServerless, workflow.DeploymentCreating, "deployment is provisioning")
- case status.StateUPDATING, status.StateREPAIRING:
- 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", atlasServerless.GetState()))
- }
-}
diff --git a/internal/controller/atlasdeployment/serverless_deployment_test.go b/internal/controller/atlasdeployment/serverless_deployment_test.go
deleted file mode 100644
index 723aa41056..0000000000
--- a/internal/controller/atlasdeployment/serverless_deployment_test.go
+++ /dev/null
@@ -1,972 +0,0 @@
-// Copyright 2025 MongoDB Inc
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package atlasdeployment
-
-import (
- "context"
- "errors"
- "net/http"
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "github.com/google/go-cmp/cmp/cmpopts"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "github.com/stretchr/testify/require"
- "go.mongodb.org/atlas-sdk/v20250312006/admin"
- "go.mongodb.org/atlas-sdk/v20250312006/mockadmin"
- "go.uber.org/zap/zaptest"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
-
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/api"
- akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/common"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/provider"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/atlas"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/reconciler"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/workflow"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/indexer"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/mocks/translation"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/deployment"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/project"
-)
-
-func TestHandleServerlessInstance(t *testing.T) {
- type workflowRes struct {
- res ctrl.Result
- err error
- }
- tests := map[string]struct {
- atlasDeployment *akov2.AtlasDeployment
- deploymentInAtlas *deployment.Serverless
- deploymentService func() deployment.AtlasDeploymentsService
- sdkMock func() *admin.APIClient
- expectedResult workflowRes
- expectedConditions []api.Condition
- }{
- "fail to create a new serverless instance in atlas": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- deploymentInAtlas: nil,
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
- service.EXPECT().CreateDeployment(context.Background(), mock.AnythingOfType("*deployment.Serverless")).
- Return(nil, errors.New("failed to create serverless instance"))
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- return &admin.APIClient{}
- },
- expectedResult: workflowRes{
- err: errors.New("failed to create serverless instance"),
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.DeploymentNotCreatedInAtlas)).
- WithMessageRegexp("failed to create serverless instance"),
- },
- },
- "create a new serverless instance in atlas": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- deploymentInAtlas: nil,
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
- service.EXPECT().CreateDeployment(context.Background(), mock.AnythingOfType("*deployment.Serverless")).
- Return(
- &deployment.Serverless{
- ProjectID: "project-id",
- State: "CREATING",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- nil,
- )
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- return &admin.APIClient{}
- },
- expectedResult: workflowRes{
- res: ctrl.Result{RequeueAfter: workflow.DefaultRetry},
- err: nil,
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.DeploymentCreating)).
- WithMessageRegexp("deployment is provisioning"),
- },
- },
- "fail to update a serverless instance in atlas": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "IDLE",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
- service.EXPECT().UpdateDeployment(context.Background(), mock.AnythingOfType("*deployment.Serverless")).
- Return(nil, errors.New("failed to update serverless instance"))
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- return &admin.APIClient{}
- },
- expectedResult: workflowRes{
- err: errors.New("failed to update serverless instance"),
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.DeploymentNotUpdatedInAtlas)).
- WithMessageRegexp("failed to update serverless instance"),
- },
- },
- "update a serverless instance in atlas": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "IDLE",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
- service.EXPECT().UpdateDeployment(context.Background(), mock.AnythingOfType("*deployment.Serverless")).
- Return(
- &deployment.Serverless{
- ProjectID: "project-id",
- State: "UPDATING",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- nil,
- )
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- return &admin.APIClient{}
- },
- expectedResult: workflowRes{
- res: ctrl.Result{RequeueAfter: workflow.DefaultRetry},
- err: nil,
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.DeploymentUpdating)).
- WithMessageRegexp("deployment is updating"),
- },
- },
- "serverless instance is updating in atlas": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "UPDATING",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- return &admin.APIClient{}
- },
- expectedResult: workflowRes{
- res: ctrl.Result{RequeueAfter: workflow.DefaultRetry},
- err: nil,
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.DeploymentUpdating)).
- WithMessageRegexp("deployment is updating"),
- },
- },
- "update tags of a serverless instance in atlas": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- {
- Key: "newTag",
- Value: "newValue",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "IDLE",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
- service.EXPECT().UpdateDeployment(context.Background(), mock.AnythingOfType("*deployment.Serverless")).
- Return(
- &deployment.Serverless{
- ProjectID: "project-id",
- State: "UPDATING",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- {
- Key: "newTag",
- Value: "newValue",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- nil,
- )
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- return &admin.APIClient{}
- },
- expectedResult: workflowRes{
- res: ctrl.Result{RequeueAfter: workflow.DefaultRetry},
- err: nil,
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.DeploymentUpdating)).
- WithMessageRegexp("deployment is updating"),
- },
- },
- "serverless instance fails when private endpoints fails": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ProjectDualReference: akov2.ProjectDualReference{
- ProjectRef: &common.ResourceRefNamespaced{
- Name: "my-project",
- },
- },
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe1",
- CloudProviderEndpointID: "arn-12345",
- },
- },
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "IDLE",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- speClient := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speClient.EXPECT().ListServerlessPrivateEndpoints(context.Background(), "project-id", "instance0").
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speClient})
- speClient.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return(nil, &http.Response{}, errors.New("failed to list private endpoints"))
-
- return &admin.APIClient{ServerlessPrivateEndpointsApi: speClient}
- },
- expectedResult: workflowRes{
- err: errors.New("unable to retrieve list of serverless private endpoints from Atlas: failed to list private endpoints"),
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.ServerlessPrivateEndpointReadyType).
- WithReason(string(workflow.ServerlessPrivateEndpointFailed)).
- WithMessageRegexp("unable to retrieve list of serverless private endpoints from Atlas: failed to list private endpoints"),
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.ServerlessPrivateEndpointFailed)).
- WithMessageRegexp("unable to retrieve list of serverless private endpoints from Atlas: failed to list private endpoints"),
- },
- },
- "serverless flex instance fails when private endpoints are set": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ProjectDualReference: akov2.ProjectDualReference{
- ProjectRef: &common.ResourceRefNamespaced{
- Name: "my-project",
- },
- },
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe1",
- CloudProviderEndpointID: "arn-12345",
- },
- },
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "IDLE",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- mockError := &admin.GenericOpenAPIError{}
- model := *admin.NewApiErrorWithDefaults()
- model.SetErrorCode("NOT_SERVERLESS_TENANT_CLUSTER")
- mockError.SetModel(model)
-
- speClient := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speClient.EXPECT().ListServerlessPrivateEndpoints(context.Background(), "project-id", "instance0").
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speClient})
- speClient.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return(nil, &http.Response{}, mockError)
-
- return &admin.APIClient{ServerlessPrivateEndpointsApi: speClient}
- },
- expectedResult: workflowRes{
- err: errors.New("serverless private endpoints are not supported: "),
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.ServerlessPrivateEndpointReadyType).
- WithReason(string(workflow.ServerlessPrivateEndpointFailed)).
- WithMessageRegexp("serverless private endpoints are not supported: "),
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.ServerlessPrivateEndpointFailed)).
- WithMessageRegexp("serverless private endpoints are not supported: "),
- },
- },
- "serverless instance is updating when private endpoints are in progress": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ProjectDualReference: akov2.ProjectDualReference{
- ProjectRef: &common.ResourceRefNamespaced{
- Name: "my-project",
- },
- },
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe1",
- CloudProviderEndpointID: "arn-12345",
- },
- },
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "IDLE",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- speClient := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speClient.EXPECT().ListServerlessPrivateEndpoints(context.Background(), "project-id", "instance0").
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speClient})
- speClient.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return(nil, &http.Response{}, nil)
-
- speClient.EXPECT().CreateServerlessPrivateEndpoint(context.Background(), "project-id", "instance0", mock.AnythingOfType("*admin.ServerlessTenantCreateRequest")).
- Return(admin.CreateServerlessPrivateEndpointApiRequest{ApiService: speClient})
- speClient.EXPECT().CreateServerlessPrivateEndpointExecute(mock.AnythingOfType("admin.CreateServerlessPrivateEndpointApiRequest")).
- Return(&admin.ServerlessTenantEndpoint{}, &http.Response{}, nil)
-
- return &admin.APIClient{ServerlessPrivateEndpointsApi: speClient}
- },
- expectedResult: workflowRes{
- res: ctrl.Result{RequeueAfter: workflow.DefaultRetry},
- err: nil,
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.ServerlessPrivateEndpointReadyType).
- WithReason(string(workflow.ServerlessPrivateEndpointInProgress)).
- WithMessageRegexp("Waiting serverless private endpoint to be configured"),
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.ServerlessPrivateEndpointInProgress)).
- WithMessageRegexp("Waiting serverless private endpoint to be configured"),
- },
- },
- "serverless instance is ready in atlas": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ProjectDualReference: akov2.ProjectDualReference{
- ProjectRef: &common.ResourceRefNamespaced{
- Name: "my-project",
- },
- },
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "IDLE",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- service := translation.NewAtlasDeploymentsServiceMock(t)
-
- return service
- },
- sdkMock: func() *admin.APIClient {
- speClient := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speClient.EXPECT().ListServerlessPrivateEndpoints(context.Background(), "project-id", "instance0").
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speClient})
- speClient.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return(nil, &http.Response{}, nil)
-
- return &admin.APIClient{ServerlessPrivateEndpointsApi: speClient}
- },
- expectedResult: workflowRes{
- res: ctrl.Result{},
- err: nil,
- },
- expectedConditions: []api.Condition{
- api.TrueCondition(api.DeploymentReadyType),
- api.TrueCondition(api.ReadyType).
- WithMessageRegexp("WARNING: Serverless is deprecated. See https://dochub.mongodb.org/core/atlas-flex-migration for details."),
- },
- },
- "serverless instance has an unknown state": {
- atlasDeployment: &akov2.AtlasDeployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance0",
- Namespace: "default",
- },
- Spec: akov2.AtlasDeploymentSpec{
- ProjectDualReference: akov2.ProjectDualReference{
- ProjectRef: &common.ResourceRefNamespaced{
- Name: "my-project",
- },
- },
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- deploymentInAtlas: &deployment.Serverless{
- ProjectID: "project-id",
- State: "NEW_UNKNOWN_STATE",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderServerless,
- BackingProviderName: "AWS",
- RegionName: "us-east-1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "test",
- Value: "e2e",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: false,
- },
- TerminationProtectionEnabled: true,
- },
- },
- deploymentService: func() deployment.AtlasDeploymentsService {
- return translation.NewAtlasDeploymentsServiceMock(t)
- },
- sdkMock: func() *admin.APIClient {
- return &admin.APIClient{}
- },
- expectedResult: workflowRes{
- err: errors.New("unknown deployment state: NEW_UNKNOWN_STATE"),
- },
- expectedConditions: []api.Condition{
- api.FalseCondition(api.DeploymentReadyType).
- WithReason(string(workflow.Internal)).
- WithMessageRegexp("unknown deployment state: NEW_UNKNOWN_STATE"),
- },
- },
- }
-
- for name, tt := range tests {
- t.Run(name, func(t *testing.T) {
- ctx := context.Background()
- logger := zaptest.NewLogger(t)
- testScheme := runtime.NewScheme()
- require.NoError(t, akov2.AddToScheme(testScheme))
- dbUserProjectIndexer := indexer.NewAtlasDatabaseUserByProjectIndexer(ctx, nil, logger)
- k8sClient := fake.NewClientBuilder().
- WithScheme(testScheme).
- WithObjects(tt.atlasDeployment).
- WithIndex(dbUserProjectIndexer.Object(), dbUserProjectIndexer.Name(), dbUserProjectIndexer.Keys).
- Build()
- reconciler := &AtlasDeploymentReconciler{
- AtlasReconciler: reconciler.AtlasReconciler{
- Client: k8sClient,
- Log: logger.Sugar(),
- },
- }
- workflowCtx := &workflow.Context{
- Context: ctx,
- Log: logger.Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: tt.sdkMock(),
- },
- }
-
- deploymentInAKO := deployment.NewDeployment("project-id", tt.atlasDeployment).(*deployment.Serverless)
- var projectService project.ProjectService
- result, err := reconciler.handleServerlessInstance(workflowCtx, projectService, tt.deploymentService(), deploymentInAKO, tt.deploymentInAtlas)
- //require.NoError(t, err)
- assert.Equal(t, tt.expectedResult, workflowRes{
- res: result,
- err: err,
- })
- assert.True(
- t,
- cmp.Equal(
- tt.expectedConditions,
- workflowCtx.Conditions(),
- cmpopts.IgnoreFields(api.Condition{}, "LastTransitionTime"),
- ),
- )
- })
- }
-}
diff --git a/internal/controller/atlasdeployment/serverless_private_endpoint.go b/internal/controller/atlasdeployment/serverless_private_endpoint.go
deleted file mode 100644
index 3bc5d7aabf..0000000000
--- a/internal/controller/atlasdeployment/serverless_private_endpoint.go
+++ /dev/null
@@ -1,311 +0,0 @@
-// Copyright 2025 MongoDB Inc
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package atlasdeployment
-
-import (
- "errors"
- "fmt"
-
- "go.mongodb.org/atlas-sdk/v20250312006/admin"
-
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/api"
- akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/provider"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/status"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/workflow"
-)
-
-// Status transitions:
-// RESERVATION_REQUESTED -> RESERVED -> INITIATING -> AVAILABLE -> DELETING
-// I assume FAILED state can be reach from any other state transition
-const (
- SPEStatusDeleting = "DELETING"
- SPEStatusReserved = "RESERVED"
- SPEStatusAvailable = "AVAILABLE"
-)
-
-func ensureServerlessPrivateEndpoints(service *workflow.Context, projectID string, deployment *akov2.AtlasDeployment) workflow.DeprecatedResult {
- if deployment == nil || deployment.Spec.ServerlessSpec == nil {
- return workflow.Terminate(workflow.Internal, errors.New("serverless deployment spec is empty"))
- }
-
- deploymentSpec := deployment.Spec.ServerlessSpec
-
- if isGCPWithPrivateEndpoints(deploymentSpec) {
- return workflow.Terminate(workflow.AtlasUnsupportedFeature, errors.New("serverless private endpoints are not supported for GCP"))
- }
-
- if isGCPWithoutPrivateEndpoints(deploymentSpec) {
- return workflow.OK()
- }
-
- finished, err := syncServerlessPrivateEndpoints(service, projectID, deploymentSpec)
- var result workflow.DeprecatedResult
- switch {
- case err != nil:
- result = workflow.Terminate(workflow.ServerlessPrivateEndpointFailed, err)
- case err == nil && !finished:
- result = workflow.InProgress(workflow.ServerlessPrivateEndpointInProgress, "Waiting serverless private endpoint to be configured")
- default:
- result = workflow.OK()
- }
-
- switch len(deploymentSpec.PrivateEndpoints) {
- case 0:
- service.UnsetCondition(api.ServerlessPrivateEndpointReadyType)
- default:
- service.SetConditionFromResult(api.ServerlessPrivateEndpointReadyType, result)
- }
-
- return result
-}
-
-func syncServerlessPrivateEndpoints(service *workflow.Context, projectID string, deployment *akov2.ServerlessSpec) (bool, error) {
- service.Log.Debugf("Syncing serverless private endpoints for deployment %s", deployment.Name)
-
- atlasPrivateEndpoints, err := listServerlessPrivateEndpoints(service, projectID, deployment.Name)
- // This is a shimmed flex cluster, if there are private serverless endpoints configured, we have to return an error.
- if admin.IsErrorCode(err, "NOT_SERVERLESS_TENANT_CLUSTER") {
- if len(deployment.PrivateEndpoints) > 0 {
- return false, fmt.Errorf("serverless private endpoints are not supported: %w", err)
- }
- return true, nil
- }
-
- if err != nil {
- return false, fmt.Errorf("unable to retrieve list of serverless private endpoints from Atlas: %w", err)
- }
-
- toCreate, toUpdate, toDelete := sortTasks(deployment.PrivateEndpoints, atlasPrivateEndpoints)
- speStatusMap := newSPEStatusMap(atlasPrivateEndpoints)
-
- service.Log.Debugf("Creating %d serverless private endpoints for deployment %s", len(toCreate), deployment.Name)
- for i := range toCreate {
- privateEndpointCreate := toCreate[i]
- service.Log.Debugf("Creating serverless private endpoint %s", privateEndpointCreate.Name)
- atlasPrivateEndpoint, err := createServerLessPrivateEndpoint(service, projectID, deployment.Name, &privateEndpointCreate)
- if err != nil {
- return false, fmt.Errorf("unable to create serverless private endpoint on Atlas: %w", err)
- }
-
- speStatusMap[privateEndpointCreate.Name] = speStatusFromAtlas(atlasPrivateEndpoint)
- }
-
- service.Log.Debugf("Connecting %d serverless private endpoints for deployment %s", len(toUpdate), deployment.Name)
- for i := range toUpdate {
- privateEndpointUpdate := toUpdate[i]
- service.Log.Debugf("Connecting serverless private endpoint %s", privateEndpointUpdate.Name)
- latestPEStatus := speStatusMap[privateEndpointUpdate.Name]
- atlasPrivateEndpoint, err := updateServerLessPrivateEndpoint(service, projectID, deployment.Name, latestPEStatus.ID, latestPEStatus.ProviderName, &privateEndpointUpdate)
- if err != nil {
- return false, fmt.Errorf("unable to update/connect serverless private endpoint on Atlas: %w", err)
- }
-
- speStatusMap[privateEndpointUpdate.Name] = speStatusFromAtlas(atlasPrivateEndpoint)
- }
-
- service.Log.Debugf("Deleting %d serverless private endpoints for deployment %s", len(toDelete), deployment.Name)
- for _, privateEndpointDelete := range toDelete {
- service.Log.Debugf("Deleting serverless private endpoint with ID %s", privateEndpointDelete)
- err = deleteServerLessPrivateEndpoint(service, projectID, deployment.Name, privateEndpointDelete.GetId())
- if err != nil {
- return false, fmt.Errorf("unable to delete serverless private endpoint on Atlas: %w", err)
- }
-
- // Serverless private endpoints first go through DELETING state before they are gone
- speStatus := speStatusMap[privateEndpointDelete.GetComment()]
- speStatus.Status = SPEStatusDeleting
- speStatusMap[privateEndpointDelete.GetComment()] = speStatus
- }
-
- speStatuses := make([]status.ServerlessPrivateEndpoint, 0, len(speStatusMap))
- for _, speStatus := range speStatusMap {
- speStatuses = append(speStatuses, speStatus)
- }
- service.EnsureStatusOption(status.AtlasDeploymentSPEOption(speStatuses))
-
- return areSPEsAvailable(speStatuses), nil
-}
-
-func isGCPWithPrivateEndpoints(deployment *akov2.ServerlessSpec) bool {
- if provider.ProviderName(deployment.ProviderSettings.BackingProviderName) == provider.ProviderGCP &&
- len(deployment.PrivateEndpoints) > 0 {
- return true
- }
-
- return false
-}
-
-func isGCPWithoutPrivateEndpoints(deployment *akov2.ServerlessSpec) bool {
- if provider.ProviderName(deployment.ProviderSettings.BackingProviderName) == provider.ProviderGCP &&
- len(deployment.PrivateEndpoints) == 0 {
- return true
- }
-
- return false
-}
-
-func listServerlessPrivateEndpoints(service *workflow.Context, projectID, deploymentName string) ([]admin.ServerlessTenantEndpoint, error) {
- // this endpoint does not offer paginated responses
- privateEndpoints, _, err := service.SdkClientSet.SdkClient20250312006.ServerlessPrivateEndpointsApi.
- ListServerlessPrivateEndpoints(service.Context, projectID, deploymentName).
- Execute()
-
- return privateEndpoints, err
-}
-
-func createServerLessPrivateEndpoint(service *workflow.Context, projectID, deploymentName string, privateEndpoint *akov2.ServerlessPrivateEndpoint) (*admin.ServerlessTenantEndpoint, error) {
- request := admin.ServerlessTenantCreateRequest{
- Comment: &privateEndpoint.Name,
- }
-
- atlasPrivateEndpoint, _, err := service.SdkClientSet.SdkClient20250312006.ServerlessPrivateEndpointsApi.
- CreateServerlessPrivateEndpoint(service.Context, projectID, deploymentName, &request).
- Execute()
-
- return atlasPrivateEndpoint, err
-}
-
-func updateServerLessPrivateEndpoint(service *workflow.Context, projectID, deploymentName, endpointID, providerName string, privateEndpoint *akov2.ServerlessPrivateEndpoint) (*admin.ServerlessTenantEndpoint, error) {
- // we don't allow update name (comment) once it's used as identifier
- request := admin.ServerlessTenantEndpointUpdate{
- ProviderName: providerName,
- CloudProviderEndpointId: &privateEndpoint.CloudProviderEndpointID,
- }
-
- // when provider is Azure we expect IP Address to be set
- if privateEndpoint.PrivateEndpointIPAddress != "" {
- request.PrivateEndpointIpAddress = &privateEndpoint.PrivateEndpointIPAddress
- }
-
- atlasPrivateEndpoint, _, err := service.SdkClientSet.SdkClient20250312006.ServerlessPrivateEndpointsApi.
- UpdateServerlessPrivateEndpoint(service.Context, projectID, deploymentName, endpointID, &request).
- Execute()
-
- return atlasPrivateEndpoint, err
-}
-
-func deleteServerLessPrivateEndpoint(service *workflow.Context, projectID, deploymentName, endpointID string) error {
- _, err := service.SdkClientSet.SdkClient20250312006.ServerlessPrivateEndpointsApi.
- DeleteServerlessPrivateEndpoint(service.Context, projectID, deploymentName, endpointID).
- Execute()
-
- return err
-}
-
-// sortTasks Build and return all the operations pending to reconcile
-// There are 3 possible operations:
-// CREATE: A private endpoint with a given name doesn't exist on Atlas
-// UPDATE: A private endpoint with a given name exists on Atlas with status RESERVED (waiting to be connected)
-// DELETE: A private endpoint with a given name exists on Atlas, but it's not describe in Kubernetes resource
-//
-// A private endpoint is not expected to have duplicated name as validation happens at very beginning of the
-// reconciliation. See validate.serverlessPrivateEndpoints
-func sortTasks(
- privateEndpoints []akov2.ServerlessPrivateEndpoint,
- atlasPrivateEndpoints []admin.ServerlessTenantEndpoint,
-) ([]akov2.ServerlessPrivateEndpoint, []akov2.ServerlessPrivateEndpoint, []admin.ServerlessTenantEndpoint) {
- toCreate := make([]akov2.ServerlessPrivateEndpoint, 0, len(privateEndpoints))
- toUpdate := make([]akov2.ServerlessPrivateEndpoint, 0, len(privateEndpoints))
- toDelete := make([]admin.ServerlessTenantEndpoint, 0, len(atlasPrivateEndpoints))
-
- privateEndpointsByName := map[string]*akov2.ServerlessPrivateEndpoint{}
- for i := range privateEndpoints {
- privateEndpoint := privateEndpoints[i]
- privateEndpointsByName[privateEndpoint.Name] = &privateEndpoint
- }
-
- atlasPrivateEndpointsByComment := map[string]*admin.ServerlessTenantEndpoint{}
- for i := range atlasPrivateEndpoints {
- atlasPrivateEndpoint := atlasPrivateEndpoints[i]
- atlasPrivateEndpointsByComment[atlasPrivateEndpoint.GetComment()] = &atlasPrivateEndpoint
- }
-
- // Collect all endpoints to create and update (connect)
- for i := range privateEndpoints {
- privateEndpoint := privateEndpoints[i]
- atlasPrivateEndpoint, ok := atlasPrivateEndpointsByComment[privateEndpoint.Name]
-
- // If a private endpoint with a given name doesn't exist on Atlas, add to creation list
- if !ok {
- toCreate = append(toCreate, privateEndpoint)
- }
-
- // If a private endpoint with a given name exists on Atlas with status RESERVED, add to update list (need to be connected)
- if isReadyToConnect(&privateEndpoint, atlasPrivateEndpoint) {
- toUpdate = append(toUpdate, privateEndpoint)
- }
- }
-
- for _, atlasPrivateEndpoint := range atlasPrivateEndpoints {
- // If an existing Atlas private endpoint is not present in kubernetes resource, add to deletion list
- if _, ok := privateEndpointsByName[atlasPrivateEndpoint.GetComment()]; !ok {
- toDelete = append(toDelete, atlasPrivateEndpoint)
- }
- }
-
- return toCreate, toUpdate, toDelete
-}
-
-func newSPEStatusMap(atlasPrivateEndpoints []admin.ServerlessTenantEndpoint) map[string]status.ServerlessPrivateEndpoint {
- statuses := map[string]status.ServerlessPrivateEndpoint{}
-
- for i := range atlasPrivateEndpoints {
- atlasPrivateEndpoint := atlasPrivateEndpoints[i]
- statuses[atlasPrivateEndpoint.GetComment()] = speStatusFromAtlas(&atlasPrivateEndpoint)
- }
-
- return statuses
-}
-
-func isReadyToConnect(privateEndpoint *akov2.ServerlessPrivateEndpoint, atlasPrivateEndpoint *admin.ServerlessTenantEndpoint) bool {
- if atlasPrivateEndpoint.GetStatus() != SPEStatusReserved {
- return false
- }
-
- switch provider.ProviderName(atlasPrivateEndpoint.GetProviderName()) {
- case provider.ProviderAWS:
- return privateEndpoint.CloudProviderEndpointID != ""
- case provider.ProviderAzure:
- return privateEndpoint.CloudProviderEndpointID != "" && privateEndpoint.PrivateEndpointIPAddress != ""
- }
-
- return false
-}
-
-func areSPEsAvailable(pe []status.ServerlessPrivateEndpoint) bool {
- for _, p := range pe {
- if p.Status != SPEStatusAvailable {
- return false
- }
- }
-
- return true
-}
-
-func speStatusFromAtlas(in *admin.ServerlessTenantEndpoint) status.ServerlessPrivateEndpoint {
- return status.ServerlessPrivateEndpoint{
- ID: in.GetId(),
- // Comment property is internally used as name to identify and match items on the operator against their peers on Atlas
- Name: in.GetComment(),
- ProviderName: in.GetProviderName(),
- CloudProviderEndpointID: in.GetCloudProviderEndpointId(),
- PrivateEndpointIPAddress: in.GetPrivateEndpointIpAddress(),
- EndpointServiceName: in.GetEndpointServiceName(),
- PrivateLinkServiceResourceID: in.GetPrivateLinkServiceResourceId(),
- Status: in.GetStatus(),
- ErrorMessage: in.GetErrorMessage(),
- }
-}
diff --git a/internal/controller/atlasdeployment/serverless_private_endpoint_test.go b/internal/controller/atlasdeployment/serverless_private_endpoint_test.go
deleted file mode 100644
index 87ec595b8c..0000000000
--- a/internal/controller/atlasdeployment/serverless_private_endpoint_test.go
+++ /dev/null
@@ -1,769 +0,0 @@
-// Copyright 2025 MongoDB Inc
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package atlasdeployment
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "go.mongodb.org/atlas-sdk/v20250312006/admin"
- "go.mongodb.org/atlas-sdk/v20250312006/mockadmin"
- "go.uber.org/zap/zaptest"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/api"
- akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/status"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/atlas"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/workflow"
- "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer"
-)
-
-func TestEnsureServerlessPrivateEndpoints(t *testing.T) {
- t.Run("should fail when deployment is nil", func(t *testing.T) {
- result := ensureServerlessPrivateEndpoints(&workflow.Context{}, "project-id", nil)
-
- assert.Equal(
- t,
- workflow.Terminate(workflow.Internal, errors.New("serverless deployment spec is empty")),
- result,
- )
- })
-
- t.Run("should fail when serverless spec is nil", func(t *testing.T) {
- result := ensureServerlessPrivateEndpoints(&workflow.Context{}, "project-id", &akov2.AtlasDeployment{})
-
- assert.Equal(
- t,
- workflow.Terminate(workflow.Internal, errors.New("serverless deployment spec is empty")),
- result,
- )
- })
-
- t.Run("should fail when setting a GCP serverless instance with a private endpoint", func(t *testing.T) {
- deployment := akov2.AtlasDeployment{
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "GCP",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- },
- },
- },
- }
- result := ensureServerlessPrivateEndpoints(&workflow.Context{}, "project-id", &deployment)
-
- assert.Equal(
- t,
- workflow.Terminate(workflow.AtlasUnsupportedFeature, errors.New("serverless private endpoints are not supported for GCP")),
- result,
- )
- })
-
- t.Run("should succeed when setting a GCP serverless instance without private endpoints", func(t *testing.T) {
- deployment := akov2.AtlasDeployment{
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "GCP",
- },
- },
- },
- }
- result := ensureServerlessPrivateEndpoints(&workflow.Context{}, "project-id", &deployment)
-
- assert.Equal(t, workflow.OK(), result)
- })
-
- t.Run("should succeed when there are nothing to sync", func(t *testing.T) {
- deployment := akov2.AtlasDeployment{
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- },
- },
- },
- }
- speAPI := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speAPI.EXPECT().ListServerlessPrivateEndpoints(mock.Anything, mock.Anything, mock.Anything).
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speAPI})
- speAPI.EXPECT().ListServerlessPrivateEndpointsExecute(mock.Anything).
- Return([]admin.ServerlessTenantEndpoint{}, &http.Response{}, nil)
- service := workflow.Context{
- Context: context.Background(),
- Log: zaptest.NewLogger(t).Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: &admin.APIClient{
- ServerlessPrivateEndpointsApi: speAPI,
- },
- },
- }
- result := ensureServerlessPrivateEndpoints(&service, "project-id", &deployment)
-
- assert.Equal(t, workflow.OK(), result)
- })
-
- t.Run("should fail when error happens syncing private endpoints", func(t *testing.T) {
- deployment := akov2.AtlasDeployment{
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- },
- },
- },
- }
- speAPI := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speAPI.EXPECT().ListServerlessPrivateEndpoints(mock.Anything, mock.Anything, mock.Anything).
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speAPI})
- speAPI.EXPECT().ListServerlessPrivateEndpointsExecute(mock.Anything).
- Return(nil, &http.Response{}, errors.New("connection failed"))
- service := workflow.Context{
- Context: context.Background(),
- Log: zaptest.NewLogger(t).Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: &admin.APIClient{
- ServerlessPrivateEndpointsApi: speAPI,
- },
- },
- }
- result := ensureServerlessPrivateEndpoints(&service, "project-id", &deployment)
-
- assert.Equal(t, result.GetError().Error(), "unable to retrieve list of serverless private endpoints from Atlas: connection failed")
- expected := workflow.Terminate(workflow.ServerlessPrivateEndpointFailed, fmt.Errorf("unable to retrieve list of serverless private endpoints from Atlas: connection failed"))
- assert.Equal(t, result.CloneWithoutError(), expected.CloneWithoutError())
- })
-
- t.Run("should succeed when syncing private endpoints still in progress", func(t *testing.T) {
- deployment := akov2.AtlasDeployment{
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- },
- },
- },
- }
- speAPI := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speAPI.EXPECT().ListServerlessPrivateEndpoints(mock.Anything, mock.Anything, mock.Anything).
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speAPI})
- speAPI.EXPECT().ListServerlessPrivateEndpointsExecute(mock.Anything).
- Return([]admin.ServerlessTenantEndpoint{}, &http.Response{}, nil)
- speAPI.EXPECT().CreateServerlessPrivateEndpoint(mock.Anything, mock.Anything, mock.Anything, mock.Anything).
- Return(admin.CreateServerlessPrivateEndpointApiRequest{ApiService: speAPI})
- speAPI.EXPECT().CreateServerlessPrivateEndpointExecute(mock.Anything).
- Return(
- &admin.ServerlessTenantEndpoint{
- Id: pointer.MakePtr("spe-id"),
- Comment: pointer.MakePtr("spe-1"),
- Status: pointer.MakePtr("RESERVATION_REQUESTED"),
- },
- &http.Response{},
- nil,
- )
- service := workflow.Context{
- Context: context.Background(),
- Log: zaptest.NewLogger(t).Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: &admin.APIClient{
- ServerlessPrivateEndpointsApi: speAPI,
- },
- },
- }
- result := ensureServerlessPrivateEndpoints(&service, "project-id", &deployment)
-
- assert.Equal(
- t,
- workflow.InProgress(workflow.ServerlessPrivateEndpointInProgress, "Waiting serverless private endpoint to be configured"),
- result,
- )
-
- condition, ok := service.GetCondition(api.ServerlessPrivateEndpointReadyType)
- assert.True(t, ok)
- condition.LastTransitionTime = metav1.Time{} // not relevant for the unit test
- assert.Equal(
- t,
- api.Condition{
- Type: api.ServerlessPrivateEndpointReadyType,
- Status: corev1.ConditionFalse,
- Reason: string(workflow.ServerlessPrivateEndpointInProgress),
- Message: "Waiting serverless private endpoint to be configured",
- },
- condition,
- )
- })
-
- t.Run("should succeed when finish syncing private endpoints", func(t *testing.T) {
- deployment := akov2.AtlasDeployment{
- Spec: akov2.AtlasDeploymentSpec{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- CloudProviderEndpointID: "aws-endpoint-id",
- },
- },
- },
- },
- }
- speAPI := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speAPI.EXPECT().ListServerlessPrivateEndpoints(mock.Anything, mock.Anything, mock.Anything).
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speAPI})
- speAPI.EXPECT().ListServerlessPrivateEndpointsExecute(mock.Anything).
- Return(
- []admin.ServerlessTenantEndpoint{
- {
- Id: pointer.MakePtr("spe-id"),
- ProviderName: pointer.MakePtr("AWS"),
- CloudProviderEndpointId: pointer.MakePtr("aws-endpoint-id"),
- Comment: pointer.MakePtr("spe-1"),
- Status: pointer.MakePtr(SPEStatusAvailable),
- },
- },
- &http.Response{},
- nil,
- )
- service := workflow.Context{
- Context: context.Background(),
- Log: zaptest.NewLogger(t).Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: &admin.APIClient{
- ServerlessPrivateEndpointsApi: speAPI,
- },
- },
- }
- result := ensureServerlessPrivateEndpoints(&service, "project-id", &deployment)
-
- assert.Equal(t, workflow.OK(), result)
-
- condition, ok := service.GetCondition(api.ServerlessPrivateEndpointReadyType)
- assert.True(t, ok)
- condition.LastTransitionTime = metav1.Time{} // not relevant for the unit test
- assert.Equal(
- t,
- api.Condition{
- Type: api.ServerlessPrivateEndpointReadyType,
- Status: corev1.ConditionTrue,
- },
- condition,
- )
- })
-}
-
-func TestSyncServerlessPrivateEndpoints(t *testing.T) {
- t.Run("should succeed adding, creating and deleting private endpoints", func(t *testing.T) {
- spec := akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- {
- Name: "spe-2",
- CloudProviderEndpointID: "aws-endpoint-id",
- },
- },
- }
- speAPI := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speAPI.EXPECT().ListServerlessPrivateEndpoints(context.Background(), "project-id", "instance-0").
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speAPI})
- speAPI.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return(
- []admin.ServerlessTenantEndpoint{
- {
- Id: pointer.MakePtr("spe-2-id"),
- ProviderName: pointer.MakePtr("AWS"),
- Comment: pointer.MakePtr("spe-2"),
- Status: pointer.MakePtr(SPEStatusReserved),
- },
- {
- Id: pointer.MakePtr("spe-3-id"),
- ProviderName: pointer.MakePtr("AWS"),
- Comment: pointer.MakePtr("spe-3"),
- Status: pointer.MakePtr(SPEStatusAvailable),
- },
- },
- &http.Response{},
- nil,
- )
- speAPI.EXPECT().CreateServerlessPrivateEndpoint(context.Background(), "project-id", "instance-0", mock.AnythingOfType("*admin.ServerlessTenantCreateRequest")).
- Return(admin.CreateServerlessPrivateEndpointApiRequest{ApiService: speAPI})
- speAPI.EXPECT().CreateServerlessPrivateEndpointExecute(mock.AnythingOfType("admin.CreateServerlessPrivateEndpointApiRequest")).
- Return(
- &admin.ServerlessTenantEndpoint{
- Id: pointer.MakePtr("spe-1-id"),
- ProviderName: pointer.MakePtr("AWS"),
- Comment: pointer.MakePtr("spe-1"),
- Status: pointer.MakePtr("RESERVATION_REQUESTED"),
- },
- &http.Response{},
- nil,
- )
- speAPI.EXPECT().UpdateServerlessPrivateEndpoint(context.Background(), "project-id", "instance-0", "spe-2-id", mock.AnythingOfType("*admin.ServerlessTenantEndpointUpdate")).
- Return(admin.UpdateServerlessPrivateEndpointApiRequest{ApiService: speAPI})
- speAPI.EXPECT().UpdateServerlessPrivateEndpointExecute(mock.AnythingOfType("admin.UpdateServerlessPrivateEndpointApiRequest")).
- Return(
- &admin.ServerlessTenantEndpoint{
- Id: pointer.MakePtr("spe-2-id"),
- ProviderName: pointer.MakePtr("AWS"),
- CloudProviderEndpointId: pointer.MakePtr("aws-endpoint-id"),
- Comment: pointer.MakePtr("spe-2"),
- Status: pointer.MakePtr("INITIATING"),
- },
- &http.Response{},
- nil,
- )
- speAPI.EXPECT().DeleteServerlessPrivateEndpoint(context.Background(), "project-id", "instance-0", "spe-3-id").
- Return(admin.DeleteServerlessPrivateEndpointApiRequest{ApiService: speAPI})
- speAPI.EXPECT().DeleteServerlessPrivateEndpointExecute(mock.AnythingOfType("admin.DeleteServerlessPrivateEndpointApiRequest")).
- Return(
- &http.Response{},
- nil,
- )
- service := workflow.Context{
- Context: context.Background(),
- Log: zaptest.NewLogger(t).Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: &admin.APIClient{
- ServerlessPrivateEndpointsApi: speAPI,
- },
- },
- }
-
- finished, err := syncServerlessPrivateEndpoints(&service, "project-id", &spec)
- assert.NoError(t, err)
- assert.False(t, finished)
- })
-
- t.Run("should fail adding a private endpoint", func(t *testing.T) {
- spec := akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- },
- }
- speAPI := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speAPI.EXPECT().ListServerlessPrivateEndpoints(context.Background(), "project-id", "instance-0").
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speAPI})
- speAPI.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return([]admin.ServerlessTenantEndpoint{}, &http.Response{}, nil)
- speAPI.EXPECT().CreateServerlessPrivateEndpoint(context.Background(), "project-id", "instance-0", mock.AnythingOfType("*admin.ServerlessTenantCreateRequest")).
- Return(admin.CreateServerlessPrivateEndpointApiRequest{ApiService: speAPI})
- speAPI.EXPECT().CreateServerlessPrivateEndpointExecute(mock.AnythingOfType("admin.CreateServerlessPrivateEndpointApiRequest")).
- Return(
- nil,
- &http.Response{},
- errors.New("failed to create serverless private endpoint"),
- )
- service := workflow.Context{
- Context: context.Background(),
- Log: zaptest.NewLogger(t).Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: &admin.APIClient{
- ServerlessPrivateEndpointsApi: speAPI,
- },
- },
- }
-
- finished, err := syncServerlessPrivateEndpoints(&service, "project-id", &spec)
- assert.ErrorContains(t, err, "failed to create serverless private endpoint")
- assert.False(t, finished)
- })
-
- t.Run("should fail updating a private endpoint", func(t *testing.T) {
- spec := akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- CloudProviderEndpointID: "endpoint-id",
- },
- },
- }
- speAPI := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speAPI.EXPECT().ListServerlessPrivateEndpoints(context.Background(), "project-id", "instance-0").
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speAPI})
- speAPI.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return(
- []admin.ServerlessTenantEndpoint{
- {
- Id: pointer.MakePtr("spe-1-id"),
- Comment: pointer.MakePtr("spe-1"),
- Status: pointer.MakePtr(SPEStatusReserved),
- ProviderName: pointer.MakePtr("AWS"),
- },
- },
- &http.Response{},
- nil,
- )
- speAPI.EXPECT().UpdateServerlessPrivateEndpoint(context.Background(), "project-id", "instance-0", "spe-1-id", mock.AnythingOfType("*admin.ServerlessTenantEndpointUpdate")).
- Return(admin.UpdateServerlessPrivateEndpointApiRequest{ApiService: speAPI})
- speAPI.EXPECT().UpdateServerlessPrivateEndpointExecute(mock.AnythingOfType("admin.UpdateServerlessPrivateEndpointApiRequest")).
- Return(
- nil,
- &http.Response{},
- errors.New("failed to update serverless private endpoint"),
- )
- service := workflow.Context{
- Context: context.Background(),
- Log: zaptest.NewLogger(t).Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: &admin.APIClient{
- ServerlessPrivateEndpointsApi: speAPI,
- },
- },
- }
-
- finished, err := syncServerlessPrivateEndpoints(&service, "project-id", &spec)
- assert.ErrorContains(t, err, "failed to update serverless private endpoint")
- assert.False(t, finished)
- })
-
- t.Run("should fail delete a private endpoint", func(t *testing.T) {
- spec := akov2.ServerlessSpec{
- Name: "instance-0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- },
- }
- speAPI := mockadmin.NewServerlessPrivateEndpointsApi(t)
- speAPI.EXPECT().ListServerlessPrivateEndpoints(context.Background(), "project-id", "instance-0").
- Return(admin.ListServerlessPrivateEndpointsApiRequest{ApiService: speAPI})
- speAPI.EXPECT().ListServerlessPrivateEndpointsExecute(mock.AnythingOfType("admin.ListServerlessPrivateEndpointsApiRequest")).
- Return(
- []admin.ServerlessTenantEndpoint{
- {
- Id: pointer.MakePtr("spe-1-id"),
- Comment: pointer.MakePtr("spe-1"),
- Status: pointer.MakePtr(SPEStatusAvailable),
- ProviderName: pointer.MakePtr("AWS"),
- },
- },
- &http.Response{},
- nil,
- )
- speAPI.EXPECT().DeleteServerlessPrivateEndpoint(context.Background(), "project-id", "instance-0", "spe-1-id").
- Return(admin.DeleteServerlessPrivateEndpointApiRequest{ApiService: speAPI})
- speAPI.EXPECT().DeleteServerlessPrivateEndpointExecute(mock.AnythingOfType("admin.DeleteServerlessPrivateEndpointApiRequest")).
- Return(
- &http.Response{},
- errors.New("failed to delete serverless private endpoint"),
- )
- service := workflow.Context{
- Context: context.Background(),
- Log: zaptest.NewLogger(t).Sugar(),
- SdkClientSet: &atlas.ClientSet{
- SdkClient20250312006: &admin.APIClient{
- ServerlessPrivateEndpointsApi: speAPI,
- },
- },
- }
-
- finished, err := syncServerlessPrivateEndpoints(&service, "project-id", &spec)
- assert.ErrorContains(t, err, "failed to delete serverless private endpoint")
- assert.False(t, finished)
- })
-}
-
-func TestIsGCPWithPrivateEndpoints(t *testing.T) {
- t.Run("should return true when is GCP serverless instance containing private endpoint configuration", func(t *testing.T) {
- deployment := akov2.ServerlessSpec{
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- BackingProviderName: "GCP",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- },
- }
-
- assert.True(t, isGCPWithPrivateEndpoints(&deployment))
- })
-
- t.Run("should return false when is GCP serverless instance without private endpoint configuration", func(t *testing.T) {
- deployment := akov2.ServerlessSpec{
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- BackingProviderName: "GCP",
- },
- }
-
- assert.False(t, isGCPWithPrivateEndpoints(&deployment))
- })
-}
-
-func TestIsGCPWithoutPrivateEndpoints(t *testing.T) {
- t.Run("should return false when is GCP serverless instance containing private endpoint configuration", func(t *testing.T) {
- deployment := akov2.ServerlessSpec{
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- BackingProviderName: "GCP",
- },
- PrivateEndpoints: []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- },
- }
-
- assert.False(t, isGCPWithoutPrivateEndpoints(&deployment))
- })
-
- t.Run("should return true when is GCP serverless instance without private endpoint configuration", func(t *testing.T) {
- deployment := akov2.ServerlessSpec{
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- BackingProviderName: "GCP",
- },
- }
-
- assert.True(t, isGCPWithoutPrivateEndpoints(&deployment))
- })
-}
-
-func TestSortTasks(t *testing.T) {
- t.Run("should sort one of each operation", func(t *testing.T) {
- spes := []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- {
- Name: "spe-2",
- CloudProviderEndpointID: "endpoint-id",
- },
- }
- atlas := []admin.ServerlessTenantEndpoint{
- {
- ProviderName: pointer.MakePtr("AWS"),
- Comment: pointer.MakePtr("spe-2"),
- Status: pointer.MakePtr(SPEStatusReserved),
- },
- {
- Comment: pointer.MakePtr("spe-3"),
- },
- }
-
- toCreate, toUpdate, toDelete := sortTasks(spes, atlas)
-
- assert.Equal(
- t,
- []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-1",
- },
- },
- toCreate,
- )
- assert.Equal(
- t,
- []akov2.ServerlessPrivateEndpoint{
- {
- Name: "spe-2",
- CloudProviderEndpointID: "endpoint-id",
- },
- },
- toUpdate,
- )
- assert.Equal(
- t,
- []admin.ServerlessTenantEndpoint{
- {
- Comment: pointer.MakePtr("spe-3"),
- },
- },
- toDelete,
- )
- })
-}
-
-func TestIsReadyToConnect(t *testing.T) {
- data := map[string]struct {
- spe akov2.ServerlessPrivateEndpoint
- atlas admin.ServerlessTenantEndpoint
- expected bool
- }{
- "should return false when private endpoint is not in RESERVED state": {
- spe: akov2.ServerlessPrivateEndpoint{},
- atlas: admin.ServerlessTenantEndpoint{
- Status: pointer.MakePtr("RESERVATION_REQUESTED"),
- },
- expected: false,
- },
- "should return false when a AWS private endpoint is in RESERVED state but miss endpoint ID": {
- spe: akov2.ServerlessPrivateEndpoint{},
- atlas: admin.ServerlessTenantEndpoint{
- ProviderName: pointer.MakePtr("AWS"),
- Status: pointer.MakePtr(SPEStatusReserved),
- },
- expected: false,
- },
- "should return false when a Azure private endpoint is in RESERVED state but miss endpoint ID": {
- spe: akov2.ServerlessPrivateEndpoint{
- PrivateEndpointIPAddress: "some-ip-address",
- },
- atlas: admin.ServerlessTenantEndpoint{
- ProviderName: pointer.MakePtr("AZURE"),
- Status: pointer.MakePtr(SPEStatusReserved),
- },
- expected: false,
- },
- "should return false when a Azure private endpoint is in RESERVED state but miss IP address": {
- spe: akov2.ServerlessPrivateEndpoint{
- CloudProviderEndpointID: "azure-endpoint-id",
- },
- atlas: admin.ServerlessTenantEndpoint{
- ProviderName: pointer.MakePtr("AZURE"),
- Status: pointer.MakePtr(SPEStatusReserved),
- },
- expected: false,
- },
- "should return true when a Azure private endpoint is in RESERVED state and has connection data": {
- spe: akov2.ServerlessPrivateEndpoint{
- CloudProviderEndpointID: "azure-endpoint-id",
- PrivateEndpointIPAddress: "some-ip-address",
- },
- atlas: admin.ServerlessTenantEndpoint{
- ProviderName: pointer.MakePtr("AZURE"),
- Status: pointer.MakePtr(SPEStatusReserved),
- },
- expected: true,
- },
- "should return true when a AWS private endpoint is in RESERVED state and has connection data": {
- spe: akov2.ServerlessPrivateEndpoint{
- CloudProviderEndpointID: "aws-endpoint-id",
- },
- atlas: admin.ServerlessTenantEndpoint{
- ProviderName: pointer.MakePtr("AWS"),
- Status: pointer.MakePtr(SPEStatusReserved),
- },
- expected: true,
- },
- }
-
- for desc, val := range data {
- t.Run(desc, func(t *testing.T) {
- spe := val.spe
- atlas := val.atlas
- assert.Equal(t, val.expected, isReadyToConnect(&spe, &atlas))
- })
- }
-}
-
-func TestCheckStatuses(t *testing.T) {
- data := map[string]struct {
- spes []status.ServerlessPrivateEndpoint
- expected bool
- }{
- "should return true when nil": {
- spes: nil,
- expected: true,
- },
- "should return true when empty": {
- spes: []status.ServerlessPrivateEndpoint{},
- expected: true,
- },
- "should return true when all status are available": {
- spes: []status.ServerlessPrivateEndpoint{
- {
- Status: SPEStatusAvailable,
- },
- {
- Status: SPEStatusAvailable,
- },
- },
- expected: true,
- },
- "should return false when all status are not available": {
- spes: []status.ServerlessPrivateEndpoint{
- {
- Status: SPEStatusReserved,
- },
- {
- Status: SPEStatusDeleting,
- },
- },
- expected: false,
- },
- "should return false when at least one status is not available": {
- spes: []status.ServerlessPrivateEndpoint{
- {
- Status: SPEStatusReserved,
- },
- {
- Status: SPEStatusAvailable,
- },
- {
- Status: SPEStatusAvailable,
- },
- },
- expected: false,
- },
- }
-
- for desc, val := range data {
- t.Run(desc, func(t *testing.T) {
- assert.Equal(t, val.expected, areSPEsAvailable(val.spes))
- })
- }
-}
diff --git a/internal/translation/deployment/conversion.go b/internal/translation/deployment/conversion.go
index d87caec586..6a94fb4b4b 100644
--- a/internal/translation/deployment/conversion.go
+++ b/internal/translation/deployment/conversion.go
@@ -153,64 +153,6 @@ func deprecatedSpecs(specs *akov2.Specs) bool {
return false
}
-type Serverless struct {
- *akov2.ServerlessSpec
- ProjectID string
- State string
- MongoDBVersion string
- Connection *status.ConnectionStrings
-
- customResource *akov2.AtlasDeployment
-}
-
-func (s *Serverless) GetName() string {
- return s.Name
-}
-
-func (s *Serverless) GetProjectID() string {
- return s.ProjectID
-}
-
-func (s *Serverless) GetState() string {
- return s.State
-}
-
-func (s *Serverless) GetMongoDBVersion() string {
- return s.MongoDBVersion
-}
-
-func (s *Serverless) GetConnection() *status.ConnectionStrings {
- return s.Connection
-}
-
-func (s *Serverless) GetReplicaSet() []status.ReplicaSet {
- return nil
-}
-
-func (s *Serverless) GetCustomResource() *akov2.AtlasDeployment {
- return s.customResource
-}
-
-func (s *Serverless) IsServerless() bool {
- return true
-}
-
-func (s *Serverless) IsFlex() bool {
- return false
-}
-
-func (s *Serverless) IsTenant() bool {
- return false
-}
-
-func (s *Serverless) IsDedicated() bool {
- return false
-}
-
-func (s *Serverless) Notifications() (bool, string, string) {
- return true, NOTIFICATION_REASON_DEPRECATION, "WARNING: Serverless is deprecated. See https://dochub.mongodb.org/core/atlas-flex-migration for details."
-}
-
type Flex struct {
*akov2.FlexSpec
ProjectID string
@@ -266,6 +208,10 @@ func (f *Flex) IsDedicated() bool {
}
func (f *Flex) Notifications() (bool, string, string) {
+ if f.customResource.IsServerless() {
+ return true, NOTIFICATION_REASON_DEPRECATION, "WARNING: Serverless is deprecated. See https://dochub.mongodb.org/core/atlas-flex-migration for details."
+ }
+
return false, "", ""
}
@@ -294,14 +240,14 @@ type Endpoint struct {
func NewDeployment(projectID string, atlasDeployment *akov2.AtlasDeployment) Deployment {
if atlasDeployment.IsServerless() {
- serverless := &Serverless{
+ flex := &Flex{
customResource: atlasDeployment,
ProjectID: projectID,
- ServerlessSpec: atlasDeployment.Spec.ServerlessSpec.DeepCopy(),
+ FlexSpec: serverlessToFlexSpec(atlasDeployment.Spec.ServerlessSpec.DeepCopy()),
}
- normalizeServerlessDeployment(serverless)
+ normalizeFlexDeployment(flex)
- return serverless
+ return flex
}
if atlasDeployment.IsFlex() {
@@ -325,15 +271,19 @@ func NewDeployment(projectID string, atlasDeployment *akov2.AtlasDeployment) Dep
return cluster
}
-func normalizeServerlessDeployment(serverless *Serverless) {
- serverless.ServerlessSpec.PrivateEndpoints = nil
- if serverless.ServerlessSpec.Tags == nil {
- serverless.ServerlessSpec.Tags = []*akov2.TagSpec{}
+func serverlessToFlexSpec(serverless *akov2.ServerlessSpec) *akov2.FlexSpec {
+ settings := &akov2.FlexProviderSettings{}
+ if serverless.ProviderSettings != nil {
+ settings.BackingProviderName = serverless.ProviderSettings.BackingProviderName
+ settings.RegionName = serverless.ProviderSettings.RegionName
}
- cmp.NormalizeSlice(serverless.Tags, func(a, b *akov2.TagSpec) int {
- return strings.Compare(a.Key, b.Key)
- })
+ return &akov2.FlexSpec{
+ Name: serverless.Name,
+ Tags: serverless.Tags,
+ TerminationProtectionEnabled: serverless.TerminationProtectionEnabled,
+ ProviderSettings: settings,
+ }
}
func normalizeFlexDeployment(flex *Flex) {
@@ -997,85 +947,6 @@ func processArgsToAtlas(config *akov2.ProcessArgs) (*admin.ClusterDescriptionPro
}, nil
}
-func serverlessFromAtlas(instance *admin.ServerlessInstanceDescription) *Serverless {
- providerSettings := instance.GetProviderSettings()
- serverlessBackupOptions := instance.GetServerlessBackupOptions()
- connectionStrings := instance.GetConnectionStrings()
-
- pes := make([]status.PrivateEndpoint, 0, len(connectionStrings.GetPrivateEndpoint()))
- for _, pe := range connectionStrings.GetPrivateEndpoint() {
- eps := make([]status.Endpoint, 0, len(pe.GetEndpoints()))
- for _, ep := range pe.GetEndpoints() {
- eps = append(
- eps,
- status.Endpoint{
- EndpointID: ep.GetEndpointId(),
- ProviderName: ep.GetProviderName(),
- Region: ep.GetRegion(),
- })
- }
-
- pes = append(
- pes,
- status.PrivateEndpoint{
- SRVConnectionString: pe.GetSrvConnectionString(),
- Endpoints: eps,
- })
- }
-
- s := &Serverless{
- ProjectID: instance.GetGroupId(),
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: instance.GetName(),
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: provider.ProviderName(providerSettings.GetProviderName()),
- BackingProviderName: providerSettings.GetBackingProviderName(),
- RegionName: providerSettings.GetRegionName(),
- },
- Tags: tag.FromAtlas(instance.GetTags()),
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: serverlessBackupOptions.GetServerlessContinuousBackupEnabled(),
- },
- TerminationProtectionEnabled: instance.GetTerminationProtectionEnabled(),
- },
- State: instance.GetStateName(),
- MongoDBVersion: instance.GetMongoDBVersion(),
- Connection: &status.ConnectionStrings{
- StandardSrv: connectionStrings.GetStandardSrv(),
- PrivateEndpoint: pes,
- },
- }
- normalizeServerlessDeployment(s)
-
- return s
-}
-
-func serverlessCreateToAtlas(serverless *Serverless) *admin.ServerlessInstanceDescriptionCreate {
- return &admin.ServerlessInstanceDescriptionCreate{
- Name: serverless.Name,
- ProviderSettings: admin.ServerlessProviderSettings{
- ProviderName: pointer.MakePtr(string(serverless.ProviderSettings.ProviderName)),
- BackingProviderName: serverless.ProviderSettings.BackingProviderName,
- RegionName: serverless.ProviderSettings.RegionName,
- },
- ServerlessBackupOptions: &admin.ClusterServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: &serverless.BackupOptions.ServerlessContinuousBackupEnabled,
- },
- Tags: tag.ToAtlas(serverless.Tags),
- TerminationProtectionEnabled: &serverless.TerminationProtectionEnabled,
- }
-}
-
-func serverlessUpdateToAtlas(serverless *Serverless) *admin.ServerlessInstanceDescriptionUpdate {
- return &admin.ServerlessInstanceDescriptionUpdate{
- ServerlessBackupOptions: &admin.ClusterServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: &serverless.BackupOptions.ServerlessContinuousBackupEnabled,
- },
- Tags: tag.ToAtlas(serverless.Tags),
- TerminationProtectionEnabled: &serverless.TerminationProtectionEnabled,
- }
-}
-
func clustersToConnections(clusters []admin.ClusterDescription20240805) []Connection {
conns := []Connection{}
for _, c := range clusters {
@@ -1104,30 +975,6 @@ func fillClusterPrivateEndpoints(cpeList []admin.ClusterDescriptionConnectionStr
return pes
}
-func serverlessToConnections(serverless []admin.ServerlessInstanceDescription) []Connection {
- conns := []Connection{}
- for _, s := range serverless {
- conns = append(conns, Connection{
- Name: s.GetName(),
- ConnURL: "",
- SrvConnURL: s.ConnectionStrings.GetStandardSrv(),
- Serverless: true,
- PrivateEndpoints: fillServerlessPrivateEndpoints(s.ConnectionStrings.GetPrivateEndpoint()),
- })
- }
- return conns
-}
-
-func fillServerlessPrivateEndpoints(cpeList []admin.ServerlessConnectionStringsPrivateEndpointList) []PrivateEndpoint {
- pes := []PrivateEndpoint{}
- for _, cpe := range cpeList {
- pes = append(pes, PrivateEndpoint{
- ServerURL: cpe.GetSrvConnectionString(),
- })
- }
- return pes
-}
-
func flexToConnections(flex []admin.FlexClusterDescription20241113) []Connection {
conns := []Connection{}
for _, f := range flex {
diff --git a/internal/translation/deployment/conversion_test.go b/internal/translation/deployment/conversion_test.go
index bdfd4eb1e2..316b67e9b9 100644
--- a/internal/translation/deployment/conversion_test.go
+++ b/internal/translation/deployment/conversion_test.go
@@ -33,7 +33,7 @@ func TestNewDeployment(t *testing.T) {
cr *akov2.AtlasDeployment
expected Deployment
}{
- "should create a new serverless deployment": {
+ "should create a new serverless deployment as flex": {
cr: &akov2.AtlasDeployment{
Spec: akov2.AtlasDeploymentSpec{
ServerlessSpec: &akov2.ServerlessSpec{
@@ -62,11 +62,10 @@ func TestNewDeployment(t *testing.T) {
},
},
},
- expected: &Serverless{
- ServerlessSpec: &akov2.ServerlessSpec{
+ expected: &Flex{
+ FlexSpec: &akov2.FlexSpec{
Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
+ ProviderSettings: &akov2.FlexProviderSettings{
BackingProviderName: "AWS",
RegionName: "US_EAST_1",
},
@@ -76,9 +75,6 @@ func TestNewDeployment(t *testing.T) {
Value: "test",
},
},
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
TerminationProtectionEnabled: true,
},
ProjectID: "project-id",
@@ -303,103 +299,6 @@ func TestNewDeployment(t *testing.T) {
}
}
-func TestNormalizeServerlessDeployment(t *testing.T) {
- tests := map[string]struct {
- deployment *Serverless
- expected *Serverless
- }{
- "normalize deployment without tags": {
- deployment: &Serverless{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- RegionName: "US_EAST_1",
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- expected: &Serverless{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- RegionName: "US_EAST_1",
- },
- Tags: []*akov2.TagSpec{},
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- "normalize deployment with tags": {
- deployment: &Serverless{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- RegionName: "US_EAST_1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "b",
- Value: "b",
- },
- {
- Key: "a",
- Value: "a",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- expected: &Serverless{
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- RegionName: "US_EAST_1",
- },
- Tags: []*akov2.TagSpec{
- {
- Key: "a",
- Value: "a",
- },
- {
- Key: "b",
- Value: "b",
- },
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- },
- },
- },
- }
-
- for name, tt := range tests {
- t.Run(name, func(t *testing.T) {
- normalizeServerlessDeployment(tt.deployment)
-
- assert.Equal(t, tt.expected, tt.deployment)
- })
- }
-}
-
func TestNormalizeClusterDeployment(t *testing.T) {
tests := map[string]struct {
deployment *Cluster
@@ -1168,8 +1067,8 @@ func TestIsType(t *testing.T) {
ServerlessSpec: &akov2.ServerlessSpec{},
},
},
- wantServerless: true,
- wantFlex: false,
+ wantServerless: false,
+ wantFlex: true,
wantTenant: false,
wantDedicated: false,
},
diff --git a/internal/translation/deployment/deployment.go b/internal/translation/deployment/deployment.go
index 804083079b..2f9bfbc3ba 100644
--- a/internal/translation/deployment/deployment.go
+++ b/internal/translation/deployment/deployment.go
@@ -58,14 +58,13 @@ type GlobalClusterService interface {
type ProductionAtlasDeployments struct {
clustersAPI admin.ClustersApi
- serverlessAPI admin.ServerlessInstancesApi
flexAPI admin.FlexClustersApi
globalClusterAPI admin.GlobalClustersApi
isGov bool
}
-func NewAtlasDeployments(clusterService admin.ClustersApi, serverlessAPI admin.ServerlessInstancesApi, globalClusterAPI admin.GlobalClustersApi, flexAPI admin.FlexClustersApi, isGov bool) *ProductionAtlasDeployments {
- return &ProductionAtlasDeployments{clustersAPI: clusterService, serverlessAPI: serverlessAPI, globalClusterAPI: globalClusterAPI, flexAPI: flexAPI, isGov: isGov}
+func NewAtlasDeployments(clusterService admin.ClustersApi, globalClusterAPI admin.GlobalClustersApi, flexAPI admin.FlexClustersApi, isGov bool) *ProductionAtlasDeployments {
+ return &ProductionAtlasDeployments{clustersAPI: clusterService, globalClusterAPI: globalClusterAPI, flexAPI: flexAPI, isGov: isGov}
}
func (ds *ProductionAtlasDeployments) ListDeploymentNames(ctx context.Context, projectID string) ([]string, error) {
@@ -96,16 +95,6 @@ func (ds *ProductionAtlasDeployments) ListDeploymentNames(ctx context.Context, p
}
}
- serverless, _, err := ds.serverlessAPI.ListServerlessInstances(ctx, projectID).Execute()
- if err != nil {
- return nil, fmt.Errorf("failed to list serverless deployments for project %s: %w", projectID, err)
- }
- for _, d := range serverless.GetResults() {
- name := pointer.GetOrDefault(d.Name, "")
- if name != "" {
- deploymentNames = append(deploymentNames, name)
- }
- }
return deploymentNames, nil
}
@@ -126,13 +115,7 @@ func (ds *ProductionAtlasDeployments) ListDeploymentConnections(ctx context.Cont
}
flexConns := flexToConnections(flex.GetResults())
- serverless, _, serverlessErr := ds.serverlessAPI.ListServerlessInstances(ctx, projectID).Execute()
- if serverlessErr != nil {
- return nil, fmt.Errorf("failed to list serverless deployments for project %s: %w", projectID, err)
- }
- serverlessConns := serverlessToConnections(serverless.GetResults())
-
- return connectionSet(clusterConns, serverlessConns, flexConns), nil
+ return connectionSet(clusterConns, flexConns), nil
}
func (ds *ProductionAtlasDeployments) ClusterExists(ctx context.Context, projectID, name string) (bool, error) {
@@ -152,14 +135,6 @@ func (ds *ProductionAtlasDeployments) ClusterExists(ctx context.Context, project
return true, nil
}
- serverless, err := ds.GetServerless(ctx, projectID, name)
- if !admin.IsErrorCode(err, atlas.ClusterInstanceFromServerlessAPI) && err != nil {
- return false, err
- }
- if serverless != nil {
- return true, nil
- }
-
return false, nil
}
@@ -202,36 +177,11 @@ func (ds *ProductionAtlasDeployments) GetCluster(ctx context.Context, projectID,
return nil, nil
}
-func (ds *ProductionAtlasDeployments) GetServerless(ctx context.Context, projectID, name string) (*Serverless, error) {
- if ds.isGov {
- return nil, nil
- }
-
- serverless, _, err := ds.serverlessAPI.GetServerlessInstance(ctx, projectID, name).Execute()
- if err == nil {
- return serverlessFromAtlas(serverless), err
- }
-
- if !admin.IsErrorCode(err, atlas.ServerlessInstanceNotFound) && !admin.IsErrorCode(err, atlas.ProviderUnsupported) {
- return nil, err
- }
-
- 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")
}
- serverless, err := ds.GetServerless(ctx, projectID, deployment.GetDeploymentName())
- if !admin.IsErrorCode(err, atlas.ClusterInstanceFromServerlessAPI) && err != nil {
- return nil, err
- }
- if serverless != nil {
- return serverless, nil
- }
-
cluster, err := ds.GetCluster(ctx, projectID, deployment.GetDeploymentName())
if !admin.IsErrorCode(err, atlas.ServerlessInstanceFromClusterAPI) && !admin.IsErrorCode(err, atlas.FlexFromClusterAPI) && err != nil {
return nil, err
@@ -261,13 +211,6 @@ func (ds *ProductionAtlasDeployments) CreateDeployment(ctx context.Context, depl
}
return clusterFromAtlas(cluster), nil
- case *Serverless:
- serverless, _, err := ds.serverlessAPI.CreateServerlessInstance(ctx, deployment.GetProjectID(), serverlessCreateToAtlas(d)).Execute()
- if err != nil {
- return nil, err
- }
-
- return serverlessFromAtlas(serverless), nil
case *Flex:
flex, _, err := ds.flexAPI.CreateFlexCluster(ctx, deployment.GetProjectID(), flexCreateToAtlas(d)).Execute()
if err != nil {
@@ -288,13 +231,6 @@ func (ds *ProductionAtlasDeployments) UpdateDeployment(ctx context.Context, depl
}
return clusterFromAtlas(cluster), nil
- case *Serverless:
- serverless, _, err := ds.serverlessAPI.UpdateServerlessInstance(ctx, deployment.GetProjectID(), deployment.GetName(), serverlessUpdateToAtlas(d)).Execute()
- if err != nil {
- return nil, err
- }
-
- return serverlessFromAtlas(serverless), nil
case *Flex:
flex, _, err := ds.flexAPI.UpdateFlexCluster(ctx, deployment.GetProjectID(), deployment.GetName(), flexUpdateToAtlas(d)).Execute()
if err != nil {
@@ -313,8 +249,6 @@ func (ds *ProductionAtlasDeployments) DeleteDeployment(ctx context.Context, depl
switch deployment.(type) {
case *Cluster:
_, 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()
}
@@ -334,8 +268,6 @@ func (ds *ProductionAtlasDeployments) UpgradeToDedicated(ctx context.Context, cu
switch currentDeployment.(type) {
case *Cluster:
return nil, errors.New("upgrade from shared to dedicated is not supported")
- case *Serverless:
- return nil, errors.New("upgrade from serverless to dedicated is not supported")
case *Flex:
d := targetDeployment.(*Cluster)
flex, _, err := ds.flexAPI.UpgradeFlexCluster(ctx, targetDeployment.GetProjectID(), flexUpgradeToAtlas(d)).Execute()
diff --git a/internal/translation/deployment/deployment_test.go b/internal/translation/deployment/deployment_test.go
index 5939a2bcb5..a67fd4b2aa 100644
--- a/internal/translation/deployment/deployment_test.go
+++ b/internal/translation/deployment/deployment_test.go
@@ -44,15 +44,12 @@ func TestProductionAtlasDeployments_ListDeploymentConnections(t *testing.T) {
mockClustersAPI.EXPECT().ListClustersExecute(admin.ListClustersApiRequest{ApiService: mockClustersAPI}).Return(
nil, &http.Response{StatusCode: http.StatusOK}, nil)
- mockServerlessAPI := mockadmin.NewServerlessInstancesApi(t)
- mockServerlessAPI.EXPECT().ListServerlessInstancesExecute(mock.Anything).Unset()
mockFlexAPI := mockadmin.NewFlexClustersApi(t)
mockFlexAPI.EXPECT().ListFlexClustersExecute(mock.Anything).Unset()
ds := &ProductionAtlasDeployments{
- clustersAPI: mockClustersAPI,
- serverlessAPI: mockServerlessAPI,
- flexAPI: mockFlexAPI,
- isGov: true,
+ clustersAPI: mockClustersAPI,
+ flexAPI: mockFlexAPI,
+ isGov: true,
}
projectID := "testProjectID"
_, err := ds.ListDeploymentConnections(context.Background(), projectID)
@@ -66,13 +63,6 @@ func TestProductionAtlasDeployments_ListDeploymentConnections(t *testing.T) {
mockClustersAPI.EXPECT().ListClustersExecute(admin.ListClustersApiRequest{ApiService: mockClustersAPI}).Return(
nil, &http.Response{StatusCode: http.StatusOK}, nil)
- mockServerlessAPI := mockadmin.NewServerlessInstancesApi(t)
- mockServerlessAPI.EXPECT().ListServerlessInstances(context.Background(), mock.Anything).Return(
- admin.ListServerlessInstancesApiRequest{ApiService: mockServerlessAPI})
- mockServerlessAPI.EXPECT().ListServerlessInstancesExecute(
- admin.ListServerlessInstancesApiRequest{ApiService: mockServerlessAPI}).Return(
- nil, &http.Response{StatusCode: http.StatusOK}, nil)
-
mockFlexAPI := mockadmin.NewFlexClustersApi(t)
mockFlexAPI.EXPECT().ListFlexClusters(context.Background(), mock.Anything).Return(
admin.ListFlexClustersApiRequest{ApiService: mockFlexAPI})
@@ -81,10 +71,9 @@ func TestProductionAtlasDeployments_ListDeploymentConnections(t *testing.T) {
nil, &http.Response{StatusCode: http.StatusOK}, nil)
ds := &ProductionAtlasDeployments{
- clustersAPI: mockClustersAPI,
- serverlessAPI: mockServerlessAPI,
- flexAPI: mockFlexAPI,
- isGov: false,
+ clustersAPI: mockClustersAPI,
+ flexAPI: mockFlexAPI,
+ isGov: false,
}
projectID := "testProjectID"
_, err := ds.ListDeploymentConnections(context.Background(), projectID)
@@ -105,20 +94,6 @@ func TestProductionAtlasDeployments_ListDeploymentConnections(t *testing.T) {
},
}, &http.Response{StatusCode: http.StatusOK}, nil)
- mockServerlessAPI := mockadmin.NewServerlessInstancesApi(t)
- mockServerlessAPI.EXPECT().ListServerlessInstances(context.Background(), mock.Anything).Return(
- admin.ListServerlessInstancesApiRequest{ApiService: mockServerlessAPI})
- mockServerlessAPI.EXPECT().ListServerlessInstancesExecute(
- admin.ListServerlessInstancesApiRequest{ApiService: mockServerlessAPI}).Return(
- &admin.PaginatedServerlessInstanceDescription{
- Results: &[]admin.ServerlessInstanceDescription{
- {
- Name: pointer.MakePtr("testServerless"),
- ConnectionStrings: &admin.ServerlessInstanceDescriptionConnectionStrings{StandardSrv: pointer.MakePtr("serverlessSRV")},
- },
- },
- }, &http.Response{StatusCode: http.StatusOK}, nil)
-
mockFlexAPI := mockadmin.NewFlexClustersApi(t)
mockFlexAPI.EXPECT().ListFlexClusters(context.Background(), mock.Anything).Return(
admin.ListFlexClustersApiRequest{ApiService: mockFlexAPI})
@@ -134,29 +109,28 @@ func TestProductionAtlasDeployments_ListDeploymentConnections(t *testing.T) {
}, &http.Response{StatusCode: http.StatusOK}, nil)
ds := &ProductionAtlasDeployments{
- clustersAPI: mockClustersAPI,
- serverlessAPI: mockServerlessAPI,
- flexAPI: mockFlexAPI,
- isGov: false,
+ clustersAPI: mockClustersAPI,
+ flexAPI: mockFlexAPI,
+ isGov: false,
}
projectID := "testProjectID"
conns, err := ds.ListDeploymentConnections(context.Background(), projectID)
assert.Nil(t, err)
- assert.Equal(t, len(conns), 3)
+ assert.Equal(t, len(conns), 2)
})
}
func TestClusterExists(t *testing.T) {
tests := map[string]struct {
deployment *akov2.AtlasDeployment
- apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi)
+ apiMocker func() (admin.ClustersApi, admin.FlexClustersApi)
gov bool
result bool
err error
}{
"should fail to assert a cluster exists in atlas": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
flexAPI := mockadmin.NewFlexClustersApi(t)
flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "cluster0").
Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
@@ -164,54 +138,34 @@ func TestClusterExists(t *testing.T) {
Return(nil, nil, errors.New("failed to get cluster from atlas"))
clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, 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, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.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").
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")).
- Return(nil, nil, errors.New("failed to get serverless instance from atlas"))
-
- err := &admin.GenericOpenAPIError{}
- err.SetModel(admin.ApiError{ErrorCode: atlas.ClusterNotFound})
flexAPI := mockadmin.NewFlexClustersApi(t)
flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0").
Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")).
- Return(nil, nil, err)
+ Return(nil, nil, errors.New("failed to get serverless instance from atlas"))
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, 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, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.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, 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 := &admin.GenericOpenAPIError{}
err.SetModel(admin.ApiError{ErrorCode: atlas.NonFlexInFlexAPI})
@@ -221,39 +175,30 @@ func TestClusterExists(t *testing.T) {
flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")).
Return(nil, nil, err)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
},
"should return false when serverless instance doesn't exist": {
deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.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").
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")).
- Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceNotFound))
-
- err := &admin.GenericOpenAPIError{}
- err.SetModel(admin.ApiError{ErrorCode: atlas.NonFlexInFlexAPI})
-
flexAPI := mockadmin.NewFlexClustersApi(t)
flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0").
Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")).
- Return(nil, nil, err)
+ Return(nil, nil, atlasAPIError(atlas.ClusterNotFound))
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
},
"should return a cluster exists": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0").
Return(admin.GetClusterApiRequest{ApiService: clusterAPI})
@@ -264,8 +209,6 @@ func TestClusterExists(t *testing.T) {
nil,
)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
-
err := &admin.GenericOpenAPIError{}
err.SetModel(admin.ApiError{ErrorCode: atlas.NonFlexInFlexAPI})
@@ -275,55 +218,37 @@ func TestClusterExists(t *testing.T) {
flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")).
Return(nil, &http.Response{}, err)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: true,
},
"should return a serverless instance exists": {
deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.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").
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")).
- Return(
- atlasServerlessInstance(),
- nil,
- nil,
- )
-
- err := &admin.GenericOpenAPIError{}
- err.SetModel(admin.ApiError{ErrorCode: atlas.NonFlexInFlexAPI})
flexAPI := mockadmin.NewFlexClustersApi(t)
flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0").
Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")).
- Return(nil, nil, err)
+ Return(&admin.FlexClusterDescription20241113{}, nil, nil)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: true,
},
"should return false when asserting serverless instance exists in gov": {
deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.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)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
gov: true,
result: false,
@@ -332,8 +257,8 @@ func TestClusterExists(t *testing.T) {
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker()
- service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, tt.gov)
+ clusterAPI, flexAPI := tt.apiMocker()
+ service := NewAtlasDeployments(clusterAPI, nil, flexAPI, tt.gov)
result, err := service.ClusterExists(context.Background(), "project-id", tt.deployment.GetDeploymentName())
require.Equal(t, tt.err, err)
@@ -345,72 +270,64 @@ func TestClusterExists(t *testing.T) {
func TestGetDeployment(t *testing.T) {
tests := map[string]struct {
deployment *akov2.AtlasDeployment
- apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi)
+ apiMocker func() (admin.ClustersApi, admin.FlexClustersApi)
result Deployment
err error
}{
"should fail to retrieve cluster from atlas": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.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"))
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "project-id", mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, atlasAPIError(atlas.ClusterInstanceFromServerlessAPI))
-
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessAPI, flexAPI
+ return clusterAPI, 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, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
-
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().GetServerlessInstance(context.Background(), "project-id", "instance0").
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")).
- Return(nil, nil, errors.New("failed to get serverless instance from atlas"))
+ 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))
flexAPI := mockadmin.NewFlexClustersApi(t)
+ flexAPI.EXPECT().GetFlexCluster(context.Background(), "project-id", "instance0").
+ Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
+ flexAPI.EXPECT().GetFlexClusterExecute(mock.AnythingOfType("admin.GetFlexClusterApiRequest")).
+ Return(nil, nil, errors.New("failed to get serverless instance from atlas"))
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, 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, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.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, atlasAPIError(atlas.ClusterNotFound))
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "project-id", mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, atlasAPIError(atlas.ClusterInstanceFromServerlessAPI))
-
flexAPI := mockadmin.NewFlexClustersApi(t)
flexAPI.EXPECT().GetFlexCluster(mock.Anything, "project-id", mock.Anything).
Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
flexAPI.EXPECT().GetFlexClusterExecute(mock.Anything).Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI))
- return clusterAPI, serverlessAPI, flexAPI
+ return clusterAPI, flexAPI
},
},
"should return nil when serverless instance doesn't exist": {
deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "instance0").
Return(admin.GetClusterApiRequest{ApiService: clusterAPI})
@@ -420,20 +337,14 @@ func TestGetDeployment(t *testing.T) {
flexAPI := mockadmin.NewFlexClustersApi(t)
flexAPI.EXPECT().GetFlexCluster(mock.Anything, "project-id", mock.Anything).
Return(admin.GetFlexClusterApiRequest{ApiService: flexAPI})
- flexAPI.EXPECT().GetFlexClusterExecute(mock.Anything).Return(nil, nil, atlasAPIError(atlas.NonFlexInFlexAPI))
+ flexAPI.EXPECT().GetFlexClusterExecute(mock.Anything).Return(nil, nil, atlasAPIError(atlas.ClusterNotFound))
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().GetServerlessInstance(context.Background(), "project-id", "instance0").
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")).
- Return(nil, nil, atlasAPIError(atlas.ServerlessInstanceNotFound))
-
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
},
"should return a cluster": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetCluster(context.Background(), "project-id", "cluster0").
Return(admin.GetClusterApiRequest{ApiService: clusterAPI})
@@ -444,44 +355,18 @@ func TestGetDeployment(t *testing.T) {
nil,
)
- serverlessAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessAPI.EXPECT().GetServerlessInstance(mock.Anything, "project-id", mock.Anything).
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessAPI})
- serverlessAPI.EXPECT().GetServerlessInstanceExecute(mock.Anything).Return(nil, nil, atlasAPIError(atlas.ClusterInstanceFromServerlessAPI))
-
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: expectedGeoShardedCluster(),
},
- "should return a serverless instance": {
- deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
- clusterAPI := mockadmin.NewClustersApi(t)
-
- flexAPI := mockadmin.NewFlexClustersApi(t)
-
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().GetServerlessInstance(context.Background(), "project-id", "instance0").
- Return(admin.GetServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().GetServerlessInstanceExecute(mock.AnythingOfType("admin.GetServerlessInstanceApiRequest")).
- Return(
- atlasServerlessInstance(),
- nil,
- nil,
- )
-
- return clusterAPI, serverlessInstanceAPI, flexAPI
- },
- result: expectedServerlessInstance(),
- },
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker()
- service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false)
+ clusterAPI, flexAPI := tt.apiMocker()
+ service := NewAtlasDeployments(clusterAPI, nil, flexAPI, false)
result, err := service.GetDeployment(context.Background(), "project-id", tt.deployment)
require.Equal(t, tt.err, err)
@@ -493,44 +378,42 @@ func TestGetDeployment(t *testing.T) {
func TestCreateDeployment(t *testing.T) {
tests := map[string]struct {
deployment *akov2.AtlasDeployment
- apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi)
+ apiMocker func() (admin.ClustersApi, admin.FlexClustersApi)
result Deployment
err error
}{
"should fail to create cluster in atlas": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().CreateCluster(context.Background(), "project-id", mock.AnythingOfType("*admin.ClusterDescription20240805")).
Return(admin.CreateClusterApiRequest{ApiService: clusterAPI})
clusterAPI.EXPECT().CreateClusterExecute(mock.AnythingOfType("admin.CreateClusterApiRequest")).
Return(nil, nil, errors.New("failed to create cluster in atlas"))
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
err: errors.New("failed to create cluster in atlas"),
},
- "should fail to create serverless instance in atlas": {
+ "should fail to create flex cluster in atlas": {
deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().CreateServerlessInstance(context.Background(), "project-id", mock.AnythingOfType("*admin.ServerlessInstanceDescriptionCreate")).
- Return(admin.CreateServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().CreateServerlessInstanceExecute(mock.AnythingOfType("admin.CreateServerlessInstanceApiRequest")).
- Return(nil, nil, errors.New("failed to create serverless instance in atlas"))
-
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ flexAPI.EXPECT().CreateFlexCluster(context.Background(), "project-id", mock.AnythingOfType("*admin.FlexClusterDescriptionCreate20241113")).
+ Return(admin.CreateFlexClusterApiRequest{ApiService: flexAPI})
+ flexAPI.EXPECT().CreateFlexClusterExecute(mock.AnythingOfType("admin.CreateFlexClusterApiRequest")).
+ Return(nil, nil, errors.New("failed to create flex cluster in atlas"))
+
+ return clusterAPI, flexAPI
},
- err: errors.New("failed to create serverless instance in atlas"),
+ err: errors.New("failed to create flex cluster in atlas"),
},
"should create a cluster": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().CreateCluster(context.Background(), "project-id", mock.AnythingOfType("*admin.ClusterDescription20240805")).
Return(admin.CreateClusterApiRequest{ApiService: clusterAPI})
@@ -541,39 +424,18 @@ func TestCreateDeployment(t *testing.T) {
nil,
)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: expectedGeoShardedCluster(),
},
- "should create a serverless instance": {
- deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
- clusterAPI := mockadmin.NewClustersApi(t)
-
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().CreateServerlessInstance(context.Background(), "project-id", mock.AnythingOfType("*admin.ServerlessInstanceDescriptionCreate")).
- Return(admin.CreateServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().CreateServerlessInstanceExecute(mock.AnythingOfType("admin.CreateServerlessInstanceApiRequest")).
- Return(
- atlasServerlessInstance(),
- nil,
- nil,
- )
-
- flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
- },
- result: expectedServerlessInstance(),
- },
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker()
- service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false)
+ clusterAPI, flexAPI := tt.apiMocker()
+ service := NewAtlasDeployments(clusterAPI, nil, flexAPI, false)
result, err := service.CreateDeployment(context.Background(), NewDeployment("project-id", tt.deployment))
require.Equal(t, tt.err, err)
@@ -585,44 +447,42 @@ func TestCreateDeployment(t *testing.T) {
func TestUpdateDeployment(t *testing.T) {
tests := map[string]struct {
deployment *akov2.AtlasDeployment
- apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi)
+ apiMocker func() (admin.ClustersApi, admin.FlexClustersApi)
result Deployment
err error
}{
"should fail to update cluster in atlas": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().UpdateCluster(context.Background(), "project-id", "cluster0", mock.AnythingOfType("*admin.ClusterDescription20240805")).
Return(admin.UpdateClusterApiRequest{ApiService: clusterAPI})
clusterAPI.EXPECT().UpdateClusterExecute(mock.AnythingOfType("admin.UpdateClusterApiRequest")).
Return(nil, nil, errors.New("failed to update cluster in atlas"))
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
err: errors.New("failed to update cluster in atlas"),
},
- "should fail to update serverless instance in atlas": {
+ "should fail to update flex cluster in atlas": {
deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().UpdateServerlessInstance(context.Background(), "project-id", "instance0", mock.AnythingOfType("*admin.ServerlessInstanceDescriptionUpdate")).
- Return(admin.UpdateServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().UpdateServerlessInstanceExecute(mock.AnythingOfType("admin.UpdateServerlessInstanceApiRequest")).
- Return(nil, nil, errors.New("failed to update serverless instance in atlas"))
-
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ flexAPI.EXPECT().UpdateFlexCluster(context.Background(), "project-id", "instance0", mock.AnythingOfType("*admin.FlexClusterDescriptionUpdate20241113")).
+ Return(admin.UpdateFlexClusterApiRequest{ApiService: flexAPI})
+ flexAPI.EXPECT().UpdateFlexClusterExecute(mock.AnythingOfType("admin.UpdateFlexClusterApiRequest")).
+ Return(nil, nil, errors.New("failed to update flex cluster in atlas"))
+
+ return clusterAPI, flexAPI
},
- err: errors.New("failed to update serverless instance in atlas"),
+ err: errors.New("failed to update flex cluster in atlas"),
},
"should update a cluster": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().UpdateCluster(context.Background(), "project-id", "cluster0", mock.AnythingOfType("*admin.ClusterDescription20240805")).
Return(admin.UpdateClusterApiRequest{ApiService: clusterAPI})
@@ -633,39 +493,17 @@ func TestUpdateDeployment(t *testing.T) {
nil,
)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: expectedGeoShardedCluster(),
},
- "should update a serverless instance": {
- deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
- clusterAPI := mockadmin.NewClustersApi(t)
-
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().UpdateServerlessInstance(context.Background(), "project-id", "instance0", mock.AnythingOfType("*admin.ServerlessInstanceDescriptionUpdate")).
- Return(admin.UpdateServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().UpdateServerlessInstanceExecute(mock.AnythingOfType("admin.UpdateServerlessInstanceApiRequest")).
- Return(
- atlasServerlessInstance(),
- nil,
- nil,
- )
-
- flexAPI := mockadmin.NewFlexClustersApi(t)
-
- return clusterAPI, serverlessInstanceAPI, flexAPI
- },
- result: expectedServerlessInstance(),
- },
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker()
- service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false)
+ clusterAPI, flexAPI := tt.apiMocker()
+ service := NewAtlasDeployments(clusterAPI, nil, flexAPI, false)
result, err := service.UpdateDeployment(context.Background(), NewDeployment("project-id", tt.deployment))
require.Equal(t, tt.err, err)
@@ -677,82 +515,61 @@ func TestUpdateDeployment(t *testing.T) {
func TestDeleteDeployment(t *testing.T) {
tests := map[string]struct {
deployment *akov2.AtlasDeployment
- apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi)
+ apiMocker func() (admin.ClustersApi, admin.FlexClustersApi)
result Deployment
err error
}{
"should fail to delete cluster in atlas": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().DeleteCluster(context.Background(), "project-id", "cluster0").
Return(admin.DeleteClusterApiRequest{ApiService: clusterAPI})
clusterAPI.EXPECT().DeleteClusterExecute(mock.AnythingOfType("admin.DeleteClusterApiRequest")).
Return(nil, errors.New("failed to delete cluster in atlas"))
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
err: errors.New("failed to delete cluster in atlas"),
},
- "should fail to delete serverless instance in atlas": {
+ "should fail to delete flex cluster in atlas": {
deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().DeleteServerlessInstance(context.Background(), "project-id", "instance0").
- Return(admin.DeleteServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().DeleteServerlessInstanceExecute(mock.AnythingOfType("admin.DeleteServerlessInstanceApiRequest")).
- Return(nil, nil, errors.New("failed to delete serverless instance in atlas"))
-
flexAPI := mockadmin.NewFlexClustersApi(t)
+ flexAPI.EXPECT().DeleteFlexCluster(context.Background(), "project-id", "instance0").
+ Return(admin.DeleteFlexClusterApiRequest{ApiService: flexAPI})
+ flexAPI.EXPECT().DeleteFlexClusterExecute(mock.AnythingOfType("admin.DeleteFlexClusterApiRequest")).
+ Return(nil, errors.New("failed to delete flex cluster in atlas"))
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
- err: errors.New("failed to delete serverless instance in atlas"),
+ err: errors.New("failed to delete flex cluster in atlas"),
},
"should delete a cluster": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().DeleteCluster(context.Background(), "project-id", "cluster0").
Return(admin.DeleteClusterApiRequest{ApiService: clusterAPI})
clusterAPI.EXPECT().DeleteClusterExecute(mock.AnythingOfType("admin.DeleteClusterApiRequest")).
Return(nil, nil)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: expectedGeoShardedCluster(),
},
- "should delete a serverless instance": {
- deployment: serverlessInstance(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
- clusterAPI := mockadmin.NewClustersApi(t)
-
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- serverlessInstanceAPI.EXPECT().DeleteServerlessInstance(context.Background(), "project-id", "instance0").
- Return(admin.DeleteServerlessInstanceApiRequest{ApiService: serverlessInstanceAPI})
- serverlessInstanceAPI.EXPECT().DeleteServerlessInstanceExecute(mock.AnythingOfType("admin.DeleteServerlessInstanceApiRequest")).
- Return(nil, nil, nil)
-
- flexAPI := mockadmin.NewFlexClustersApi(t)
-
- return clusterAPI, serverlessInstanceAPI, flexAPI
- },
- result: expectedServerlessInstance(),
- },
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker()
- service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false)
+ clusterAPI, flexAPI := tt.apiMocker()
+ service := NewAtlasDeployments(clusterAPI, nil, flexAPI, false)
err := service.DeleteDeployment(context.Background(), NewDeployment("project-id", tt.deployment))
require.Equal(t, tt.err, err)
@@ -763,29 +580,28 @@ func TestDeleteDeployment(t *testing.T) {
func TestClusterWithProcessArgs(t *testing.T) {
tests := map[string]struct {
deployment *akov2.AtlasDeployment
- apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi)
+ apiMocker func() (admin.ClustersApi, admin.FlexClustersApi)
result Deployment
err error
}{
"should fail to retrieve cluster process args from atlas": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0").
Return(admin.GetClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI})
clusterAPI.EXPECT().GetClusterAdvancedConfigurationExecute(mock.AnythingOfType("admin.GetClusterAdvancedConfigurationApiRequest")).
Return(nil, nil, errors.New("failed to get cluster process args from atlas"))
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, 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, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0").
Return(admin.GetClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI})
@@ -800,10 +616,9 @@ func TestClusterWithProcessArgs(t *testing.T) {
nil,
)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: &Cluster{
ProcessArgs: &akov2.ProcessArgs{
@@ -815,7 +630,7 @@ func TestClusterWithProcessArgs(t *testing.T) {
},
"should return process args": {
deployment: geoShardedCluster(),
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().GetClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0").
Return(admin.GetClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI})
@@ -835,10 +650,9 @@ func TestClusterWithProcessArgs(t *testing.T) {
nil,
)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: &Cluster{
ProcessArgs: &akov2.ProcessArgs{
@@ -857,8 +671,8 @@ func TestClusterWithProcessArgs(t *testing.T) {
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker()
- service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false)
+ clusterAPI, flexAPI := tt.apiMocker()
+ service := NewAtlasDeployments(clusterAPI, nil, flexAPI, false)
d := NewDeployment("project-id", tt.deployment)
cluster := d.(*Cluster)
@@ -874,7 +688,7 @@ func TestClusterWithProcessArgs(t *testing.T) {
func TestUpdateProcessArgs(t *testing.T) {
tests := map[string]struct {
deployment Deployment
- apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi)
+ apiMocker func() (admin.ClustersApi, admin.FlexClustersApi)
result Deployment
err error
}{
@@ -888,12 +702,11 @@ func TestUpdateProcessArgs(t *testing.T) {
OplogMinRetentionHours: "wrong",
},
},
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
err: &strconv.NumError{Func: "ParseFloat", Num: "wrong", Err: errors.New("invalid syntax")},
},
@@ -913,17 +726,16 @@ func TestUpdateProcessArgs(t *testing.T) {
OplogMinRetentionHours: "12.0",
},
},
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().UpdateClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0", mock.AnythingOfType("*admin.ClusterDescriptionProcessArgs20240805")).
Return(admin.UpdateClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI})
clusterAPI.EXPECT().UpdateClusterAdvancedConfigurationExecute(mock.AnythingOfType("admin.UpdateClusterAdvancedConfigurationApiRequest")).
Return(nil, nil, errors.New("failed to update cluster process args in atlas"))
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
err: errors.New("failed to update cluster process args in atlas"),
},
@@ -943,7 +755,7 @@ func TestUpdateProcessArgs(t *testing.T) {
OplogMinRetentionHours: "12.0",
},
},
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
clusterAPI.EXPECT().UpdateClusterAdvancedConfiguration(context.Background(), "project-id", "cluster0", mock.AnythingOfType("*admin.ClusterDescriptionProcessArgs20240805")).
Return(admin.UpdateClusterAdvancedConfigurationApiRequest{ApiService: clusterAPI})
@@ -963,10 +775,9 @@ func TestUpdateProcessArgs(t *testing.T) {
nil,
)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: &Cluster{
ProcessArgs: &akov2.ProcessArgs{
@@ -985,8 +796,8 @@ func TestUpdateProcessArgs(t *testing.T) {
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker()
- service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false)
+ clusterAPI, flexAPI := tt.apiMocker()
+ service := NewAtlasDeployments(clusterAPI, nil, flexAPI, false)
cluster := tt.deployment.(*Cluster)
err := service.UpdateProcessArgs(context.Background(), cluster)
@@ -1002,30 +813,19 @@ func TestUpgradeCluster(t *testing.T) {
tests := map[string]struct {
currentDeployment Deployment
targetDeployment Deployment
- apiMocker func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi)
+ apiMocker func() (admin.ClustersApi, admin.FlexClustersApi)
result Deployment
err error
}{
"should fail to upgrade shared cluster in atlas": {
currentDeployment: &Cluster{},
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
err: errors.New("upgrade from shared to dedicated is not supported"),
},
- "should fail to upgrade serverless instance in atlas": {
- currentDeployment: &Serverless{},
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
- clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
- flexAPI := mockadmin.NewFlexClustersApi(t)
- return clusterAPI, serverlessInstanceAPI, flexAPI
- },
- err: errors.New("upgrade from serverless to dedicated is not supported"),
- },
"should fail to upgrade flex instance in atlas": {
currentDeployment: &Flex{},
targetDeployment: &Cluster{
@@ -1038,15 +838,14 @@ func TestUpgradeCluster(t *testing.T) {
},
},
},
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
flexAPI.EXPECT().UpgradeFlexCluster(context.Background(), "project-id", mock.AnythingOfType("*admin.AtlasTenantClusterUpgradeRequest20240805")).
Return(admin.UpgradeFlexClusterApiRequest{ApiService: flexAPI})
flexAPI.EXPECT().UpgradeFlexClusterExecute(mock.AnythingOfType("admin.UpgradeFlexClusterApiRequest")).
Return(nil, &http.Response{}, errors.New("failed to upgrade flex cluster in atlas"))
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
err: errors.New("failed to upgrade flex cluster in atlas"),
},
@@ -1062,9 +861,8 @@ func TestUpgradeCluster(t *testing.T) {
},
},
},
- apiMocker: func() (admin.ClustersApi, admin.ServerlessInstancesApi, admin.FlexClustersApi) {
+ apiMocker: func() (admin.ClustersApi, admin.FlexClustersApi) {
clusterAPI := mockadmin.NewClustersApi(t)
- serverlessInstanceAPI := mockadmin.NewServerlessInstancesApi(t)
flexAPI := mockadmin.NewFlexClustersApi(t)
flexAPI.EXPECT().UpgradeFlexCluster(context.Background(), "project-id", mock.AnythingOfType("*admin.AtlasTenantClusterUpgradeRequest20240805")).
Return(admin.UpgradeFlexClusterApiRequest{ApiService: flexAPI})
@@ -1074,7 +872,7 @@ func TestUpgradeCluster(t *testing.T) {
&http.Response{},
nil,
)
- return clusterAPI, serverlessInstanceAPI, flexAPI
+ return clusterAPI, flexAPI
},
result: &Flex{
FlexSpec: &akov2.FlexSpec{
@@ -1089,8 +887,8 @@ func TestUpgradeCluster(t *testing.T) {
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- clusterAPI, serverlessInstanceAPI, flexAPI := tt.apiMocker()
- service := NewAtlasDeployments(clusterAPI, serverlessInstanceAPI, nil, flexAPI, false)
+ clusterAPI, flexAPI := tt.apiMocker()
+ service := NewAtlasDeployments(clusterAPI, nil, flexAPI, false)
result, err := service.UpgradeToDedicated(context.Background(), tt.currentDeployment, tt.targetDeployment)
require.Equal(t, tt.err, err)
@@ -1789,92 +1587,3 @@ func serverlessInstance() *akov2.AtlasDeployment {
},
}
}
-
-func expectedServerlessInstance() *Serverless {
- return &Serverless{
- ProjectID: "project-id",
- ServerlessSpec: &akov2.ServerlessSpec{
- Name: "instance0",
- ProviderSettings: &akov2.ServerlessProviderSettingsSpec{
- ProviderName: "SERVERLESS",
- BackingProviderName: "AWS",
- RegionName: "US_EAST_1",
- },
- BackupOptions: akov2.ServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: true,
- },
- TerminationProtectionEnabled: true,
- Tags: []*akov2.TagSpec{
- {
- Key: "A",
- Value: "A",
- },
- {
- Key: "B",
- Value: "B",
- },
- },
- },
- State: "IDLE",
- MongoDBVersion: "7.3.3",
- Connection: &status.ConnectionStrings{
- StandardSrv: "standard-str",
- PrivateEndpoint: []status.PrivateEndpoint{
- {
- SRVConnectionString: "connection-srv-str",
- Endpoints: []status.Endpoint{
- {
- ProviderName: "AWS",
- Region: "US_EAST_1",
- EndpointID: "arn-endpoint-id",
- },
- },
- },
- },
- },
- }
-}
-
-func atlasServerlessInstance() *admin.ServerlessInstanceDescription {
- return &admin.ServerlessInstanceDescription{
- GroupId: pointer.MakePtr("project-id"),
- Name: pointer.MakePtr("instance0"),
- ProviderSettings: admin.ServerlessProviderSettings{
- ProviderName: pointer.MakePtr("SERVERLESS"),
- BackingProviderName: "AWS",
- RegionName: "US_EAST_1",
- },
- ServerlessBackupOptions: &admin.ClusterServerlessBackupOptions{
- ServerlessContinuousBackupEnabled: pointer.MakePtr(true),
- },
- TerminationProtectionEnabled: pointer.MakePtr(true),
- Tags: &[]admin.ResourceTag{
- {
- Key: "B",
- Value: "B",
- },
- {
- Key: "A",
- Value: "A",
- },
- },
- StateName: pointer.MakePtr("IDLE"),
- MongoDBVersion: pointer.MakePtr("7.3.3"),
- ConnectionStrings: &admin.ServerlessInstanceDescriptionConnectionStrings{
- StandardSrv: pointer.MakePtr("standard-str"),
- PrivateEndpoint: &[]admin.ServerlessConnectionStringsPrivateEndpointList{
- {
- SrvConnectionString: pointer.MakePtr("connection-srv-str"),
- Endpoints: &[]admin.ServerlessConnectionStringsPrivateEndpointItem{
- {
- ProviderName: pointer.MakePtr("AWS"),
- Region: pointer.MakePtr("US_EAST_1"),
- EndpointId: pointer.MakePtr("arn-endpoint-id"),
- },
- },
- Type: pointer.MakePtr("MONGOS"),
- },
- },
- },
- }
-}
diff --git a/test/int/deployment_test.go b/test/int/deployment_test.go
index db44e568be..4dc5d4b1a2 100644
--- a/test/int/deployment_test.go
+++ b/test/int/deployment_test.go
@@ -79,7 +79,7 @@ var _ = Describe("AtlasDeployment", Label("int", "AtlasDeployment", "deployment-
BeforeEach(func() {
prepareControllers(false)
- deploymentService = deployment.NewAtlasDeployments(atlasClient.ClustersApi, atlasClient.ServerlessInstancesApi, atlasClient.GlobalClustersApi, atlasClient.FlexClustersApi, false)
+ deploymentService = deployment.NewAtlasDeployments(atlasClient.ClustersApi, atlasClient.GlobalClustersApi, atlasClient.FlexClustersApi, false)
createdDeployment = &akov2.AtlasDeployment{}
manualDeletion = false
@@ -1439,7 +1439,7 @@ var _ = Describe("AtlasDeploymentSharding", Label("int", "AtlasDeploymentShardin
BeforeEach(func() {
prepareControllers(false)
- deployment.NewAtlasDeployments(atlasClient.ClustersApi, atlasClient.ServerlessInstancesApi, atlasClient.GlobalClustersApi, atlasClient.FlexClustersApi, false)
+ deployment.NewAtlasDeployments(atlasClient.ClustersApi, atlasClient.GlobalClustersApi, atlasClient.FlexClustersApi, false)
createdDeployment = &akov2.AtlasDeployment{}
manualDeletion = false
diff --git a/version.json b/version.json
index c44ac30594..2ce490c8e9 100644
--- a/version.json
+++ b/version.json
@@ -1,4 +1,4 @@
{
"current": "2.11.1",
- "next": "2.11.2"
+ "next": "2.12.0"
}