From c6430e129ade9b0c9dd48a33ecd9c8a90cda1265 Mon Sep 17 00:00:00 2001 From: Bohdan Siryk Date: Wed, 9 Aug 2023 15:09:39 +0300 Subject: [PATCH] added primaryTargetCadence to Cadence spec and secondaryTargetCadence to its status --- apis/clusters/v1beta1/cadence_types.go | 60 ++++++++++++++++++- .../clusters/v1beta1/zz_generated.deepcopy.go | 37 ++++++++++++ .../clusters.instaclustr.com_cadences.yaml | 24 ++++++++ config/samples/clusters_v1beta1_cadence.yaml | 6 +- controllers/clusters/cadence_controller.go | 34 ++++++++++- pkg/models/cadence_apiv2.go | 31 ++++++---- 6 files changed, 175 insertions(+), 17 deletions(-) diff --git a/apis/clusters/v1beta1/cadence_types.go b/apis/clusters/v1beta1/cadence_types.go index 9c67a5568..6c66ab325 100644 --- a/apis/clusters/v1beta1/cadence_types.go +++ b/apis/clusters/v1beta1/cadence_types.go @@ -70,6 +70,7 @@ type CadenceSpec struct { StandardProvisioning []*StandardProvisioning `json:"standardProvisioning,omitempty"` SharedProvisioning []*SharedProvisioning `json:"sharedProvisioning,omitempty"` PackagedProvisioning []*PackagedProvisioning `json:"packagedProvisioning,omitempty"` + TargetPrimaryCadence []*TargetCadence `json:"targetPrimaryCadence,omitempty"` } type AWSArchival struct { @@ -110,6 +111,11 @@ type TargetOpenSearch struct { DependencyVPCType string `json:"dependencyVpcType"` } +type TargetCadence struct { + DependencyCDCID string `json:"dependencyCdcId"` + DependencyVPCType string `json:"dependencyVpcType"` +} + type AdvancedVisibility struct { TargetKafka *TargetKafka `json:"targetKafka"` TargetOpenSearch *TargetOpenSearch `json:"targetOpenSearch"` @@ -117,7 +123,8 @@ type AdvancedVisibility struct { // CadenceStatus defines the observed state of Cadence type CadenceStatus struct { - ClusterStatus `json:",inline"` + ClusterStatus `json:",inline"` + TargetSecondaryCadence []*TargetCadence `json:"targetSecondaryCadence,omitempty"` } //+kubebuilder:object:root=true @@ -180,6 +187,7 @@ func (cs *CadenceSpec) ToInstAPI(ctx context.Context, k8sClient client.Client) ( AWSArchival: awsArchival, SharedProvisioning: sharedProvisioning, StandardProvisioning: standardProvisioning, + TargetPrimaryCadence: cs.TargetCadenceToInstAPI(), }, nil } @@ -305,6 +313,17 @@ func (cd *CadenceDataCentre) privateLinkToInstAPI() (iPrivateLink []*models.Priv return } +func (cs *CadenceSpec) TargetCadenceToInstAPI() []*models.TargetCadence { + var targets []*models.TargetCadence + for _, target := range cs.TargetPrimaryCadence { + targets = append(targets, &models.TargetCadence{ + DependencyCDCID: target.DependencyCDCID, + DependencyVPCType: target.DependencyVPCType, + }) + } + return targets +} + func (cs *CadenceSpec) DCsToInstAPI() (iDCs []*models.CadenceDataCentre) { for _, dc := range cs.DataCentres { iDCs = append(iDCs, dc.ToInstAPI()) @@ -385,9 +404,21 @@ func (cs *CadenceStatus) FromInstAPI(iCad *models.CadenceCluster) CadenceStatus CurrentClusterOperationStatus: iCad.CurrentClusterOperationStatus, MaintenanceEvents: cs.MaintenanceEvents, }, + TargetSecondaryCadence: cs.SecondaryTargetsFromInstAPI(iCad), } } +func (cs *CadenceStatus) SecondaryTargetsFromInstAPI(iCad *models.CadenceCluster) []*TargetCadence { + var targets []*TargetCadence + for _, target := range iCad.TargetSecondaryCadence { + targets = append(targets, &TargetCadence{ + DependencyCDCID: target.DependencyCDCID, + DependencyVPCType: target.DependencyVPCType, + }) + } + return targets +} + func (cs *CadenceStatus) DCsFromInstAPI(iDCs []*models.CadenceDataCentre) (dcs []*DataCentreStatus) { for _, iDC := range iDCs { dcs = append(dcs, cs.ClusterStatus.DCFromInstAPI(iDC.DataCentre)) @@ -457,6 +488,11 @@ func (cs *CadenceSpec) validateUpdate(oldSpec CadenceSpec) error { return err } + err = cs.validateTargetsPrimaryCadence(&oldSpec) + if err != nil { + return err + } + return nil } @@ -554,6 +590,28 @@ func (cs *CadenceSpec) validatePackagedProvisioning(old []*PackagedProvisioning) return nil } +func (cs *CadenceSpec) validateTargetsPrimaryCadence(old *CadenceSpec) error { + if len(cs.TargetPrimaryCadence) != len(old.TargetPrimaryCadence) { + return fmt.Errorf("targetPrimaryCadence is immutable") + } + + for _, oldTarget := range old.TargetPrimaryCadence { + var ok bool + for _, newTarget := range cs.TargetPrimaryCadence { + if *oldTarget == *newTarget { + ok = true + break + } + } + + if !ok { + return fmt.Errorf("targetPrimaryCadence is immutable") + } + } + + return nil +} + func (cdc *CadenceDataCentre) newImmutableFields() *immutableCadenceDCFields { return &immutableCadenceDCFields{ immutableDC: immutableDC{ diff --git a/apis/clusters/v1beta1/zz_generated.deepcopy.go b/apis/clusters/v1beta1/zz_generated.deepcopy.go index 957868ae4..75e8dce4b 100644 --- a/apis/clusters/v1beta1/zz_generated.deepcopy.go +++ b/apis/clusters/v1beta1/zz_generated.deepcopy.go @@ -286,6 +286,17 @@ func (in *CadenceSpec) DeepCopyInto(out *CadenceSpec) { } } } + if in.TargetPrimaryCadence != nil { + in, out := &in.TargetPrimaryCadence, &out.TargetPrimaryCadence + *out = make([]*TargetCadence, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(TargetCadence) + **out = **in + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CadenceSpec. @@ -302,6 +313,17 @@ func (in *CadenceSpec) DeepCopy() *CadenceSpec { func (in *CadenceStatus) DeepCopyInto(out *CadenceStatus) { *out = *in in.ClusterStatus.DeepCopyInto(&out.ClusterStatus) + if in.TargetSecondaryCadence != nil { + in, out := &in.TargetSecondaryCadence, &out.TargetSecondaryCadence + *out = make([]*TargetCadence, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(TargetCadence) + **out = **in + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CadenceStatus. @@ -2044,6 +2066,21 @@ func (in *StandardProvisioning) DeepCopy() *StandardProvisioning { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetCadence) DeepCopyInto(out *TargetCadence) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetCadence. +func (in *TargetCadence) DeepCopy() *TargetCadence { + if in == nil { + return nil + } + out := new(TargetCadence) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TargetCassandra) DeepCopyInto(out *TargetCassandra) { *out = *in diff --git a/config/crd/bases/clusters.instaclustr.com_cadences.yaml b/config/crd/bases/clusters.instaclustr.com_cadences.yaml index a722f40e9..5443589e9 100644 --- a/config/crd/bases/clusters.instaclustr.com_cadences.yaml +++ b/config/crd/bases/clusters.instaclustr.com_cadences.yaml @@ -241,6 +241,18 @@ spec: - targetCassandra type: object type: array + targetPrimaryCadence: + items: + properties: + dependencyCdcId: + type: string + dependencyVpcType: + type: string + required: + - dependencyCdcId + - dependencyVpcType + type: object + type: array twoFactorDelete: items: properties: @@ -335,6 +347,18 @@ spec: type: object state: type: string + targetSecondaryCadence: + items: + properties: + dependencyCdcId: + type: string + dependencyVpcType: + type: string + required: + - dependencyCdcId + - dependencyVpcType + type: object + type: array twoFactorDeleteEnabled: type: boolean type: object diff --git a/config/samples/clusters_v1beta1_cadence.yaml b/config/samples/clusters_v1beta1_cadence.yaml index 1f1b19a19..a4953f07e 100644 --- a/config/samples/clusters_v1beta1_cadence.yaml +++ b/config/samples/clusters_v1beta1_cadence.yaml @@ -48,5 +48,7 @@ spec: nodesNumber: 2 clientEncryption: false slaTier: "NON_PRODUCTION" - useCadenceWebAuth: true - + useCadenceWebAuth: false +# targetPrimaryCadence: +# - dependencyCdcId: "cce79be3-7f41-4cad-837c-86d3d8b4be77" +# dependencyVpcType: "SEPARATE_VPC" diff --git a/controllers/clusters/cadence_controller.go b/controllers/clusters/cadence_controller.go index 6b7d8a2b5..0a70b366c 100644 --- a/controllers/clusters/cadence_controller.go +++ b/controllers/clusters/cadence_controller.go @@ -771,7 +771,7 @@ func (r *CadenceReconciler) newWatchStatusJob(cadence *v1beta1.Cadence) schedule if k8serrors.IsNotFound(err) { l.Info("Resource is not found in the k8s cluster. Closing Instaclustr status sync.", "namespaced name", namespacedName) - r.Scheduler.RemoveJob(cadence.GetJobID(scheduler.StatusChecker)) + go r.Scheduler.RemoveJob(cadence.GetJobID(scheduler.StatusChecker)) return nil } if err != nil { @@ -839,7 +839,9 @@ func (r *CadenceReconciler) newWatchStatusJob(cadence *v1beta1.Cadence) schedule return err } - if !areStatusesEqual(&iCadence.Status.ClusterStatus, &cadence.Status.ClusterStatus) { + cadenceTargetsEqual := areSecondaryCadenceTargetsEqual(cadence.Status.TargetSecondaryCadence, iCadence.Status.TargetSecondaryCadence) + if !areStatusesEqual(&iCadence.Status.ClusterStatus, &cadence.Status.ClusterStatus) || + !cadenceTargetsEqual { l.Info("Updating Cadence cluster status", "new status", iCadence.Status.ClusterStatus, "old status", cadence.Status.ClusterStatus, @@ -874,6 +876,16 @@ func (r *CadenceReconciler) newWatchStatusJob(cadence *v1beta1.Cadence) schedule return err } } + + if !cadenceTargetsEqual { + patch := cadence.NewPatch() + cadence.Status.TargetSecondaryCadence = iCadence.Status.TargetSecondaryCadence + err = r.Status().Patch(context.Background(), cadence, patch) + if err != nil { + l.Error(err, "Cannot patch cadence status with new target secondary cadence") + return err + } + } } if iCadence.Status.CurrentClusterOperationStatus == models.NoOperation && @@ -1179,6 +1191,24 @@ func (r *CadenceReconciler) updateDescriptionAndTwoFactorDelete(cadence *v1beta1 return nil } +func areSecondaryCadenceTargetsEqual(first, second []*v1beta1.TargetCadence) bool { + for _, secondTarget := range second { + var ok bool + for _, firstTarget := range first { + if *secondTarget == *firstTarget { + ok = true + break + } + } + + if !ok { + return false + } + } + + return true +} + // SetupWithManager sets up the controller with the Manager. func (r *CadenceReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). diff --git a/pkg/models/cadence_apiv2.go b/pkg/models/cadence_apiv2.go index 09b0bc732..db859aaa5 100644 --- a/pkg/models/cadence_apiv2.go +++ b/pkg/models/cadence_apiv2.go @@ -26,18 +26,20 @@ const ( ) type CadenceCluster struct { - ClusterStatus `json:",inline"` - Name string `json:"name"` - CadenceVersion string `json:"cadenceVersion"` - DataCentres []*CadenceDataCentre `json:"dataCentres"` - SharedProvisioning []*CadenceSharedProvisioning `json:"sharedProvisioning,omitempty"` - StandardProvisioning []*CadenceStandardProvisioning `json:"standardProvisioning,omitempty"` - PCIComplianceMode bool `json:"pciComplianceMode"` - TwoFactorDelete []*TwoFactorDelete `json:"twoFactorDelete,omitempty"` - UseCadenceWebAuth bool `json:"useCadenceWebAuth"` - PrivateNetworkCluster bool `json:"privateNetworkCluster"` - SLATier string `json:"slaTier"` - AWSArchival []*AWSArchival `json:"awsArchival,omitempty"` + ClusterStatus `json:",inline"` + Name string `json:"name"` + CadenceVersion string `json:"cadenceVersion"` + DataCentres []*CadenceDataCentre `json:"dataCentres"` + SharedProvisioning []*CadenceSharedProvisioning `json:"sharedProvisioning,omitempty"` + StandardProvisioning []*CadenceStandardProvisioning `json:"standardProvisioning,omitempty"` + PCIComplianceMode bool `json:"pciComplianceMode"` + TwoFactorDelete []*TwoFactorDelete `json:"twoFactorDelete,omitempty"` + UseCadenceWebAuth bool `json:"useCadenceWebAuth"` + PrivateNetworkCluster bool `json:"privateNetworkCluster"` + SLATier string `json:"slaTier"` + AWSArchival []*AWSArchival `json:"awsArchival,omitempty"` + TargetPrimaryCadence []*TargetCadence `json:"targetPrimaryCadence,omitempty"` + TargetSecondaryCadence []*TargetCadence `json:"targetSecondaryCadence,omitempty"` } type CadenceDataCentre struct { @@ -75,6 +77,11 @@ type TargetCassandra struct { DependencyVPCType string `json:"dependencyVpcType"` } +type TargetCadence struct { + DependencyCDCID string `json:"dependencyCdcId"` + DependencyVPCType string `json:"dependencyVpcType"` +} + type AWSArchival struct { ArchivalS3Region string `json:"archivalS3Region,omitempty"` AWSAccessKeyID string `json:"awsAccessKeyId,omitempty"`