diff --git a/controllers/clusters/cadence_controller.go b/controllers/clusters/cadence_controller.go index 35026415c..3c95990b9 100644 --- a/controllers/clusters/cadence_controller.go +++ b/controllers/clusters/cadence_controller.go @@ -30,16 +30,17 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/instaclustr/operator/apis/clusters/v1beta1" "github.com/instaclustr/operator/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" "github.com/instaclustr/operator/pkg/models" + "github.com/instaclustr/operator/pkg/ratelimiter" "github.com/instaclustr/operator/pkg/scheduler" ) @@ -73,36 +74,36 @@ func (r *CadenceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct logger.Info("Cadence resource is not found", "resource name", req.NamespacedName, ) - return models.ExitReconcile, nil + return ctrl.Result{}, nil } logger.Error(err, "Unable to fetch Cadence resource", "resource name", req.NamespacedName, ) - return models.ReconcileRequeue, nil + return ctrl.Result{}, err } switch cadenceCluster.Annotations[models.ResourceStateAnnotation] { case models.CreatingEvent: - return r.HandleCreateCluster(ctx, cadenceCluster, logger), nil + return r.HandleCreateCluster(ctx, cadenceCluster, logger) case models.UpdatingEvent: - return r.HandleUpdateCluster(ctx, cadenceCluster, logger), nil + return r.HandleUpdateCluster(ctx, cadenceCluster, logger) case models.DeletingEvent: - return r.HandleDeleteCluster(ctx, cadenceCluster, logger), nil + return r.HandleDeleteCluster(ctx, cadenceCluster, logger) case models.GenericEvent: logger.Info("Generic event isn't handled", "request", req, "event", cadenceCluster.Annotations[models.ResourceStateAnnotation], ) - return models.ExitReconcile, nil + return ctrl.Result{}, nil default: logger.Info("Unknown event isn't handled", "request", req, "event", cadenceCluster.Annotations[models.ResourceStateAnnotation], ) - return models.ExitReconcile, nil + return ctrl.Result{}, nil } } @@ -110,7 +111,7 @@ func (r *CadenceReconciler) HandleCreateCluster( ctx context.Context, cadence *v1beta1.Cadence, logger logr.Logger, -) reconcile.Result { +) (ctrl.Result, error) { if cadence.Status.ID == "" { patch := cadence.NewPatch() @@ -124,7 +125,7 @@ func (r *CadenceReconciler) HandleCreateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.CreationFailed, "Cannot prepare packaged solution for Cadence cluster. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } if requeueNeeded { @@ -134,7 +135,7 @@ func (r *CadenceReconciler) HandleCreateCluster( r.EventRecorder.Event(cadence, models.Normal, "Waiting", "Waiting for bundled clusters to be created") - return models.ReconcileRequeue + return models.ReconcileRequeue, nil } } @@ -152,7 +153,7 @@ func (r *CadenceReconciler) HandleCreateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.ConvertionFailed, "Cluster convertion from the Instaclustr API to k8s resource is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } id, err := r.API.CreateCluster(instaclustr.CadenceEndpoint, cadenceAPISpec) @@ -164,7 +165,7 @@ func (r *CadenceReconciler) HandleCreateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.CreationFailed, "Cluster creation on the Instaclustr is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } cadence.Status.ID = id @@ -178,7 +179,7 @@ func (r *CadenceReconciler) HandleCreateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.PatchFailed, "Cluster resource status patch is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } if cadence.Spec.Description != "" { @@ -206,7 +207,7 @@ func (r *CadenceReconciler) HandleCreateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.PatchFailed, "Cluster resource status patch is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } logger.Info( @@ -232,21 +233,21 @@ func (r *CadenceReconciler) HandleCreateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.CreationFailed, "Cluster status check job is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } r.EventRecorder.Event(cadence, models.Normal, models.Created, "Cluster status check job is started") } - return models.ExitReconcile + return ctrl.Result{}, nil } func (r *CadenceReconciler) HandleUpdateCluster( ctx context.Context, cadence *v1beta1.Cadence, logger logr.Logger, -) reconcile.Result { +) (ctrl.Result, error) { iData, err := r.API.GetCadence(cadence.Status.ID) if err != nil { logger.Error( @@ -258,7 +259,7 @@ func (r *CadenceReconciler) HandleUpdateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.FetchFailed, "Cluster fetch from the Instaclustr API is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } iCadence, err := cadence.FromInstAPI(iData) @@ -272,7 +273,7 @@ func (r *CadenceReconciler) HandleUpdateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.ConvertionFailed, "Cluster convertion from the Instaclustr API to k8s resource is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } if iCadence.Status.CurrentClusterOperationStatus != models.NoOperation { @@ -294,10 +295,10 @@ func (r *CadenceReconciler) HandleUpdateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.PatchFailed, "Cluster resource patch is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } - return models.ReconcileRequeue + return models.ReconcileRequeue, nil } if cadence.Annotations[models.ExternalChangesAnnotation] == models.True { @@ -316,7 +317,7 @@ func (r *CadenceReconciler) HandleUpdateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.UpdateFailed, "Cannot update cluster settings. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } } @@ -334,7 +335,7 @@ func (r *CadenceReconciler) HandleUpdateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.UpdateFailed, "Cluster update on the Instaclustr API is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } patch := cadence.NewPatch() @@ -349,7 +350,7 @@ func (r *CadenceReconciler) HandleUpdateCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.PatchFailed, "Cluster resource patch is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } logger.Info( @@ -359,10 +360,10 @@ func (r *CadenceReconciler) HandleUpdateCluster( "data centres", cadence.Spec.DataCentres, ) - return models.ExitReconcile + return ctrl.Result{}, nil } -func (r *CadenceReconciler) handleExternalChanges(cadence, iCadence *v1beta1.Cadence, l logr.Logger) reconcile.Result { +func (r *CadenceReconciler) handleExternalChanges(cadence, iCadence *v1beta1.Cadence, l logr.Logger) (ctrl.Result, error) { if !cadence.Spec.AreDCsEqual(iCadence.Spec.DataCentres) { l.Info(msgExternalChanges, "instaclustr data", iCadence.Spec.DataCentres, @@ -372,11 +373,11 @@ func (r *CadenceReconciler) handleExternalChanges(cadence, iCadence *v1beta1.Cad if err != nil { l.Error(err, "Cannot create specification difference message", "instaclustr data", iCadence.Spec, "k8s resource spec", cadence.Spec) - return models.ExitReconcile + return ctrl.Result{}, err } r.EventRecorder.Eventf(cadence, models.Warning, models.ExternalChanges, msgDiffSpecs) - return models.ExitReconcile + return ctrl.Result{}, nil } patch := cadence.NewPatch() @@ -391,20 +392,20 @@ func (r *CadenceReconciler) handleExternalChanges(cadence, iCadence *v1beta1.Cad r.EventRecorder.Eventf(cadence, models.Warning, models.PatchFailed, "Cluster resource patch is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } l.Info("External changes have been reconciled", "resource ID", cadence.Status.ID) r.EventRecorder.Event(cadence, models.Normal, models.ExternalChanges, "External changes have been reconciled") - return models.ExitReconcile + return ctrl.Result{}, nil } func (r *CadenceReconciler) HandleDeleteCluster( ctx context.Context, cadence *v1beta1.Cadence, logger logr.Logger, -) reconcile.Result { +) (ctrl.Result, error) { _, err := r.API.GetCadence(cadence.Status.ID) if err != nil && !errors.Is(err, instaclustr.NotFound) { logger.Error( @@ -416,7 +417,7 @@ func (r *CadenceReconciler) HandleDeleteCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.FetchFailed, "Cluster resource fetch from the Instaclustr API is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } if !errors.Is(err, instaclustr.NotFound) { @@ -434,7 +435,7 @@ func (r *CadenceReconciler) HandleDeleteCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.DeletionFailed, "Cluster deletion is failed on the Instaclustr. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } r.EventRecorder.Event(cadence, models.Normal, models.DeletionStarted, @@ -454,7 +455,7 @@ func (r *CadenceReconciler) HandleDeleteCluster( "Cluster resource patch is failed. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } logger.Info(msgDeleteClusterWithTwoFactorDelete, "cluster ID", cadence.Status.ID) @@ -462,10 +463,8 @@ func (r *CadenceReconciler) HandleDeleteCluster( r.EventRecorder.Event(cadence, models.Normal, models.DeletionStarted, "Two-Factor Delete is enabled, please confirm cluster deletion via email or phone.") - return models.ExitReconcile + return ctrl.Result{}, nil } - - return models.ReconcileRequeue } logger.Info("Cadence cluster is being deleted", @@ -484,7 +483,7 @@ func (r *CadenceReconciler) HandleDeleteCluster( r.EventRecorder.Eventf(cadence, models.Warning, models.DeletionFailed, "Cannot delete Cadence packaged resources. Reason: %v", err) - return models.ReconcileRequeue + return ctrl.Result{}, err } } @@ -499,7 +498,7 @@ func (r *CadenceReconciler) HandleDeleteCluster( "cluster name", cadence.Spec.Name, "patch", patch, ) - return models.ReconcileRequeue + return ctrl.Result{}, err } err = exposeservice.Delete(r.Client, cadence.Name, cadence.Namespace) @@ -509,7 +508,7 @@ func (r *CadenceReconciler) HandleDeleteCluster( "cluster name", cadence.Spec.Name, ) - return models.ReconcileRequeue + return ctrl.Result{}, err } logger.Info("Cadence cluster was deleted", @@ -519,7 +518,7 @@ func (r *CadenceReconciler) HandleDeleteCluster( r.EventRecorder.Event(cadence, models.Normal, models.Deleted, "Cluster resource is deleted") - return models.ExitReconcile + return ctrl.Result{}, nil } func (r *CadenceReconciler) preparePackagedSolution( @@ -851,6 +850,7 @@ func (r *CadenceReconciler) newWatchStatusJob(cadence *v1beta1.Cadence) schedule } if iCadence.Status.CurrentClusterOperationStatus == models.NoOperation && + cadence.Annotations[models.ResourceStateAnnotation] != models.UpdatingEvent && cadence.Annotations[models.UpdateQueuedAnnotation] != models.True && !cadence.Spec.AreDCsEqual(iCadence.Spec.DataCentres) { l.Info(msgExternalChanges, @@ -1161,6 +1161,12 @@ func areSecondaryCadenceTargetsEqual(k8sTargets, iTargets []*v1beta1.TargetCaden // SetupWithManager sets up the controller with the Manager. func (r *CadenceReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). + WithOptions(controller.Options{ + RateLimiter: ratelimiter.NewItemExponentialFailureRateLimiterWithMaxTries( + ratelimiter.DefaultBaseDelay, + ratelimiter.DefaultMaxDelay, + ), + }). For(&v1beta1.Cadence{}, builder.WithPredicates(predicate.Funcs{ CreateFunc: func(event event.CreateEvent) bool { if deleting := confirmDeletion(event.Object); deleting { diff --git a/controllers/clusters/cadence_controller_test.go b/controllers/clusters/cadence_controller_test.go new file mode 100644 index 000000000..6e6e94f66 --- /dev/null +++ b/controllers/clusters/cadence_controller_test.go @@ -0,0 +1,194 @@ +/* +Copyright 2023. + +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 clusters + +import ( + "os" + "path/filepath" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/yaml" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/instaclustr/operator/apis/clusters/v1beta1" + "github.com/instaclustr/operator/pkg/instaclustr" + mock "github.com/instaclustr/operator/pkg/instaclustr/mock/server/go" + "github.com/instaclustr/operator/pkg/models" +) + +var _ = Describe("Cadence Controller", func() { + Context("Standard provisioning of cadence cluster", func() { + cadenceManifest := &v1beta1.Cadence{} + + b, err := os.ReadFile(filepath.Join(".", "datatest", "cadence_v1beta1.yaml")) + Expect(err).NotTo(HaveOccurred()) + Expect(yaml.Unmarshal(b, cadenceManifest)).Should(Succeed()) + + It("creates the cadence custom resource in k8s", func() { + Expect(k8sClient.Create(ctx, cadenceManifest)).Should(Succeed()) + + key := client.ObjectKeyFromObject(cadenceManifest) + cadence := &v1beta1.Cadence{} + + expectedClusterID := cadenceManifest.Spec.Name + "-" + mock.CreatedID + + Eventually(func() (string, error) { + if err := k8sClient.Get(ctx, key, cadence); err != nil { + return "", err + } + + return cadence.Status.ID, nil + }, timeout, interval).Should(Equal(expectedClusterID)) + }) + + It("updates node size of the existing cadence custom resource", func() { + key := client.ObjectKeyFromObject(cadenceManifest) + cadence := &v1beta1.Cadence{} + + Eventually(func() error { + return k8sClient.Get(ctx, key, cadence) + }, timeout, interval).ShouldNot(HaveOccurred()) + + const newNodeSize = "cadence-test-node-size-2" + + patch := cadence.NewPatch() + cadence.Spec.DataCentres[0].NodeSize = newNodeSize + Expect(k8sClient.Patch(ctx, cadence, patch)).Should(Succeed()) + + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, key, cadence)).Should(Succeed()) + + g.Expect(cadence.Status.DataCentres).ShouldNot(BeEmpty()) + g.Expect(cadence.Status.DataCentres[0].Nodes).ShouldNot(BeEmpty()) + + g.Expect(cadence.Status.DataCentres[0].Nodes[0].Size).Should(Equal(newNodeSize)) + }, timeout, interval).Should(Succeed()) + }) + + It("deletes the cadence resource in k8s and on Instaclustr", func() { + key := client.ObjectKeyFromObject(cadenceManifest) + cadence := &v1beta1.Cadence{} + + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, key, cadence)).Should(Succeed(), "should get the cadence resource") + g.Expect(cadence.Status.ID).ShouldNot(BeEmpty(), "the cadence id should not be empty") + }, timeout, interval).Should(Succeed()) + + Expect(k8sClient.Delete(ctx, cadence)).Should(Succeed()) + + Eventually(func(g Gomega) { + c := &v1beta1.Cadence{} + g.Expect(k8sClient.Get(ctx, key, c)).ShouldNot(Succeed()) + }, timeout, interval).Should(Succeed()) + + Eventually(func() error { + _, err := instaClient.GetCadence(cadence.Status.ID) + return err + }, timeout, interval).Should(Equal(instaclustr.NotFound)) + }) + }) + + Context("Packaged provisioning of cadence cluster", func() { + cadenceManifest := &v1beta1.Cadence{} + + b, err := os.ReadFile(filepath.Join(".", "datatest", "cadence_v1beta1_packaged.yaml")) + Expect(err).NotTo(HaveOccurred()) + Expect(yaml.Unmarshal(b, cadenceManifest)).Should(Succeed()) + + It("creates a cadence and all packaged custom resources in k8s and on Instaclustr", func() { + Expect(k8sClient.Create(ctx, cadenceManifest)).Should(Succeed()) + + cadence := &v1beta1.Cadence{} + opensearch := &v1beta1.OpenSearch{} + kafka := &v1beta1.Kafka{} + cassandra := &v1beta1.Cassandra{} + + key := client.ObjectKeyFromObject(cadenceManifest) + + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, key, cadence)).Should(Succeed()) + g.Expect(cadence.Status.ID).ShouldNot(BeEmpty()) + }, timeout, interval).Should(Succeed()) + + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{ + Namespace: metav1.NamespaceDefault, + Name: models.OpenSearchChildPrefix + cadence.Name}, opensearch, + ) + }, timeout, interval).Should(Succeed(), "should get opensearch resource") + + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{ + Namespace: metav1.NamespaceDefault, + Name: models.CassandraChildPrefix + cadence.Name}, cassandra, + ) + }, timeout, interval).Should(Succeed(), "should get cassandra resource") + + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{ + Namespace: metav1.NamespaceDefault, + Name: models.KafkaChildPrefix + cadence.Name}, kafka, + ) + }, timeout, interval).Should(Succeed(), "should get kafka resource") + }) + + It("deletes the cadence and bundled resources in k8s and Instaclustr", func() { + key := client.ObjectKeyFromObject(cadenceManifest) + cadence := &v1beta1.Cadence{} + + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, key, cadence)).Should(Succeed(), "should get the cadence resource") + g.Expect(cadence.Status.ID).ShouldNot(BeEmpty(), "the cadence id should not be empty") + }, timeout, interval).Should(Succeed()) + + Expect(k8sClient.Delete(ctx, cadence)).Should(Succeed()) + + Eventually(func(g Gomega) { + c := &v1beta1.Cadence{} + g.Expect(k8sClient.Get(ctx, key, c)).ShouldNot(Succeed()) + }, timeout, interval).Should(Succeed()) + + opensearch := &v1beta1.OpenSearch{} + kafka := &v1beta1.Kafka{} + cassandra := &v1beta1.Cassandra{} + + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{ + Namespace: metav1.NamespaceDefault, + Name: models.OpenSearchChildPrefix + cadence.Name}, opensearch, + ) + }, timeout, interval).ShouldNot(Succeed(), "should not get opensearch resource") + + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{ + Namespace: metav1.NamespaceDefault, + Name: models.CassandraChildPrefix + cadence.Name}, cassandra, + ) + }, timeout, interval).ShouldNot(Succeed(), "should not get cassandra resource") + + Eventually(func() error { + return k8sClient.Get(ctx, types.NamespacedName{ + Namespace: metav1.NamespaceDefault, + Name: models.KafkaChildPrefix + cadence.Name}, kafka, + ) + }, timeout, interval).ShouldNot(Succeed(), "should not get kafka resource") + }) + }) +}) diff --git a/controllers/clusters/datatest/cadence_v1beta1.yaml b/controllers/clusters/datatest/cadence_v1beta1.yaml new file mode 100644 index 000000000..322a5e6b7 --- /dev/null +++ b/controllers/clusters/datatest/cadence_v1beta1.yaml @@ -0,0 +1,66 @@ +#apiVersion: v1 +#kind: Secret +#metadata: +# name: inst-test-aws-cred-secret +#data: +# awsAccessKeyId: access_key +# awsSecretAccessKey: secret_key +#--- +apiVersion: clusters.instaclustr.com/v1beta1 +kind: Cadence +metadata: + name: cadence-test + namespace: default + annotations: + defaulter: webhook +spec: + name: "cadence-test" + version: "1.0.0" + standardProvisioning: + - targetCassandra: + dependencyCdcId: test-cassandra-cdcid + dependencyVpcType: "VPC_PEERED" +# packagedProvisioning: +# - bundledCassandraSpec: +# nodeSize: "CAS-DEV-t4g.small-5" +# network: "10.2.0.0/16" +# replicationFactor: 3 +# nodesNumber: 3 +# privateIPBroadcastForDiscovery: false +# passwordAndUserAuth: true + # useAdvancedVisibility: true + # bundledKafkaSpec: + # nodeSize: "KFK-DEV-t4g.small-5" + # nodesNumber: 3 + # network: "10.3.0.0/16" + # replicationFactor: 3 + # partitionsNumber: 3 + # bundledOpenSearchSpec: + # nodeSize: "SRH-DEV-t4g.small-5" + # replicationFactor: 3 + # network: "10.4.0.0/16" + # twoFactorDelete: + # - email: "example@netapp.com" + privateNetworkCluster: false + dataCentres: + - region: "US_WEST_2" + network: "10.12.0.0/16" + # if you use multi-region mode please provide + # non-overlapping CIDR block for the secondary mode cluster + # network: "10.16.0.0/16" + cloudProvider: "AWS_VPC" + name: "testdc" + # nodeSize: "CAD-PRD-m5ad.large-75" + nodeSize: "cadence-test-node-size-1" + nodesNumber: 1 + clientEncryption: false + # privateLink: + # - advertisedHostname: "cadence-sample-test.com" + slaTier: "NON_PRODUCTION" + useCadenceWebAuth: false + # targetPrimaryCadence: + # - dependencyCdcId: "cce79be3-7f41-4cad-837c-86d3d8b4be77" + # dependencyVpcType: "SEPARATE_VPC" + resizeSettings: + - notifySupportContacts: false + concurrency: 1 \ No newline at end of file diff --git a/controllers/clusters/datatest/cadence_v1beta1_packaged.yaml b/controllers/clusters/datatest/cadence_v1beta1_packaged.yaml new file mode 100644 index 000000000..7339656a7 --- /dev/null +++ b/controllers/clusters/datatest/cadence_v1beta1_packaged.yaml @@ -0,0 +1,66 @@ +#apiVersion: v1 +#kind: Secret +#metadata: +# name: inst-test-aws-cred-secret +#data: +# awsAccessKeyId: access_key +# awsSecretAccessKey: secret_key +#--- +apiVersion: clusters.instaclustr.com/v1beta1 +kind: Cadence +metadata: + name: cadence-test-packaged-provisioning + namespace: default + annotations: + defaulter: webhook +spec: + name: "cadence-test" + version: "1.0.0" +# standardProvisioning: +# - targetCassandra: +# dependencyCdcId: test-cassandra-cdcid +# dependencyVpcType: "VPC_PEERED" + packagedProvisioning: + - bundledCassandraSpec: + nodeSize: "CAS-DEV-t4g.small-5" + network: "10.2.0.0/16" + replicationFactor: 3 + nodesNumber: 3 + privateIPBroadcastForDiscovery: false + passwordAndUserAuth: true + useAdvancedVisibility: true + bundledKafkaSpec: + nodeSize: "KFK-DEV-t4g.small-5" + nodesNumber: 3 + network: "10.3.0.0/16" + replicationFactor: 3 + partitionsNumber: 3 + bundledOpenSearchSpec: + nodeSize: "SRH-DEV-t4g.small-5" + replicationFactor: 3 + network: "10.4.0.0/16" + # twoFactorDelete: + # - email: "example@netapp.com" + privateNetworkCluster: false + dataCentres: + - region: "US_WEST_2" + network: "10.12.0.0/16" + # if you use multi-region mode please provide + # non-overlapping CIDR block for the secondary mode cluster + # network: "10.16.0.0/16" + cloudProvider: "AWS_VPC" + name: "testdc" + # nodeSize: "CAD-PRD-m5ad.large-75" + nodeSize: "cadence-test-node-size-1" + nodesNumber: 1 + clientEncryption: false + # privateLink: + # - advertisedHostname: "cadence-sample-test.com" + slaTier: "NON_PRODUCTION" + useCadenceWebAuth: false + # targetPrimaryCadence: + # - dependencyCdcId: "cce79be3-7f41-4cad-837c-86d3d8b4be77" + # dependencyVpcType: "SEPARATE_VPC" + resizeSettings: + - notifySupportContacts: false + concurrency: 1 \ No newline at end of file diff --git a/controllers/clusters/suite_test.go b/controllers/clusters/suite_test.go index b87d78a35..6cf1a2d87 100644 --- a/controllers/clusters/suite_test.go +++ b/controllers/clusters/suite_test.go @@ -158,6 +158,15 @@ var _ = BeforeSuite(func() { }).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) + err = (&CadenceReconciler{ + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + API: instaClient, + Scheduler: scheduler.NewScheduler(logf.Log), + EventRecorder: eRecorder, + }).SetupWithManager(k8sManager) + Expect(err).ToNot(HaveOccurred()) + err = (&PostgreSQLReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), diff --git a/pkg/instaclustr/mock/server/go/api.go b/pkg/instaclustr/mock/server/go/api.go index 128e551af..06e8487e7 100644 --- a/pkg/instaclustr/mock/server/go/api.go +++ b/pkg/instaclustr/mock/server/go/api.go @@ -562,6 +562,7 @@ type CadenceProvisioningV2APIServicer interface { ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdGet(context.Context, string) (ImplResponse, error) ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdPut(context.Context, string, CadenceClusterUpdateV2) (ImplResponse, error) ClusterManagementV2ResourcesApplicationsCadenceClustersV2Post(context.Context, CadenceClusterV2) (ImplResponse, error) + ClusterManagementV2ResourcesApplicationsVersions(ctx context.Context, appKind string) (ImplResponse, error) } // ClusterExclusionWindowV2APIServicer defines the api actions for the ClusterExclusionWindowV2API service diff --git a/pkg/instaclustr/mock/server/go/api_apache_cassandra_provisioning_v2_service.go b/pkg/instaclustr/mock/server/go/api_apache_cassandra_provisioning_v2_service.go index 522880524..b9c157c82 100644 --- a/pkg/instaclustr/mock/server/go/api_apache_cassandra_provisioning_v2_service.go +++ b/pkg/instaclustr/mock/server/go/api_apache_cassandra_provisioning_v2_service.go @@ -13,12 +13,14 @@ import ( "context" "errors" "net/http" + "sync" ) // ApacheCassandraProvisioningV2APIService is a service that implements the logic for the ApacheCassandraProvisioningV2APIServicer // This service should implement the business logic for every endpoint for the ApacheCassandraProvisioningV2API API. // Include any external packages or services that will be required by this service. type ApacheCassandraProvisioningV2APIService struct { + mu sync.RWMutex clusters map[string]*CassandraClusterV2 } @@ -64,6 +66,9 @@ func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2OperationsA func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsCassandraClustersV2ClusterIdDelete(ctx context.Context, clusterId string) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsCassandraClustersV2ClusterIdDelete with the required logic for this service method. // Add api_apache_cassandra_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() + _, exists := s.clusters[clusterId] if !exists { return Response(http.StatusNotFound, nil), nil @@ -78,6 +83,8 @@ func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2ResourcesAp func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsCassandraClustersV2ClusterIdGet(ctx context.Context, clusterId string) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsCassandraClustersV2ClusterIdGet with the required logic for this service method. // Add api_apache_cassandra_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() c, exists := s.clusters[clusterId] if !exists { @@ -93,6 +100,8 @@ func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2ResourcesAp func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsCassandraClustersV2ClusterIdPut(ctx context.Context, clusterId string, cassandraClusterUpdateV2 CassandraClusterUpdateV2) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsCassandraClustersV2ClusterIdPut with the required logic for this service method. // Add api_apache_cassandra_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() c, exists := s.clusters[clusterId] if !exists { @@ -114,6 +123,8 @@ func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2ResourcesAp func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsCassandraClustersV2Post(ctx context.Context, cassandraClusterV2 CassandraClusterV2) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsCassandraClustersV2Post with the required logic for this service method. // Add api_apache_cassandra_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() newCassandra := &CassandraClusterV2{} @@ -121,6 +132,10 @@ func (s *ApacheCassandraProvisioningV2APIService) ClusterManagementV2ResourcesAp newCassandra.Id = cassandraClusterV2.Name + CreatedID newCassandra.DataCentres[0].Nodes = []NodeDetailsV2{{NodeSize: cassandraClusterV2.DataCentres[0].NodeSize}} + for i := range newCassandra.DataCentres { + newCassandra.DataCentres[i].Id = newCassandra.DataCentres[i].Name + "-" + CreatedID + } + s.clusters[newCassandra.Id] = newCassandra return Response(http.StatusAccepted, newCassandra), nil diff --git a/pkg/instaclustr/mock/server/go/api_apache_kafka_provisioning_v2_service.go b/pkg/instaclustr/mock/server/go/api_apache_kafka_provisioning_v2_service.go index 2d19ed608..ea81a0bf5 100644 --- a/pkg/instaclustr/mock/server/go/api_apache_kafka_provisioning_v2_service.go +++ b/pkg/instaclustr/mock/server/go/api_apache_kafka_provisioning_v2_service.go @@ -11,6 +11,7 @@ package openapi import ( "context" + "sync" ) // ApacheKafkaProvisioningV2APIService is a service that implements the logic for the ApacheKafkaProvisioningV2APIServicer @@ -18,6 +19,7 @@ import ( // Include any external packages or services that will be required by this service. type ApacheKafkaProvisioningV2APIService struct { clusters map[string]*KafkaClusterV2 + mu sync.RWMutex } // NewApacheKafkaProvisioningV2APIService creates a default api service @@ -29,6 +31,8 @@ func NewApacheKafkaProvisioningV2APIService() ApacheKafkaProvisioningV2APIServic func (s *ApacheKafkaProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsKafkaClustersV2ClusterIdDelete(ctx context.Context, clusterId string) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsKafkaClustersV2ClusterIdDelete with the required logic for this service method. // Add api_apache_kafka_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() delete(s.clusters, clusterId) return Response(204, nil), nil @@ -38,6 +42,8 @@ func (s *ApacheKafkaProvisioningV2APIService) ClusterManagementV2ResourcesApplic func (s *ApacheKafkaProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsKafkaClustersV2ClusterIdGet(ctx context.Context, clusterId string) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsKafkaClustersV2ClusterIdGet with the required logic for this service method. // Add api_apache_kafka_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() cluster, exists := s.clusters[clusterId] if !exists { @@ -53,6 +59,8 @@ func (s *ApacheKafkaProvisioningV2APIService) ClusterManagementV2ResourcesApplic func (s *ApacheKafkaProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsKafkaClustersV2ClusterIdPut(ctx context.Context, clusterId string, kafkaClusterUpdateV2 KafkaClusterUpdateV2) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsKafkaClustersV2ClusterIdPut with the required logic for this service method. // Add api_apache_kafka_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() cluster, exists := s.clusters[clusterId] if !exists { @@ -78,8 +86,15 @@ func (s *ApacheKafkaProvisioningV2APIService) ClusterManagementV2ResourcesApplic func (s *ApacheKafkaProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsKafkaClustersV2Post(ctx context.Context, kafkaClusterV2 KafkaClusterV2) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsKafkaClustersV2Post with the required logic for this service method. // Add api_apache_kafka_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() kafkaClusterV2.Id = kafkaClusterV2.Name + CreatedID + + for i := range kafkaClusterV2.DataCentres { + kafkaClusterV2.DataCentres[i].Id = kafkaClusterV2.DataCentres[i].Name + "-" + CreatedID + } + s.clusters[kafkaClusterV2.Id] = &kafkaClusterV2 return Response(202, kafkaClusterV2), nil diff --git a/pkg/instaclustr/mock/server/go/api_cadence_provisioning_v2.go b/pkg/instaclustr/mock/server/go/api_cadence_provisioning_v2.go index e2cfd539f..b4c938c64 100644 --- a/pkg/instaclustr/mock/server/go/api_cadence_provisioning_v2.go +++ b/pkg/instaclustr/mock/server/go/api_cadence_provisioning_v2.go @@ -70,6 +70,11 @@ func (c *CadenceProvisioningV2APIController) Routes() Routes { "/cluster-management/v2/resources/applications/cadence/clusters/v2/", c.ClusterManagementV2ResourcesApplicationsCadenceClustersV2Post, }, + "ClusterManagementV2ResourcesApplicationsVersions": Route{ + strings.ToUpper("Get"), + "/cluster-management/v2/data-sources/applications/{appKind}/versions/v2/", + c.ClusterManagementV2ResourcesApplicationsVersions, + }, } } @@ -156,3 +161,17 @@ func (c *CadenceProvisioningV2APIController) ClusterManagementV2ResourcesApplica // If no error, encode the body and the result code EncodeJSONResponse(result.Body, &result.Code, w) } + +func (c *CadenceProvisioningV2APIController) ClusterManagementV2ResourcesApplicationsVersions(w http.ResponseWriter, r *http.Request) { + appKind := mux.Vars(r)["appKind"] + + result, err := c.service.ClusterManagementV2ResourcesApplicationsVersions(r.Context(), appKind) + // If an error occurred, encode the error with the status code + if err != nil { + c.errorHandler(w, r, err, &result) + return + } + + // If no error, encode the body and the result code + EncodeJSONResponse(result.Body, &result.Code, w) +} diff --git a/pkg/instaclustr/mock/server/go/api_cadence_provisioning_v2_service.go b/pkg/instaclustr/mock/server/go/api_cadence_provisioning_v2_service.go index 4839e7655..9909dcd0e 100644 --- a/pkg/instaclustr/mock/server/go/api_cadence_provisioning_v2_service.go +++ b/pkg/instaclustr/mock/server/go/api_cadence_provisioning_v2_service.go @@ -11,19 +11,23 @@ package openapi import ( "context" - "errors" + "fmt" "net/http" + "strings" + "sync" ) // CadenceProvisioningV2APIService is a service that implements the logic for the CadenceProvisioningV2APIServicer // This service should implement the business logic for every endpoint for the CadenceProvisioningV2API API. // Include any external packages or services that will be required by this service. type CadenceProvisioningV2APIService struct { + clusters map[string]*CadenceClusterV2 + mu sync.RWMutex } // NewCadenceProvisioningV2APIService creates a default api service func NewCadenceProvisioningV2APIService() CadenceProvisioningV2APIServicer { - return &CadenceProvisioningV2APIService{} + return &CadenceProvisioningV2APIService{clusters: map[string]*CadenceClusterV2{}} } // ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdDelete - Delete cluster @@ -31,10 +35,17 @@ func (s *CadenceProvisioningV2APIService) ClusterManagementV2ResourcesApplicatio // TODO - update ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdDelete with the required logic for this service method. // Add api_cadence_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. - // TODO: Uncomment the next line to return response Response(204, {}) or use other options such as http.Ok ... - // return Response(204, nil),nil + s.mu.Lock() + defer s.mu.Unlock() - return Response(http.StatusNotImplemented, nil), errors.New("ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdDelete method not implemented") + _, exists := s.clusters[clusterId] + if !exists { + return Response(404, notFoundResponse), nil + } + + delete(s.clusters, clusterId) + + return Response(204, nil), nil } // ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdGet - Get Cadence cluster details. @@ -42,10 +53,15 @@ func (s *CadenceProvisioningV2APIService) ClusterManagementV2ResourcesApplicatio // TODO - update ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdGet with the required logic for this service method. // Add api_cadence_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. - // TODO: Uncomment the next line to return response Response(200, CadenceClusterV2{}) or use other options such as http.Ok ... - // return Response(200, CadenceClusterV2{}), nil + s.mu.Lock() + defer s.mu.Unlock() - return Response(http.StatusNotImplemented, nil), errors.New("ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdGet method not implemented") + cluster, exists := s.clusters[clusterId] + if !exists { + return Response(404, notFoundResponse), nil + } + + return Response(200, cluster), nil } // ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdPut - Update a Cadence cluster @@ -53,13 +69,34 @@ func (s *CadenceProvisioningV2APIService) ClusterManagementV2ResourcesApplicatio // TODO - update ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdPut with the required logic for this service method. // Add api_cadence_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. - // TODO: Uncomment the next line to return response Response(202, CadenceClusterV2{}) or use other options such as http.Ok ... - // return Response(202, CadenceClusterV2{}), nil + s.mu.Lock() + defer s.mu.Unlock() + + cluster, exists := s.clusters[clusterId] + if !exists { + return Response(404, notFoundResponse), nil + } - // TODO: Uncomment the next line to return response Response(404, ErrorListResponseV2{}) or use other options such as http.Ok ... - // return Response(404, ErrorListResponseV2{}), nil + for i, newDC := range cadenceClusterUpdateV2.DataCentres { + for _, oldDc := range cluster.DataCentres { + if newDC.Name == oldDc.Name { + newNodes := append([]NodeDetailsV2{}, oldDc.Nodes...) - return Response(http.StatusNotImplemented, nil), errors.New("ClusterManagementV2ResourcesApplicationsCadenceClustersV2ClusterIdPut method not implemented") + for i := range newNodes { + newNodes[i].NodeSize = newDC.NodeSize + } + + cadenceClusterUpdateV2.DataCentres[i].Nodes = newNodes + } + } + } + + cluster.DataCentres = cadenceClusterUpdateV2.DataCentres + cluster.Description = cadenceClusterUpdateV2.Description + cluster.TwoFactorDelete = cadenceClusterUpdateV2.TwoFactorDelete + cluster.ResizeSettings = cadenceClusterUpdateV2.ResizeSettings + + return Response(202, cluster), nil } // ClusterManagementV2ResourcesApplicationsCadenceClustersV2Post - Create a Cadence cluster @@ -67,8 +104,64 @@ func (s *CadenceProvisioningV2APIService) ClusterManagementV2ResourcesApplicatio // TODO - update ClusterManagementV2ResourcesApplicationsCadenceClustersV2Post with the required logic for this service method. // Add api_cadence_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. - // TODO: Uncomment the next line to return response Response(202, CadenceClusterV2{}) or use other options such as http.Ok ... - // return Response(202, CadenceClusterV2{}), nil + s.mu.Lock() + defer s.mu.Unlock() + + cadenceClusterV2.Id = cadenceClusterV2.Name + "-" + CreatedID + + for i, dc := range cadenceClusterV2.DataCentres { + var nodes []NodeDetailsV2 + for j := int32(0); j < dc.NumberOfNodes; j++ { + nodes = append(nodes, NodeDetailsV2{ + NodeSize: cadenceClusterV2.DataCentres[0].NodeSize, + Id: fmt.Sprintf("%s-%s-node-%d", cadenceClusterV2.Name, cadenceClusterV2.DataCentres[0].Name, j), + Status: "RUNNING", + }) + } + + cadenceClusterV2.DataCentres[i].Nodes = nodes + } + + cadenceClusterV2.CurrentClusterOperationStatus = "NO_OPERATION" + + s.clusters[cadenceClusterV2.Id] = &cadenceClusterV2 + + return Response(202, cadenceClusterV2), nil +} + +var notFoundResponse = ErrorListResponseV2{ + Errors: []ErrorResponseV2{ + { + Name: "clusterId", + Message: "Not found", + }, + }, +} - return Response(http.StatusNotImplemented, nil), errors.New("ClusterManagementV2ResourcesApplicationsCadenceClustersV2Post method not implemented") +func (s *CadenceProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsVersions(ctx context.Context, appKind string) (ImplResponse, error) { + type appVersions struct { + Application string `json:"application"` + Versions []string `json:"versions"` + } + + type apiAppVersions struct { + AppVersions []appVersions `json:"applicationVersions"` + } + + if appKind == "cassandra" { + appKind = "APACHE_CASSANDRA" + } else { + appKind = strings.ToUpper(appKind) + } + + return Response(http.StatusOK, []apiAppVersions{ + { + AppVersions: []appVersions{ + { + Application: appKind, + Versions: []string{"0.0.1"}, + }, + }, + }, + }), nil } diff --git a/pkg/instaclustr/mock/server/go/api_open_search_provisioning_v2_service.go b/pkg/instaclustr/mock/server/go/api_open_search_provisioning_v2_service.go index c8cfa315d..41914d919 100644 --- a/pkg/instaclustr/mock/server/go/api_open_search_provisioning_v2_service.go +++ b/pkg/instaclustr/mock/server/go/api_open_search_provisioning_v2_service.go @@ -13,12 +13,14 @@ import ( "context" "errors" "net/http" + "sync" ) // OpenSearchProvisioningV2APIService is a service that implements the logic for the OpenSearchProvisioningV2APIServicer // This service should implement the business logic for every endpoint for the OpenSearchProvisioningV2API API. // Include any external packages or services that will be required by this service. type OpenSearchProvisioningV2APIService struct { + mu sync.RWMutex clusters map[string]*OpenSearchClusterV2 } @@ -64,6 +66,8 @@ func (s *OpenSearchProvisioningV2APIService) ClusterManagementV2OperationsApplic func (s *OpenSearchProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsOpensearchClustersV2ClusterIdDelete(ctx context.Context, clusterId string) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsOpensearchClustersV2ClusterIdDelete with the required logic for this service method. // Add api_open_search_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() _, exists := s.clusters[clusterId] if !exists { @@ -79,6 +83,8 @@ func (s *OpenSearchProvisioningV2APIService) ClusterManagementV2ResourcesApplica func (s *OpenSearchProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsOpensearchClustersV2ClusterIdGet(ctx context.Context, clusterId string) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsOpensearchClustersV2ClusterIdGet with the required logic for this service method. // Add api_open_search_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() o, exists := s.clusters[clusterId] if !exists { @@ -94,6 +100,8 @@ func (s *OpenSearchProvisioningV2APIService) ClusterManagementV2ResourcesApplica func (s *OpenSearchProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsOpensearchClustersV2ClusterIdPut(ctx context.Context, clusterId string, openSearchClusterUpdateV2 OpenSearchClusterUpdateV2) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsOpensearchClustersV2ClusterIdPut with the required logic for this service method. // Add api_open_search_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() o, exists := s.clusters[clusterId] if !exists { @@ -114,12 +122,18 @@ func (s *OpenSearchProvisioningV2APIService) ClusterManagementV2ResourcesApplica func (s *OpenSearchProvisioningV2APIService) ClusterManagementV2ResourcesApplicationsOpensearchClustersV2Post(ctx context.Context, openSearchClusterV2 OpenSearchClusterV2) (ImplResponse, error) { // TODO - update ClusterManagementV2ResourcesApplicationsOpensearchClustersV2Post with the required logic for this service method. // Add api_open_search_provisioning_v2_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + s.mu.Lock() + defer s.mu.Unlock() newOpenSearch := &OpenSearchClusterV2{} newOpenSearch = &openSearchClusterV2 newOpenSearch.Id = openSearchClusterV2.Name + CreatedID + for i := range newOpenSearch.DataCentres { + newOpenSearch.DataCentres[i].Id = newOpenSearch.DataCentres[i].Name + "-" + CreatedID + } + s.clusters[newOpenSearch.Id] = newOpenSearch return Response(202, newOpenSearch), nil diff --git a/pkg/instaclustr/mock/server/go/routers.go b/pkg/instaclustr/mock/server/go/routers.go index 04c40b58d..d391746bc 100644 --- a/pkg/instaclustr/mock/server/go/routers.go +++ b/pkg/instaclustr/mock/server/go/routers.go @@ -12,13 +12,14 @@ package openapi import ( "encoding/json" "errors" - "github.com/gorilla/mux" "io/ioutil" "mime/multipart" "net/http" "os" "strconv" "strings" + + "github.com/gorilla/mux" ) // A Route defines the parameters for an api endpoint