diff --git a/pkg/api/v1/status/atlasdeployment.go b/pkg/api/v1/status/atlasdeployment.go index 929e8ab06c..23713b7742 100644 --- a/pkg/api/v1/status/atlasdeployment.go +++ b/pkg/api/v1/status/atlasdeployment.go @@ -171,6 +171,18 @@ func AtlasDeploymentMongoURIUpdatedOption(mongoURIUpdated string) AtlasDeploymen } } +func AtlasDeploymentRemoveStatusesWithEmptyIDs() AtlasDeploymentStatusOption { + return func(s *AtlasDeploymentStatus) { + var result []DeploymentSearchIndexStatus + for i := range s.SearchIndexes { + if s.SearchIndexes[i].ID != "" { + result = append(result, s.SearchIndexes[i]) + } + } + s.SearchIndexes = result + } +} + // AtlasDeploymentSetSearchIndexStatus set the status for one SearchIndex func AtlasDeploymentSetSearchIndexStatus(indexStatus DeploymentSearchIndexStatus) AtlasDeploymentStatusOption { return func(s *AtlasDeploymentStatus) { diff --git a/pkg/controller/atlasdeployment/searchindexes.go b/pkg/controller/atlasdeployment/searchindexes.go index 78a25b3eba..c36271e770 100644 --- a/pkg/controller/atlasdeployment/searchindexes.go +++ b/pkg/controller/atlasdeployment/searchindexes.go @@ -151,5 +151,6 @@ func (sr *searchIndexesReconciler) empty() workflow.Result { func (sr *searchIndexesReconciler) idle() workflow.Result { sr.ctx.SetConditionTrue(status.SearchIndexesReadyType) + sr.ctx.EnsureStatusOption(status.AtlasDeploymentRemoveStatusesWithEmptyIDs()) return workflow.OK() } diff --git a/pkg/controller/atlasdeployment/searchindexes_test.go b/pkg/controller/atlasdeployment/searchindexes_test.go index 2bb743b983..59c84c5c0f 100644 --- a/pkg/controller/atlasdeployment/searchindexes_test.go +++ b/pkg/controller/atlasdeployment/searchindexes_test.go @@ -6,6 +6,8 @@ import ( "net/http" "testing" + internal "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/searchindex" + "github.com/stretchr/testify/mock" "go.mongodb.org/atlas-sdk/v20231115008/admin" "go.mongodb.org/atlas-sdk/v20231115008/mockadmin" @@ -128,6 +130,110 @@ func Test_SearchIndexesReconcile(t *testing.T) { assert.False(t, result.IsOk()) }) + t.Run("Should cleanup indexes with empty IDs when IDLE", func(t *testing.T) { + searchIndexConfig := &akov2.AtlasSearchIndexConfig{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "testConfig", + Namespace: "testNamespace", + }, + Spec: akov2.AtlasSearchIndexConfigSpec{ + Analyzer: pointer.MakePtr("testAnalyzer"), + }, + Status: status.AtlasSearchIndexConfigStatus{}, + } + IDForStatus := "123" + deployment := &akov2.AtlasDeployment{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: akov2.AtlasDeploymentSpec{ + DeploymentSpec: &akov2.AdvancedDeploymentSpec{ + Name: "testDeployment", + SearchIndexes: []akov2.SearchIndex{ + { + Name: "Index1", + Type: IndexTypeSearch, + Search: &akov2.Search{ + Synonyms: &([]akov2.Synonym{ + { + Name: "testSynonym", + Analyzer: "testAnalyzer", + Source: akov2.Source{ + Collection: "testCollection", + }, + }, + }), + Mappings: nil, + SearchConfigurationRef: common.ResourceRefNamespaced{ + Name: searchIndexConfig.Name, + Namespace: searchIndexConfig.Namespace, + }, + }, + }, + }, + }, + }, + Status: status.AtlasDeploymentStatus{ + SearchIndexes: []status.DeploymentSearchIndexStatus{ + { + Name: "Index1", + ID: IDForStatus, + Status: "", + Message: "", + }, + { + Name: "Index2", + ID: "", + Status: "", + Message: "", + }, + }, + }, + } + + sch := runtime.NewScheme() + assert.Nil(t, akov2.AddToScheme(sch)) + assert.Nil(t, corev1.AddToScheme(sch)) + + atlasIdxToReturn, err := internal.NewSearchIndexFromAKO(&deployment.Spec.DeploymentSpec.SearchIndexes[0], + &searchIndexConfig.Spec).ToAtlas() + assert.NoError(t, err) + mockSearchAPI := mockadmin.NewAtlasSearchApi(t) + mockSearchAPI.EXPECT(). + GetAtlasSearchIndex(context.Background(), mock.Anything, mock.Anything, mock.Anything). + Return(admin.GetAtlasSearchIndexApiRequest{ApiService: mockSearchAPI}) + mockSearchAPI.EXPECT(). + GetAtlasSearchIndexExecute(admin.GetAtlasSearchIndexApiRequest{ApiService: mockSearchAPI}). + Return( + atlasIdxToReturn, + &http.Response{StatusCode: http.StatusCreated}, nil, + ) + + k8sClient := fake.NewClientBuilder(). + WithScheme(sch). + WithObjects(deployment, searchIndexConfig). + Build() + + reconciler := searchIndexesReconciler{ + ctx: &workflow.Context{ + Log: zap.S(), + OrgID: "testOrgID", + Client: nil, + SdkClient: &admin.APIClient{AtlasSearchApi: mockSearchAPI}, + Context: context.Background(), + }, + deployment: deployment, + k8sClient: k8sClient, + projectID: "testProjectID", + } + + result := reconciler.Reconcile() + assert.True(t, result.IsOk()) + deployment.UpdateStatus(reconciler.ctx.Conditions(), reconciler.ctx.StatusOptions()...) + assert.Len(t, deployment.Status.SearchIndexes, 1) + assert.True(t, deployment.Status.SearchIndexes[0].ID == IDForStatus) + }) + t.Run("Should proceed with the index Type Search: CREATE INDEX", func(t *testing.T) { mockSearchAPI := mockadmin.NewAtlasSearchApi(t) mockSearchAPI.EXPECT().