From cf82255807c85527fb84b5e188ba01368d7e523b Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Tue, 26 Sep 2023 17:56:17 +0600 Subject: [PATCH] EVEREST-203 Do not run registration for already registered k8s clusters (#151) * EVEREST-203 Do not run registration for already registered k8s clusters * EVEREST-203 Generated files * EVEREST-203 Added integration test * EVEREST-203 Fixed test * EVEREST-203 fixed test * EVEREST-203 Better deletion handling * EVEREST-203 Shut up linter * Update pkg/install/operators.go Co-authored-by: Michal Kralik --------- Co-authored-by: Michal Kralik --- cli-tests/tests/flow/pg-operator.spec.ts | 20 ++++++++++++- pkg/install/deps.go | 3 ++ .../mock_everest_client_connector_test.go | 28 ++++++++++++++++++- pkg/install/operators.go | 20 +++++++++++++ .../client/mock_kube_client_connector.go | 2 +- 5 files changed, 70 insertions(+), 3 deletions(-) diff --git a/cli-tests/tests/flow/pg-operator.spec.ts b/cli-tests/tests/flow/pg-operator.spec.ts index 774b9f54..92d66b1d 100644 --- a/cli-tests/tests/flow/pg-operator.spec.ts +++ b/cli-tests/tests/flow/pg-operator.spec.ts @@ -38,7 +38,6 @@ test.describe('Everest CLI install operators', async () => { await out.outNotContains([ 'percona-server-mongodb-operator', - 'percona-xtradb-cluster-operator', ]); }); }; @@ -59,6 +58,25 @@ test.describe('Everest CLI install operators', async () => { await page.waitForTimeout(10_000); + await verifyClusterResources(); + await apiVerifyClusterExists(request, clusterName); + + await test.step('re-run everest install operators command', async () => { + const out = await cli.everestExecSkipWizard( + `install operators --operator.mongodb=false --operator.postgresql=true --operator.xtradb-cluster=true --backup.enable=0 --monitoring.enable=0 --name=${clusterName}`, + ); + + await out.assertSuccess(); + await out.outErrContainsNormalizedMany([ + 'percona-xtradb-cluster-operator operator has been installed', + 'everest-operator operator has been installed', + ]); + await out.outNotContains([ + 'Connected Kubernetes cluster to Everest', + ]); + }); + await page.waitForTimeout(10_000); + await verifyClusterResources(); await apiVerifyClusterExists(request, clusterName); await cliDeleteCluster(cli, request, clusterName); diff --git a/pkg/install/deps.go b/pkg/install/deps.go index 123f28d9..2b9fb49b 100644 --- a/pkg/install/deps.go +++ b/pkg/install/deps.go @@ -25,6 +25,9 @@ import ( //go:generate ../../bin/mockery --name=everestClientConnector --case=snake --inpackage --testonly type everestClientConnector interface { + ListKubernetesClusters( + ctx context.Context, + ) ([]client.KubernetesCluster, error) RegisterKubernetesCluster( ctx context.Context, body client.RegisterKubernetesClusterJSONRequestBody, diff --git a/pkg/install/mock_everest_client_connector_test.go b/pkg/install/mock_everest_client_connector_test.go index 259aba5f..d4ddf190 100644 --- a/pkg/install/mock_everest_client_connector_test.go +++ b/pkg/install/mock_everest_client_connector_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.32.4. DO NOT EDIT. +// Code generated by mockery v2.32.3. DO NOT EDIT. package install @@ -92,6 +92,32 @@ func (_m *mockEverestClientConnector) GetMonitoringInstance(ctx context.Context, return r0, r1 } +// ListKubernetesClusters provides a mock function with given fields: ctx +func (_m *mockEverestClientConnector) ListKubernetesClusters(ctx context.Context) ([]client.KubernetesCluster, error) { + ret := _m.Called(ctx) + + var r0 []client.KubernetesCluster + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]client.KubernetesCluster, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []client.KubernetesCluster); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]client.KubernetesCluster) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // ListMonitoringInstances provides a mock function with given fields: ctx func (_m *mockEverestClientConnector) ListMonitoringInstances(ctx context.Context) ([]client.MonitoringInstanceBaseWithName, error) { ret := _m.Called(ctx) diff --git a/pkg/install/operators.go b/pkg/install/operators.go index 831781d1..2e1af8a5 100644 --- a/pkg/install/operators.go +++ b/pkg/install/operators.go @@ -32,6 +32,8 @@ import ( "golang.org/x/sync/errgroup" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "github.com/percona/percona-everest-cli/commands/common" @@ -780,6 +782,24 @@ func (o *Operators) provisionMonitoring() error { // connectToEverest connects the k8s cluster to Everest. func (o *Operators) connectToEverest(ctx context.Context) (*client.KubernetesCluster, error) { + clusters, err := o.everestClient.ListKubernetesClusters(ctx) + if err != nil { + return nil, errors.Join(err, errors.New("could not list kubernetes clusters")) + } + for _, cluster := range clusters { + if cluster.Name == o.config.Name { + ns, err := o.kubeClient.GetNamespace(ctx, cluster.Namespace) + if err != nil && !k8serrors.IsNotFound(err) { + return nil, errors.Join(err, errors.New("could not get namespace from Kubernetes")) + } + + if ns.UID != types.UID(cluster.Uid) { + return nil, errors.New("namespace UID mismatch. It looks like you're trying to register a new Kubernetes cluster using an existing name. Please unregister the existing Kubernetes cluster first") + } + // Cluster is already registered. Do nothing + return &cluster, nil + } + } if err := o.prepareServiceAccount(); err != nil { return nil, errors.Join(err, errors.New("could not prepare a service account")) } diff --git a/pkg/kubernetes/client/mock_kube_client_connector.go b/pkg/kubernetes/client/mock_kube_client_connector.go index c3988f68..21963fe1 100644 --- a/pkg/kubernetes/client/mock_kube_client_connector.go +++ b/pkg/kubernetes/client/mock_kube_client_connector.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.32.4. DO NOT EDIT. +// Code generated by mockery v2.32.3. DO NOT EDIT. package client