Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pkg/controller/atlas/api_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ const (
// The error that Atlas API returns if the GET request is sent to read the project that either doesn't exist
// or the user doesn't have permissions for
NotInGroup = "NOT_IN_GROUP"

// Error indicates that the project is being removed while it still has clusters
CannotCloseGroupActiveAtlasCluster = "CANNOT_CLOSE_GROUP_ACTIVE_ATLAS_CLUSTERS"
)
6 changes: 3 additions & 3 deletions pkg/controller/atlascluster/atlascluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (r *AtlasClusterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error
}
ctx := customresource.MarkReconciliationStarted(r.Client, cluster, log)

log.Infow("-> Starting AtlasCluster reconciliation", "spec", cluster.Spec)
log.Infow("-> Starting AtlasCluster reconciliation", "spec", cluster.Spec, "generation", cluster.Generation, "status", cluster.Status)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vasilevp this one was added for debugging issue - I expect there are sometimes caching problems and that's why our tests are flaky

defer statushandler.Update(ctx, r.Client, cluster)

project := &mdbv1.AtlasProject{}
Expand Down Expand Up @@ -135,12 +135,12 @@ func (r *AtlasClusterReconciler) Delete(obj runtime.Object) error {
return errors.New("cannot read Atlas connection")
}

client, err := atlas.Client(connection, log)
atlasClient, err := atlas.Client(connection, log)
if err != nil {
return fmt.Errorf("cannot build Atlas client: %w", err)
}

_, err = client.Clusters.Delete(context.Background(), project.Status.ID, cluster.Name)
_, err = atlasClient.Clusters.Delete(context.Background(), project.Status.ID, cluster.Spec.Name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️

if err != nil {
return fmt.Errorf("cannot delete Atlas cluster: %w", err)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/util/testutil/customresources.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func WaitFor(k8sClient client.Client, createdResource mdbv1.AtlasCustomResource,
return false
}
// Atlas Operator hasn't started working yet
fmt.Printf("Generation: %+v, observed Generation: %+v\n", createdResource.GetGeneration(), createdResource.GetStatus().GetObservedGeneration())
if createdResource.GetGeneration() != createdResource.GetStatus().GetObservedGeneration() {
return false
}
Expand Down
53 changes: 34 additions & 19 deletions test/int/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ package int

import (
"context"
"errors"
"fmt"
"net/http"
"time"

mdbv1 "github.com/mongodb/mongodb-atlas-kubernetes/pkg/api/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/pkg/api/v1/status"
"github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/atlas"
"github.com/mongodb/mongodb-atlas-kubernetes/pkg/controller/workflow"
"github.com/mongodb/mongodb-atlas-kubernetes/pkg/util/kube"
"github.com/mongodb/mongodb-atlas-kubernetes/pkg/util/testutil"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"go.mongodb.org/atlas/mongodbatlas"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand Down Expand Up @@ -59,21 +62,24 @@ var _ = Describe("AtlasCluster", func() {
AfterEach(func() {
if createdProject != nil && createdProject.Status.ID != "" {
if createdCluster != nil {
By("Removing Atlas Cluster " + createdCluster.Spec.Name)
_, _ = atlasClient.Clusters.Delete(context.Background(), createdProject.Status.ID, createdCluster.Spec.Name)
By("Removing Atlas Cluster " + createdCluster.Name)
Expect(k8sClient.Delete(context.Background(), createdCluster)).To(Succeed())

Eventually(checkAtlasClusterRemoved(createdProject.Status.ID, createdCluster.Name), 600, interval).Should(BeTrue())
}
// TODO need to wait for the cluster to get removed
// By("Removing Atlas Project " + createdProject.Status.ID)
// _, err := atlasClient.Projects.Delete(context.Background(), createdProject.Status.ID)
// Expect(err).ToNot(HaveOccurred())
By("Removing Atlas Project " + createdProject.Status.ID)
// This is a bit strange but the delete request right after the cluster is removed may fail with "Still active cluster" error
// UI shows the cluster being deleted though. Seems to be the issue only if removal is done using API,
// if the cluster is terminated using UI - it stays in "Deleting" state
Eventually(removeAtlasProject(createdProject.Status.ID), 600, interval).Should(BeTrue())
}

By("Removing the namespace " + namespace.Name)
err := k8sClient.Delete(context.Background(), &namespace)
Expect(err).ToNot(HaveOccurred())
})

Describe("Create/Update/Delete the cluster", func() {
Describe("Create/Update the cluster", func() {
It("Should Succeed", func() {
expectedCluster := testAtlasCluster(namespace.Name, "test-cluster", createdProject.Name)

Expand Down Expand Up @@ -137,16 +143,12 @@ var _ = Describe("AtlasCluster", func() {
Expect(err).ToNot(HaveOccurred())

Expect(atlasCluster.Name).To(Equal(createdAtlasCluster.Name))
print(createdCluster.Labels)
print(createdAtlasCluster.Labels)
Expect(atlasCluster.Labels).To(Equal(createdAtlasCluster.Labels))
Expect(atlasCluster.ProviderSettings.InstanceSizeName).To(Equal(createdAtlasCluster.ProviderSettings.InstanceSizeName))
Expect(atlasCluster.ProviderSettings.ProviderName).To(Equal(createdAtlasCluster.ProviderSettings.ProviderName))
Expect(atlasCluster.ProviderSettings.RegionName).To(Equal(createdAtlasCluster.ProviderSettings.RegionName))

By("Deleting the cluster")
err = k8sClient.Delete(context.Background(), createdCluster)
Expect(err).ToNot(HaveOccurred())

Eventually(checkAtlasDeleteStarted(createdProject.Status.ID, createdCluster.Name), 1200, interval).Should(BeTrue())
})
})
})
Expand Down Expand Up @@ -182,7 +184,7 @@ func testAtlasCluster(namespace, name, projectName string) *mdbv1.AtlasCluster {
Namespace: namespace,
},
Spec: mdbv1.AtlasClusterSpec{
Name: "test-cluster",
Name: "test-atlas-cluster",
Project: mdbv1.ResourceRef{Name: projectName},
ProviderSettings: &mdbv1.ProviderSettingsSpec{
InstanceSizeName: "M10",
Expand All @@ -192,18 +194,31 @@ func testAtlasCluster(namespace, name, projectName string) *mdbv1.AtlasCluster {
},
}
}
func checkAtlasDeleteStarted(projectID string, clusterName string) func() bool {

// checkAtlasClusterRemoved returns true if the Atlas Cluster is removed from Atlas. Note the behavior: the cluster
// is removed from Atlas as soon as the DELETE API call has been made. This is different from the case when the
// cluster is terminated from UI (in this case GET request succeeds while the cluster is being terminated)
func checkAtlasClusterRemoved(projectID string, clusterName string) func() bool {
return func() bool {
c, r, err := atlasClient.Clusters.Get(context.Background(), projectID, clusterName)
_, r, err := atlasClient.Clusters.Get(context.Background(), projectID, clusterName)
if err != nil {
// cluster already deleted - that's fine for us
if r != nil && r.StatusCode == http.StatusNotFound {
return true
}
}
return false
}
}

func removeAtlasProject(projectID string) func() bool {
return func() bool {
_, err := atlasClient.Projects.Delete(context.Background(), projectID)
if err != nil {
var apiError *mongodbatlas.ErrorResponse
Expect(errors.As(err, &apiError)).To(BeTrue())
Expect(apiError.ErrorCode).To(Equal(atlas.CannotCloseGroupActiveAtlasCluster))
return false
}

return c.StateName == "DELETING" || c.StateName == "DELETED"
return true
}
}