From 181a49ea5871f7b392ec0f8a0121473d78f596f3 Mon Sep 17 00:00:00 2001 From: tengu-alt Date: Thu, 16 Nov 2023 11:25:03 +0200 Subject: [PATCH] clusters were migrated on clusterresource refs pattern --- .../v1beta1/clusterbackup_types.go | 1 - .../v1beta1/exclusionwindow_types.go | 1 - .../v1beta1/gcpvpcpeering_types.go | 8 - .../v1beta1/gcpvpcpeering_webhook.go | 4 - apis/clusterresources/v1beta1/structs.go | 6 +- apis/clusters/v1beta1/cadence_types.go | 1 + apis/clusters/v1beta1/cassandra_types.go | 2 +- apis/clusters/v1beta1/kafka_types.go | 1 + apis/clusters/v1beta1/kafkaconnect_types.go | 1 + apis/clusters/v1beta1/opensearch_types.go | 2 +- apis/clusters/v1beta1/postgresql_types.go | 10 - apis/clusters/v1beta1/redis_types.go | 5 +- apis/clusters/v1beta1/structs.go | 16 ++ apis/clusters/v1beta1/zookeeper_types.go | 5 +- .../clusters/v1beta1/zz_generated.deepcopy.go | 51 +++-- ...str.com_awssecuritygroupfirewallrules.yaml | 2 - ...ources.instaclustr.com_awsvpcpeerings.yaml | 2 - ...ces.instaclustr.com_azurevnetpeerings.yaml | 2 - ...ources.instaclustr.com_clusterbackups.yaml | 2 - ...lustr.com_clusternetworkfirewallrules.yaml | 2 - ...rces.instaclustr.com_exclusionwindows.yaml | 4 +- ...ources.instaclustr.com_gcpvpcpeerings.yaml | 2 - .../clusters.instaclustr.com_cadences.yaml | 103 +++++++++ .../clusters.instaclustr.com_cassandras.yaml | 103 +++++++++ ...lusters.instaclustr.com_kafkaconnects.yaml | 103 +++++++++ .../clusters.instaclustr.com_kafkas.yaml | 103 +++++++++ ...clusters.instaclustr.com_opensearches.yaml | 103 +++++++++ .../clusters.instaclustr.com_postgresqls.yaml | 16 ++ .../bases/clusters.instaclustr.com_redis.yaml | 105 +++++++++ .../clusters.instaclustr.com_zookeepers.yaml | 103 +++++++++ ..._v1beta1_awssecuritygroupfirewallrule.yaml | 2 +- ...lusterresources_v1beta1_clusterbackup.yaml | 2 +- config/samples/clusters_v1beta1_cadence.yaml | 23 ++ .../samples/clusters_v1beta1_cassandra.yaml | 32 +++ config/samples/clusters_v1beta1_kafka.yaml | 23 ++ .../clusters_v1beta1_kafkaconnect.yaml | 23 ++ .../samples/clusters_v1beta1_opensearch.yaml | 26 +++ .../samples/clusters_v1beta1_postgresql.yaml | 8 +- config/samples/clusters_v1beta1_redis.yaml | 32 +++ .../samples/clusters_v1beta1_zookeeper.yaml | 25 +- ...awssecuritygroupfirewallrule_controller.go | 2 +- ...curitygroupfirewallrule_controller_test.go | 3 +- .../awsvpcpeering_controller_test.go | 3 +- .../azurevnetpeering_controller_test.go | 3 +- ...sternetworkfirewallrule_controller_test.go | 3 +- .../exclusionwindow_controller.go | 2 +- .../gcpvpcpeering_controller.go | 2 +- .../gcpvpcpeering_controller_test.go | 3 +- controllers/clusters/cadence_controller.go | 203 +++++++++++++++++ controllers/clusters/cassandra_controller.go | 213 ++++++++++++++++++ controllers/clusters/helpers.go | 2 +- controllers/clusters/kafka_controller.go | 203 +++++++++++++++++ .../clusters/kafkaconnect_controller.go | 207 +++++++++++++++++ controllers/clusters/opensearch_controller.go | 203 +++++++++++++++++ controllers/clusters/postgresql_controller.go | 40 +++- controllers/clusters/redis_controller.go | 213 ++++++++++++++++++ controllers/clusters/zookeeper_controller.go | 204 +++++++++++++++++ 57 files changed, 2488 insertions(+), 86 deletions(-) diff --git a/apis/clusterresources/v1beta1/clusterbackup_types.go b/apis/clusterresources/v1beta1/clusterbackup_types.go index ff5552526..e6695fb4a 100644 --- a/apis/clusterresources/v1beta1/clusterbackup_types.go +++ b/apis/clusterresources/v1beta1/clusterbackup_types.go @@ -27,7 +27,6 @@ import ( // ClusterBackupSpec defines the desired state of ClusterBackup type ClusterBackupSpec struct { - ClusterID string `json:"clusterId,omitempty"` ClusterKind string `json:"clusterKind"` } diff --git a/apis/clusterresources/v1beta1/exclusionwindow_types.go b/apis/clusterresources/v1beta1/exclusionwindow_types.go index d377395c2..723cca31d 100644 --- a/apis/clusterresources/v1beta1/exclusionwindow_types.go +++ b/apis/clusterresources/v1beta1/exclusionwindow_types.go @@ -25,7 +25,6 @@ import ( // ExclusionWindowSpec defines the desired state of ExclusionWindow type ExclusionWindowSpec struct { - ClusterID string `json:"clusterId,omitempty"` DayOfWeek string `json:"dayOfWeek"` //+kubebuilder:validation:Minimum:=0 //+kubebuilder:validation:Maximum:=23 diff --git a/apis/clusterresources/v1beta1/gcpvpcpeering_types.go b/apis/clusterresources/v1beta1/gcpvpcpeering_types.go index f427a99a2..40f3c1334 100644 --- a/apis/clusterresources/v1beta1/gcpvpcpeering_types.go +++ b/apis/clusterresources/v1beta1/gcpvpcpeering_types.go @@ -83,14 +83,6 @@ func init() { } func (gcp *GCPVPCPeeringSpec) Validate() error { - dataCentreIDMatched, err := regexp.Match(models.UUIDStringRegExp, []byte(gcp.DataCentreID)) - if err != nil { - return err - } - if !dataCentreIDMatched { - return fmt.Errorf("data centre ID is a UUID formated string. It must fit the pattern: %s", models.UUIDStringRegExp) - } - for _, subnet := range gcp.PeerSubnets { peerSubnetMatched, err := regexp.Match(models.PeerSubnetsRegExp, []byte(subnet)) if err != nil { diff --git a/apis/clusterresources/v1beta1/gcpvpcpeering_webhook.go b/apis/clusterresources/v1beta1/gcpvpcpeering_webhook.go index 72c5d2ce3..2c2cd026d 100644 --- a/apis/clusterresources/v1beta1/gcpvpcpeering_webhook.go +++ b/apis/clusterresources/v1beta1/gcpvpcpeering_webhook.go @@ -67,10 +67,6 @@ func (r *GCPVPCPeering) ValidateCreate() error { return fmt.Errorf("peer Project ID is empty") } - if r.Spec.DataCentreID == "" { - return fmt.Errorf("dataCentre ID is empty") - } - if r.Spec.PeerSubnets == nil { return fmt.Errorf("peer Subnets list is empty") } diff --git a/apis/clusterresources/v1beta1/structs.go b/apis/clusterresources/v1beta1/structs.go index 3dfabf201..bc4bcdcaf 100644 --- a/apis/clusterresources/v1beta1/structs.go +++ b/apis/clusterresources/v1beta1/structs.go @@ -21,8 +21,7 @@ import ( ) type VPCPeeringSpec struct { - DataCentreID string `json:"cdcId,omitempty"` - PeerSubnets []string `json:"peerSubnets"` + PeerSubnets []string `json:"peerSubnets"` } type PeeringStatus struct { @@ -41,8 +40,7 @@ type PatchRequest struct { } type FirewallRuleSpec struct { - ClusterID string `json:"clusterId,omitempty"` - Type string `json:"type"` + Type string `json:"type"` } type FirewallRuleStatus struct { diff --git a/apis/clusters/v1beta1/cadence_types.go b/apis/clusters/v1beta1/cadence_types.go index f3b394f27..b065322ff 100644 --- a/apis/clusters/v1beta1/cadence_types.go +++ b/apis/clusters/v1beta1/cadence_types.go @@ -73,6 +73,7 @@ type CadenceSpec struct { PackagedProvisioning []*PackagedProvisioning `json:"packagedProvisioning,omitempty"` TargetPrimaryCadence []*TargetCadence `json:"targetPrimaryCadence,omitempty"` ResizeSettings []*ResizeSettings `json:"resizeSettings,omitempty"` + ClusterResources ClusterResourceRefs `json:"clusterResources,omitempty"` } type AWSArchival struct { diff --git a/apis/clusters/v1beta1/cassandra_types.go b/apis/clusters/v1beta1/cassandra_types.go index 12912dbe1..512ca9ab3 100644 --- a/apis/clusters/v1beta1/cassandra_types.go +++ b/apis/clusters/v1beta1/cassandra_types.go @@ -63,6 +63,7 @@ type CassandraSpec struct { Spark []*Spark `json:"spark,omitempty"` BundledUseOnly bool `json:"bundledUseOnly,omitempty"` UserRefs []*NamespacedName `json:"userRefs,omitempty"` + ClusterResources ClusterResourceRefs `json:"clusterResources,omitempty"` //+kubebuilder:validate:MaxItems:=1 ResizeSettings []*ResizeSettings `json:"resizeSettings,omitempty"` } @@ -151,7 +152,6 @@ func (c *Cassandra) NewBackupSpec(startTimestamp int) *clusterresourcesv1beta1.C Finalizers: []string{models.DeletionFinalizer}, }, Spec: clusterresourcesv1beta1.ClusterBackupSpec{ - ClusterID: c.Status.ID, ClusterKind: models.CassandraClusterKind, }, } diff --git a/apis/clusters/v1beta1/kafka_types.go b/apis/clusters/v1beta1/kafka_types.go index 84ff6907c..6bf9666f4 100644 --- a/apis/clusters/v1beta1/kafka_types.go +++ b/apis/clusters/v1beta1/kafka_types.go @@ -89,6 +89,7 @@ type KafkaSpec struct { KarapaceSchemaRegistry []*KarapaceSchemaRegistry `json:"karapaceSchemaRegistry,omitempty"` BundledUseOnly bool `json:"bundledUseOnly,omitempty"` UserRefs []*NamespacedName `json:"userRefs,omitempty"` + ClusterResources ClusterResourceRefs `json:"clusterResources,omitempty"` Kraft []*Kraft `json:"kraft,omitempty"` } diff --git a/apis/clusters/v1beta1/kafkaconnect_types.go b/apis/clusters/v1beta1/kafkaconnect_types.go index a101ee454..59466dfcc 100644 --- a/apis/clusters/v1beta1/kafkaconnect_types.go +++ b/apis/clusters/v1beta1/kafkaconnect_types.go @@ -111,6 +111,7 @@ type KafkaConnectSpec struct { // CustomConnectors defines the location for custom connector storage and access info. CustomConnectors []*CustomConnectors `json:"customConnectors,omitempty"` + ClusterResources ClusterResourceRefs `json:"clusterResources,omitempty"` } // KafkaConnectStatus defines the observed state of KafkaConnect diff --git a/apis/clusters/v1beta1/opensearch_types.go b/apis/clusters/v1beta1/opensearch_types.go index efdeb736a..974e2ad70 100644 --- a/apis/clusters/v1beta1/opensearch_types.go +++ b/apis/clusters/v1beta1/opensearch_types.go @@ -54,6 +54,7 @@ type OpenSearchSpec struct { AlertingPlugin bool `json:"alertingPlugin,omitempty"` BundledUseOnly bool `json:"bundledUseOnly,omitempty"` UserRefs []*NamespacedName `json:"userRefs,omitempty"` + ClusterResources ClusterResourceRefs `json:"clusterResources,omitempty"` //+kubuilder:validation:MaxItems:=1 ResizeSettings []*ResizeSettings `json:"resizeSettings,omitempty"` } @@ -551,7 +552,6 @@ func (os *OpenSearch) NewBackupSpec(startTimestamp int) *clusterresourcesv1beta1 Finalizers: []string{models.DeletionFinalizer}, }, Spec: clusterresourcesv1beta1.ClusterBackupSpec{ - ClusterID: os.Status.ID, ClusterKind: models.OsClusterKind, }, } diff --git a/apis/clusters/v1beta1/postgresql_types.go b/apis/clusters/v1beta1/postgresql_types.go index 3d98e7bd7..47557ad55 100644 --- a/apis/clusters/v1beta1/postgresql_types.go +++ b/apis/clusters/v1beta1/postgresql_types.go @@ -84,16 +84,6 @@ type PgSpec struct { ResizeSettings []*ResizeSettings `json:"resizeSettings,omitempty"` } -type ClusterResourceRefs struct { - ClusterBackups []*NamespacedName `json:"clusterBackups,omitempty"` - ClusterNetworkFirewallRules []*NamespacedName `json:"clusterNetworkFirewallRules,omitempty"` - AWSVPCPeerings []*NamespacedName `json:"awsVPCPeerings,omitempty"` - AWSSecurityGroupFirewallRules []*NamespacedName `json:"awsSecurityGroupFirewallRules,omitempty"` - ExclusionWindows []*NamespacedName `json:"exclusionWindows,omitempty"` - GCPVPCPeerings []*NamespacedName `json:"gcpVPCPeerings,omitempty"` - AzureVNetPeerings []*NamespacedName `json:"azureVNetPeerings,omitempty"` -} - // PgStatus defines the observed state of PostgreSQL type PgStatus struct { ClusterStatus `json:",inline"` diff --git a/apis/clusters/v1beta1/redis_types.go b/apis/clusters/v1beta1/redis_types.go index 1cacd8d43..b7663650d 100644 --- a/apis/clusters/v1beta1/redis_types.go +++ b/apis/clusters/v1beta1/redis_types.go @@ -69,7 +69,9 @@ type RedisSpec struct { //+kubebuilder:validation:MaxItems:=2 DataCentres []*RedisDataCentre `json:"dataCentres,omitempty"` - UserRefs []*NamespacedName `json:"userRefs,omitempty"` + UserRefs []*NamespacedName `json:"userRefs,omitempty"` + ClusterResources ClusterResourceRefs `json:"clusterResources,omitempty"` + DataCentreNameForPeerings string `json:"dataCentreNameForPeerings,omitempty"` //+kubebuilder:validation:MaxItems:=1 ResizeSettings []*ResizeSettings `json:"resizeSettings,omitempty"` } @@ -142,7 +144,6 @@ func (r *Redis) NewBackupSpec(startTimestamp int) *clusterresourcesv1beta1.Clust Finalizers: []string{models.DeletionFinalizer}, }, Spec: clusterresourcesv1beta1.ClusterBackupSpec{ - ClusterID: r.Status.ID, ClusterKind: models.RedisClusterKind, }, } diff --git a/apis/clusters/v1beta1/structs.go b/apis/clusters/v1beta1/structs.go index 8981e8858..168424ebe 100644 --- a/apis/clusters/v1beta1/structs.go +++ b/apis/clusters/v1beta1/structs.go @@ -43,6 +43,7 @@ type DataCentre struct { } type DataCentreStatus struct { + Name string `json:"name,omitempty"` ID string `json:"id,omitempty"` Status string `json:"status,omitempty"` Nodes []*Node `json:"nodes,omitempty"` @@ -556,6 +557,7 @@ func areClusteredMaintenanceEventStatusEqual(a, b *clusterresource.MaintenanceEv func (cs *ClusterStatus) DCFromInstAPI(iDC models.DataCentre) *DataCentreStatus { return &DataCentreStatus{ + Name: iDC.Name, ID: iDC.ID, Status: iDC.Status, Nodes: cs.NodesFromInstAPI(iDC.Nodes), @@ -711,6 +713,20 @@ func (cs *ClusterStatus) PrivateLinkStatusesEqual(iStatus *ClusterStatus) bool { return true } +type ClusterResourceRefs struct { + ClusterBackups []*ClusterResourceRef `json:"clusterBackups,omitempty"` + ClusterNetworkFirewallRules []*ClusterResourceRef `json:"clusterNetworkFirewallRules,omitempty"` + AWSVPCPeerings []*ClusterResourceRef `json:"awsVPCPeerings,omitempty"` + AWSSecurityGroupFirewallRules []*ClusterResourceRef `json:"awsSecurityGroupFirewallRules,omitempty"` + ExclusionWindows []*ClusterResourceRef `json:"exclusionWindows,omitempty"` + GCPVPCPeerings []*ClusterResourceRef `json:"gcpVPCPeerings,omitempty"` + AzureVNetPeerings []*ClusterResourceRef `json:"azureVNetPeerings,omitempty"` +} +type ClusterResourceRef struct { + NamespacedName `json:",inline"` + DataCentreName string `json:"dataCentreName,omitempty"` +} + type NamespacedName struct { Namespace string `json:"namespace"` Name string `json:"name"` diff --git a/apis/clusters/v1beta1/zookeeper_types.go b/apis/clusters/v1beta1/zookeeper_types.go index 11576f109..8378fdd4a 100644 --- a/apis/clusters/v1beta1/zookeeper_types.go +++ b/apis/clusters/v1beta1/zookeeper_types.go @@ -36,8 +36,9 @@ type ZookeeperDataCentre struct { // ZookeeperSpec defines the desired state of Zookeeper type ZookeeperSpec struct { - Cluster `json:",inline"` - DataCentres []*ZookeeperDataCentre `json:"dataCentres"` + Cluster `json:",inline"` + DataCentres []*ZookeeperDataCentre `json:"dataCentres"` + ClusterResources ClusterResourceRefs `json:"clusterResources,omitempty"` } // ZookeeperStatus defines the observed state of Zookeeper diff --git a/apis/clusters/v1beta1/zz_generated.deepcopy.go b/apis/clusters/v1beta1/zz_generated.deepcopy.go index ddddd5b12..6573238af 100644 --- a/apis/clusters/v1beta1/zz_generated.deepcopy.go +++ b/apis/clusters/v1beta1/zz_generated.deepcopy.go @@ -309,6 +309,7 @@ func (in *CadenceSpec) DeepCopyInto(out *CadenceSpec) { } } } + in.ClusterResources.DeepCopyInto(&out.ClusterResources) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CadenceSpec. @@ -491,6 +492,7 @@ func (in *CassandraSpec) DeepCopyInto(out *CassandraSpec) { } } } + in.ClusterResources.DeepCopyInto(&out.ClusterResources) if in.ResizeSettings != nil { in, out := &in.ResizeSettings, &out.ResizeSettings *out = make([]*ResizeSettings, len(*in)) @@ -586,82 +588,98 @@ func (in *ClusterManagerNodes) DeepCopy() *ClusterManagerNodes { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterResourceRef) DeepCopyInto(out *ClusterResourceRef) { + *out = *in + out.NamespacedName = in.NamespacedName +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResourceRef. +func (in *ClusterResourceRef) DeepCopy() *ClusterResourceRef { + if in == nil { + return nil + } + out := new(ClusterResourceRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterResourceRefs) DeepCopyInto(out *ClusterResourceRefs) { *out = *in if in.ClusterBackups != nil { in, out := &in.ClusterBackups, &out.ClusterBackups - *out = make([]*NamespacedName, len(*in)) + *out = make([]*ClusterResourceRef, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(NamespacedName) + *out = new(ClusterResourceRef) **out = **in } } } if in.ClusterNetworkFirewallRules != nil { in, out := &in.ClusterNetworkFirewallRules, &out.ClusterNetworkFirewallRules - *out = make([]*NamespacedName, len(*in)) + *out = make([]*ClusterResourceRef, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(NamespacedName) + *out = new(ClusterResourceRef) **out = **in } } } if in.AWSVPCPeerings != nil { in, out := &in.AWSVPCPeerings, &out.AWSVPCPeerings - *out = make([]*NamespacedName, len(*in)) + *out = make([]*ClusterResourceRef, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(NamespacedName) + *out = new(ClusterResourceRef) **out = **in } } } if in.AWSSecurityGroupFirewallRules != nil { in, out := &in.AWSSecurityGroupFirewallRules, &out.AWSSecurityGroupFirewallRules - *out = make([]*NamespacedName, len(*in)) + *out = make([]*ClusterResourceRef, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(NamespacedName) + *out = new(ClusterResourceRef) **out = **in } } } if in.ExclusionWindows != nil { in, out := &in.ExclusionWindows, &out.ExclusionWindows - *out = make([]*NamespacedName, len(*in)) + *out = make([]*ClusterResourceRef, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(NamespacedName) + *out = new(ClusterResourceRef) **out = **in } } } if in.GCPVPCPeerings != nil { in, out := &in.GCPVPCPeerings, &out.GCPVPCPeerings - *out = make([]*NamespacedName, len(*in)) + *out = make([]*ClusterResourceRef, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(NamespacedName) + *out = new(ClusterResourceRef) **out = **in } } } if in.AzureVNetPeerings != nil { in, out := &in.AzureVNetPeerings, &out.AzureVNetPeerings - *out = make([]*NamespacedName, len(*in)) + *out = make([]*ClusterResourceRef, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(NamespacedName) + *out = new(ClusterResourceRef) **out = **in } } @@ -1111,6 +1129,7 @@ func (in *KafkaConnectSpec) DeepCopyInto(out *KafkaConnectSpec) { } } } + in.ClusterResources.DeepCopyInto(&out.ClusterResources) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KafkaConnectSpec. @@ -1290,6 +1309,7 @@ func (in *KafkaSpec) DeepCopyInto(out *KafkaSpec) { } } } + in.ClusterResources.DeepCopyInto(&out.ClusterResources) if in.Kraft != nil { in, out := &in.Kraft, &out.Kraft *out = make([]*Kraft, len(*in)) @@ -1636,6 +1656,7 @@ func (in *OpenSearchSpec) DeepCopyInto(out *OpenSearchSpec) { } } } + in.ClusterResources.DeepCopyInto(&out.ClusterResources) if in.ResizeSettings != nil { in, out := &in.ResizeSettings, &out.ResizeSettings *out = make([]*ResizeSettings, len(*in)) @@ -2170,6 +2191,7 @@ func (in *RedisSpec) DeepCopyInto(out *RedisSpec) { } } } + in.ClusterResources.DeepCopyInto(&out.ClusterResources) if in.ResizeSettings != nil { in, out := &in.ResizeSettings, &out.ResizeSettings *out = make([]*ResizeSettings, len(*in)) @@ -2598,6 +2620,7 @@ func (in *ZookeeperSpec) DeepCopyInto(out *ZookeeperSpec) { } } } + in.ClusterResources.DeepCopyInto(&out.ClusterResources) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZookeeperSpec. diff --git a/config/crd/bases/clusterresources.instaclustr.com_awssecuritygroupfirewallrules.yaml b/config/crd/bases/clusterresources.instaclustr.com_awssecuritygroupfirewallrules.yaml index 1a786841e..5659a82ce 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_awssecuritygroupfirewallrules.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_awssecuritygroupfirewallrules.yaml @@ -37,8 +37,6 @@ spec: description: AWSSecurityGroupFirewallRuleSpec defines the desired state of AWSSecurityGroupFirewallRule properties: - clusterId: - type: string securityGroupId: type: string type: diff --git a/config/crd/bases/clusterresources.instaclustr.com_awsvpcpeerings.yaml b/config/crd/bases/clusterresources.instaclustr.com_awsvpcpeerings.yaml index fe03cfabf..f701ff0be 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_awsvpcpeerings.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_awsvpcpeerings.yaml @@ -35,8 +35,6 @@ spec: spec: description: AWSVPCPeeringSpec defines the desired state of AWSVPCPeering properties: - cdcId: - type: string peerAwsAccountId: type: string peerRegion: diff --git a/config/crd/bases/clusterresources.instaclustr.com_azurevnetpeerings.yaml b/config/crd/bases/clusterresources.instaclustr.com_azurevnetpeerings.yaml index dd2b9f704..e69c2aa33 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_azurevnetpeerings.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_azurevnetpeerings.yaml @@ -35,8 +35,6 @@ spec: spec: description: AzureVNetPeeringSpec defines the desired state of AzureVNetPeering properties: - cdcId: - type: string peerAdObjectId: type: string peerResourceGroup: diff --git a/config/crd/bases/clusterresources.instaclustr.com_clusterbackups.yaml b/config/crd/bases/clusterresources.instaclustr.com_clusterbackups.yaml index 36667a874..781f99348 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_clusterbackups.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_clusterbackups.yaml @@ -35,8 +35,6 @@ spec: spec: description: ClusterBackupSpec defines the desired state of ClusterBackup properties: - clusterId: - type: string clusterKind: type: string required: diff --git a/config/crd/bases/clusterresources.instaclustr.com_clusternetworkfirewallrules.yaml b/config/crd/bases/clusterresources.instaclustr.com_clusternetworkfirewallrules.yaml index ed0d2f264..bee765e3c 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_clusternetworkfirewallrules.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_clusternetworkfirewallrules.yaml @@ -37,8 +37,6 @@ spec: description: ClusterNetworkFirewallRuleSpec defines the desired state of ClusterNetworkFirewallRule properties: - clusterId: - type: string network: type: string type: diff --git a/config/crd/bases/clusterresources.instaclustr.com_exclusionwindows.yaml b/config/crd/bases/clusterresources.instaclustr.com_exclusionwindows.yaml index bdf9d7c1c..6991c6b5a 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_exclusionwindows.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_exclusionwindows.yaml @@ -35,8 +35,6 @@ spec: spec: description: ExclusionWindowSpec defines the desired state of ExclusionWindow properties: - clusterId: - type: string dayOfWeek: type: string durationInHours: @@ -56,7 +54,7 @@ spec: status: description: ExclusionWindowStatus defines the observed state of ExclusionWindow properties: - clusterID: + clusterId: type: string id: type: string diff --git a/config/crd/bases/clusterresources.instaclustr.com_gcpvpcpeerings.yaml b/config/crd/bases/clusterresources.instaclustr.com_gcpvpcpeerings.yaml index ff89b9975..787b8afb5 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_gcpvpcpeerings.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_gcpvpcpeerings.yaml @@ -35,8 +35,6 @@ spec: spec: description: GCPVPCPeeringSpec defines the desired state of GCPVPCPeering properties: - cdcId: - type: string peerProjectId: type: string peerSubnets: diff --git a/config/crd/bases/clusters.instaclustr.com_cadences.yaml b/config/crd/bases/clusters.instaclustr.com_cadences.yaml index 430055b50..5275cfebd 100644 --- a/config/crd/bases/clusters.instaclustr.com_cadences.yaml +++ b/config/crd/bases/clusters.instaclustr.com_cadences.yaml @@ -66,6 +66,107 @@ spec: - awsAccessKeySecretNamespace type: object type: array + clusterResources: + properties: + awsSecurityGroupFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + awsVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + azureVNetPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterBackups: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterNetworkFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + exclusionWindows: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + gcpVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + type: object dataCentres: items: properties: @@ -313,6 +414,8 @@ spec: type: string id: type: string + name: + type: string nodeNumber: type: integer nodes: diff --git a/config/crd/bases/clusters.instaclustr.com_cassandras.yaml b/config/crd/bases/clusters.instaclustr.com_cassandras.yaml index a28675bc9..7577ce88e 100644 --- a/config/crd/bases/clusters.instaclustr.com_cassandras.yaml +++ b/config/crd/bases/clusters.instaclustr.com_cassandras.yaml @@ -50,6 +50,107 @@ spec: properties: bundledUseOnly: type: boolean + clusterResources: + properties: + awsSecurityGroupFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + awsVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + azureVNetPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterBackups: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterNetworkFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + exclusionWindows: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + gcpVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + type: object dataCentres: items: properties: @@ -235,6 +336,8 @@ spec: type: string id: type: string + name: + type: string nodeNumber: type: integer nodes: diff --git a/config/crd/bases/clusters.instaclustr.com_kafkaconnects.yaml b/config/crd/bases/clusters.instaclustr.com_kafkaconnects.yaml index fa695dab9..e49d360eb 100644 --- a/config/crd/bases/clusters.instaclustr.com_kafkaconnects.yaml +++ b/config/crd/bases/clusters.instaclustr.com_kafkaconnects.yaml @@ -48,6 +48,107 @@ spec: spec: description: KafkaConnectSpec defines the desired state of KafkaConnect properties: + clusterResources: + properties: + awsSecurityGroupFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + awsVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + azureVNetPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterBackups: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterNetworkFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + exclusionWindows: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + gcpVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + type: object customConnectors: description: CustomConnectors defines the location for custom connector storage and access info. @@ -271,6 +372,8 @@ spec: type: string id: type: string + name: + type: string nodeNumber: type: integer nodes: diff --git a/config/crd/bases/clusters.instaclustr.com_kafkas.yaml b/config/crd/bases/clusters.instaclustr.com_kafkas.yaml index fa81af863..58553882f 100644 --- a/config/crd/bases/clusters.instaclustr.com_kafkas.yaml +++ b/config/crd/bases/clusters.instaclustr.com_kafkas.yaml @@ -58,6 +58,107 @@ spec: type: boolean clientToClusterEncryption: type: boolean + clusterResources: + properties: + awsSecurityGroupFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + awsVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + azureVNetPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterBackups: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterNetworkFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + exclusionWindows: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + gcpVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + type: object dataCentres: items: properties: @@ -275,6 +376,8 @@ spec: type: string id: type: string + name: + type: string nodeNumber: type: integer nodes: diff --git a/config/crd/bases/clusters.instaclustr.com_opensearches.yaml b/config/crd/bases/clusters.instaclustr.com_opensearches.yaml index 628ea13f4..286ab6393 100644 --- a/config/crd/bases/clusters.instaclustr.com_opensearches.yaml +++ b/config/crd/bases/clusters.instaclustr.com_opensearches.yaml @@ -68,6 +68,107 @@ spec: - nodeSize type: object type: array + clusterResources: + properties: + awsSecurityGroupFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + awsVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + azureVNetPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterBackups: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterNetworkFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + exclusionWindows: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + gcpVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + type: object dashboards: items: properties: @@ -265,6 +366,8 @@ spec: type: string id: type: string + name: + type: string nodeNumber: type: integer nodes: diff --git a/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml b/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml index 0abe205c7..9eae9a2da 100644 --- a/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml +++ b/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml @@ -57,6 +57,8 @@ spec: awsSecurityGroupFirewallRules: items: properties: + dataCentreName: + type: string name: type: string namespace: @@ -69,6 +71,8 @@ spec: awsVPCPeerings: items: properties: + dataCentreName: + type: string name: type: string namespace: @@ -81,6 +85,8 @@ spec: azureVNetPeerings: items: properties: + dataCentreName: + type: string name: type: string namespace: @@ -93,6 +99,8 @@ spec: clusterBackups: items: properties: + dataCentreName: + type: string name: type: string namespace: @@ -105,6 +113,8 @@ spec: clusterNetworkFirewallRules: items: properties: + dataCentreName: + type: string name: type: string namespace: @@ -117,6 +127,8 @@ spec: exclusionWindows: items: properties: + dataCentreName: + type: string name: type: string namespace: @@ -129,6 +141,8 @@ spec: gcpVPCPeerings: items: properties: + dataCentreName: + type: string name: type: string namespace: @@ -328,6 +342,8 @@ spec: type: string id: type: string + name: + type: string nodeNumber: type: integer nodes: diff --git a/config/crd/bases/clusters.instaclustr.com_redis.yaml b/config/crd/bases/clusters.instaclustr.com_redis.yaml index f37da108c..f5cafb4fb 100644 --- a/config/crd/bases/clusters.instaclustr.com_redis.yaml +++ b/config/crd/bases/clusters.instaclustr.com_redis.yaml @@ -51,6 +51,109 @@ spec: clientEncryption: description: Enables client to node encryption type: boolean + clusterResources: + properties: + awsSecurityGroupFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + awsVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + azureVNetPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterBackups: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterNetworkFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + exclusionWindows: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + gcpVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + type: object + dataCentreNameForPeerings: + type: string dataCentres: items: properties: @@ -229,6 +332,8 @@ spec: type: string id: type: string + name: + type: string nodeNumber: type: integer nodes: diff --git a/config/crd/bases/clusters.instaclustr.com_zookeepers.yaml b/config/crd/bases/clusters.instaclustr.com_zookeepers.yaml index 061a0bc49..3f9a6cf9b 100644 --- a/config/crd/bases/clusters.instaclustr.com_zookeepers.yaml +++ b/config/crd/bases/clusters.instaclustr.com_zookeepers.yaml @@ -48,6 +48,107 @@ spec: spec: description: ZookeeperSpec defines the desired state of Zookeeper properties: + clusterResources: + properties: + awsSecurityGroupFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + awsVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + azureVNetPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterBackups: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterNetworkFirewallRules: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + exclusionWindows: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + gcpVPCPeerings: + items: + properties: + dataCentreName: + type: string + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + type: object dataCentres: items: properties: @@ -148,6 +249,8 @@ spec: type: string id: type: string + name: + type: string nodeNumber: type: integer nodes: diff --git a/config/samples/clusterresources_v1beta1_awssecuritygroupfirewallrule.yaml b/config/samples/clusterresources_v1beta1_awssecuritygroupfirewallrule.yaml index 81645a5ad..05bcda2e9 100644 --- a/config/samples/clusterresources_v1beta1_awssecuritygroupfirewallrule.yaml +++ b/config/samples/clusterresources_v1beta1_awssecuritygroupfirewallrule.yaml @@ -11,4 +11,4 @@ metadata: spec: securityGroupId: sg-0ab978e9e4f443cc8 # clusterId: ef924204-3139-43e9-8e03-c29278e6eccd - type: POSTGRESQL + type: KAFKA diff --git a/config/samples/clusterresources_v1beta1_clusterbackup.yaml b/config/samples/clusterresources_v1beta1_clusterbackup.yaml index 9ee13b783..07020d868 100644 --- a/config/samples/clusterresources_v1beta1_clusterbackup.yaml +++ b/config/samples/clusterresources_v1beta1_clusterbackup.yaml @@ -4,4 +4,4 @@ metadata: name: clusterbackup-sample spec: # clusterId: 2ae611cf-ac91-4325-941c-a35c043f9c34 - clusterKind: PostgreSQL \ No newline at end of file + clusterKind: OpenSearch \ No newline at end of file diff --git a/config/samples/clusters_v1beta1_cadence.yaml b/config/samples/clusters_v1beta1_cadence.yaml index 72b302978..8f1abd109 100644 --- a/config/samples/clusters_v1beta1_cadence.yaml +++ b/config/samples/clusters_v1beta1_cadence.yaml @@ -53,6 +53,29 @@ spec: clientEncryption: false # privateLink: # - advertisedHostname: "cadence-sample-test.com" + clusterResources: + clusterNetworkFirewallRules: +# - namespace: default +# name: clusternetworkfirewallrule-sample + awsVPCPeerings: +# - namespace: default +# name: awsvpcpeering-sample + awsSecurityGroupFirewallRules: +# - namespace: default +# name: awssecuritygroupfirewallrule-sample + exclusionWindows: +# - namespace: default +# name: exclusionwindow-sample + gcpVPCPeerings: + # - namespace: default + # name: gcpvpcpeering-sample + # - namespace: default + # name: gcpvpcpeering-sample-two + azureVNetPeerings: + # - namespace: default + # name: azurevnetpeering-sample + # - namespace: default + # name: azurevnetpeering-sample-trough slaTier: "NON_PRODUCTION" useCadenceWebAuth: false # targetPrimaryCadence: diff --git a/config/samples/clusters_v1beta1_cassandra.yaml b/config/samples/clusters_v1beta1_cassandra.yaml index d1e9be089..458cc05f8 100644 --- a/config/samples/clusters_v1beta1_cassandra.yaml +++ b/config/samples/clusters_v1beta1_cassandra.yaml @@ -42,6 +42,38 @@ spec: # name: cassandrauser-sample # - namespace: default # name: cassandrauser-sample2 + clusterResources: + clusterBackups: +# - namespace: default +# name: clusterbackup-sample +# - namespace: default +# name: clusterbackup-sample-two + clusterNetworkFirewallRules: +# - namespace: default +# name: clusternetworkfirewallrule-sample + awsVPCPeerings: +# - namespace: default +# name: awsvpcpeering-sample +# dataCentreName: AWS_cassandra +# - namespace: default +# name: awsvpcpeering-sample-two +# dataCentreName: AWS_cassandra2 + awsSecurityGroupFirewallRules: +# - namespace: default +# name: awssecuritygroupfirewallrule-sample + exclusionWindows: + - namespace: default + name: exclusionwindow-sample + gcpVPCPeerings: +# - namespace: default +# name: gcpvpcpeering-sample +# - namespace: default +# name: gcpvpcpeering-sample-two + azureVNetPeerings: +# - namespace: default +# name: azurevnetpeering-sample +# - namespace: default +# name: azurevnetpeering-sample-trough slaTier: "NON_PRODUCTION" # resizeSettings: # - notifySupportContacts: false diff --git a/config/samples/clusters_v1beta1_kafka.yaml b/config/samples/clusters_v1beta1_kafka.yaml index 6b6c632f4..02bace212 100644 --- a/config/samples/clusters_v1beta1_kafka.yaml +++ b/config/samples/clusters_v1beta1_kafka.yaml @@ -61,6 +61,29 @@ spec: # userRefs: # - name: kafkauser-sample # namespace: default + clusterResources: + clusterNetworkFirewallRules: + - namespace: default + name: clusternetworkfirewallrule-sample + awsVPCPeerings: + - namespace: default + name: awsvpcpeering-sample + awsSecurityGroupFirewallRules: +# - namespace: default +# name: awssecuritygroupfirewallrule-sample + exclusionWindows: + - namespace: default + name: exclusionwindow-sample + gcpVPCPeerings: + # - namespace: default + # name: gcpvpcpeering-sample + # - namespace: default + # name: gcpvpcpeering-sample-two + azureVNetPeerings: + # - namespace: default + # name: azurevnetpeering-sample + # - namespace: default + # name: azurevnetpeering-sample-trough resizeSettings: - notifySupportContacts: false concurrency: 1 \ No newline at end of file diff --git a/config/samples/clusters_v1beta1_kafkaconnect.yaml b/config/samples/clusters_v1beta1_kafkaconnect.yaml index 0b6a840a0..1ff8eed6f 100644 --- a/config/samples/clusters_v1beta1_kafkaconnect.yaml +++ b/config/samples/clusters_v1beta1_kafkaconnect.yaml @@ -15,6 +15,29 @@ spec: nodeSize: "KCN-DEV-t4g.medium-30" network: "10.15.0.0/16" region: "US_EAST_1" + clusterResources: + clusterNetworkFirewallRules: +# - namespace: default +# name: clusternetworkfirewallrule-sample + awsVPCPeerings: + - namespace: default + name: awsvpcpeering-sample + awsSecurityGroupFirewallRules: + - namespace: default + name: awssecuritygroupfirewallrule-sample + exclusionWindows: + - namespace: default + name: exclusionwindow-sample + gcpVPCPeerings: + # - namespace: default + # name: gcpvpcpeering-sample + # - namespace: default + # name: gcpvpcpeering-sample-two + azureVNetPeerings: + # - namespace: default + # name: azurevnetpeering-sample + # - namespace: default + # name: azurevnetpeering-sample-trough name: "Username-KC" version: "3.1.2" privateNetworkCluster: false diff --git a/config/samples/clusters_v1beta1_opensearch.yaml b/config/samples/clusters_v1beta1_opensearch.yaml index 3e006b323..e16fb719f 100644 --- a/config/samples/clusters_v1beta1_opensearch.yaml +++ b/config/samples/clusters_v1beta1_opensearch.yaml @@ -48,6 +48,32 @@ spec: reportingPlugin: false slaTier: NON_PRODUCTION sqlPlugin: false + clusterResources: + clusterBackups: +# - namespace: default +# name: clusterbackup-sample + clusterNetworkFirewallRules: +# - namespace: default +# name: clusternetworkfirewallrule-sample + awsVPCPeerings: +# - namespace: default +# name: awsvpcpeering-sample + awsSecurityGroupFirewallRules: +# - namespace: default +# name: awssecuritygroupfirewallrule-sample + exclusionWindows: +# - namespace: default +# name: exclusionwindow-sample + gcpVPCPeerings: + # - namespace: default + # name: gcpvpcpeering-sample + # - namespace: default + # name: gcpvpcpeering-sample-two + azureVNetPeerings: + # - namespace: default + # name: azurevnetpeering-sample + # - namespace: default + # name: azurevnetpeering-sample-trough # resizeSettings: # - notifySupportContacts: false # concurrency: 3 diff --git a/config/samples/clusters_v1beta1_postgresql.yaml b/config/samples/clusters_v1beta1_postgresql.yaml index 0982551c7..9fd8d0f39 100644 --- a/config/samples/clusters_v1beta1_postgresql.yaml +++ b/config/samples/clusters_v1beta1_postgresql.yaml @@ -53,8 +53,12 @@ spec: # - namespace: default # name: clusternetworkfirewallrule-sample awsVPCPeerings: -# - namespace: default -# name: awsvpcpeering-sample +# - namespace: default +# name: awsvpcpeering-sample +# dataCentreName: testDC1 +# - namespace: default +# name: awsvpcpeering-sample-two +# dataCentreName: testDC2 awsSecurityGroupFirewallRules: # - namespace: default # name: awssecuritygroupfirewallrule-sample diff --git a/config/samples/clusters_v1beta1_redis.yaml b/config/samples/clusters_v1beta1_redis.yaml index fb33d29d5..81be5499d 100644 --- a/config/samples/clusters_v1beta1_redis.yaml +++ b/config/samples/clusters_v1beta1_redis.yaml @@ -24,6 +24,38 @@ spec: # namespace: default # twoFactorDelete: # - email: "rostyslp@netapp.com" + clusterResources: + clusterBackups: +# - namespace: default +# name: clusterbackup-sample + # - namespace: default + # name: clusterbackup-sample-two + clusterNetworkFirewallRules: +# - namespace: default +# name: clusternetworkfirewallrule-sample + awsVPCPeerings: + - namespace: default + name: awsvpcpeering-sample + dataCentreName: testDC1 + - namespace: default + name: awsvpcpeering-sample-two + dataCentreName: testDC2 + awsSecurityGroupFirewallRules: +# - namespace: default +# name: awssecuritygroupfirewallrule-sample + exclusionWindows: +# - namespace: default +# name: exclusionwindow-sample + gcpVPCPeerings: + # - namespace: default + # name: gcpvpcpeering-sample + # - namespace: default + # name: gcpvpcpeering-sample-two + azureVNetPeerings: + # - namespace: default + # name: azurevnetpeering-sample + # - namespace: default + # name: azurevnetpeering-sample-trough dataCentres: - region: "US_WEST_2" cloudProvider: "AWS_VPC" diff --git a/config/samples/clusters_v1beta1_zookeeper.yaml b/config/samples/clusters_v1beta1_zookeeper.yaml index 4fb8adbe2..f12b9bcc2 100644 --- a/config/samples/clusters_v1beta1_zookeeper.yaml +++ b/config/samples/clusters_v1beta1_zookeeper.yaml @@ -12,7 +12,30 @@ spec: nodeSize: "zookeeper-production-m5.large-60" nodesNumber: 3 region: "US_EAST_1" - name: "Username-zookeeper" + clusterResources: + clusterNetworkFirewallRules: +# - namespace: default +# name: clusternetworkfirewallrule-sample + awsVPCPeerings: +# - namespace: default +# name: awsvpcpeering-sample + awsSecurityGroupFirewallRules: +# - namespace: default +# name: awssecuritygroupfirewallrule-sample + exclusionWindows: +# - namespace: default +# name: exclusionwindow-sample + gcpVPCPeerings: + # - namespace: default + # name: gcpvpcpeering-sample + # - namespace: default + # name: gcpvpcpeering-sample-two + azureVNetPeerings: + # - namespace: default + # name: azurevnetpeering-sample + # - namespace: default + # name: azurevnetpeering-sample-trough + name: "oleksandr-zookeeper" privateNetworkCluster: false slaTier: "NON_PRODUCTION" version: "3.7.1" diff --git a/controllers/clusterresources/awssecuritygroupfirewallrule_controller.go b/controllers/clusterresources/awssecuritygroupfirewallrule_controller.go index 8b9a0466c..b51d68754 100644 --- a/controllers/clusterresources/awssecuritygroupfirewallrule_controller.go +++ b/controllers/clusterresources/awssecuritygroupfirewallrule_controller.go @@ -217,7 +217,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleDeleteFirewallRule( if status != nil && status.Status != statusDELETED { err = r.API.DeleteFirewallRule(firewallRule.Status.ID, instaclustr.AWSSecurityGroupFirewallRuleEndpoint) - if err != nil { + if err != nil && !errors.Is(err, instaclustr.NotFound) { l.Error(err, "Cannot delete AWS security group firewall rule", "rule ID", firewallRule.Status.ID, "cluster ID", firewallRule.Status.ClusterID, diff --git a/controllers/clusterresources/awssecuritygroupfirewallrule_controller_test.go b/controllers/clusterresources/awssecuritygroupfirewallrule_controller_test.go index 2440693a6..789983956 100644 --- a/controllers/clusterresources/awssecuritygroupfirewallrule_controller_test.go +++ b/controllers/clusterresources/awssecuritygroupfirewallrule_controller_test.go @@ -33,8 +33,7 @@ var _ = Describe("Successful creation of a AWS Security Group Firewall Rule reso Context("When setting up a AWS Security Group Firewall Rule CRD", func() { awsSGFirewallRuleSpec := v1beta1.AWSSecurityGroupFirewallRuleSpec{ FirewallRuleSpec: v1beta1.FirewallRuleSpec{ - ClusterID: "375e4d1c-2f77-4d02-a6f2-1af617ff2ab2", - Type: "SECURITY", + Type: "SECURITY", }, SecurityGroupID: "sg-1434412", } diff --git a/controllers/clusterresources/awsvpcpeering_controller_test.go b/controllers/clusterresources/awsvpcpeering_controller_test.go index a8b28c608..2170302ac 100644 --- a/controllers/clusterresources/awsvpcpeering_controller_test.go +++ b/controllers/clusterresources/awsvpcpeering_controller_test.go @@ -33,8 +33,7 @@ var _ = Describe("Successful creation of a AWS VPC Peering resource", func() { Context("When setting up a AWS VPC Peering CRD", func() { awsVPCPeeringSpec := v1beta1.AWSVPCPeeringSpec{ VPCPeeringSpec: v1beta1.VPCPeeringSpec{ - DataCentreID: "375e4d1c-2f77-4d02-a6f2-1af617ff2ab2", - PeerSubnets: []string{"172.31.0.0/16", "192.168.0.0/16"}, + PeerSubnets: []string{"172.31.0.0/16", "192.168.0.0/16"}, }, PeerAWSAccountID: "152668027680", PeerVPCID: "vpc-87241ae1", diff --git a/controllers/clusterresources/azurevnetpeering_controller_test.go b/controllers/clusterresources/azurevnetpeering_controller_test.go index 021a30fc8..9e8bec760 100644 --- a/controllers/clusterresources/azurevnetpeering_controller_test.go +++ b/controllers/clusterresources/azurevnetpeering_controller_test.go @@ -33,8 +33,7 @@ var _ = Describe("Successful creation of a Azure VNet Peering resource", func() Context("When setting up a Azure VNet Peering CRD", func() { azureVNetPeeringSpec := v1beta1.AzureVNetPeeringSpec{ VPCPeeringSpec: v1beta1.VPCPeeringSpec{ - DataCentreID: "375e4d1c-2f77-4d02-a6f2-1af617ff2ab2", - PeerSubnets: []string{"172.31.0.0/16", "192.168.0.0/16"}, + PeerSubnets: []string{"172.31.0.0/16", "192.168.0.0/16"}, }, PeerResourceGroup: "rg-1231212", PeerSubscriptionID: "sg-123321", diff --git a/controllers/clusterresources/clusternetworkfirewallrule_controller_test.go b/controllers/clusterresources/clusternetworkfirewallrule_controller_test.go index 5c78acd8a..78d94f6ad 100644 --- a/controllers/clusterresources/clusternetworkfirewallrule_controller_test.go +++ b/controllers/clusterresources/clusternetworkfirewallrule_controller_test.go @@ -33,8 +33,7 @@ var _ = Describe("Successful creation of a Cluster Network Firewall Rule resourc Context("When setting up a Cluster Network Firewall Rule CRD", func() { clusterNetworkFirewallRuleSpec := v1beta1.ClusterNetworkFirewallRuleSpec{ FirewallRuleSpec: v1beta1.FirewallRuleSpec{ - ClusterID: "375e4d1c-2f77-4d02-a6f2-1af617ff2ab2", - Type: "SECURITY", + Type: "SECURITY", }, Network: "191.54.123.1/24", } diff --git a/controllers/clusterresources/exclusionwindow_controller.go b/controllers/clusterresources/exclusionwindow_controller.go index 8ba2895cf..68a4ffa80 100644 --- a/controllers/clusterresources/exclusionwindow_controller.go +++ b/controllers/clusterresources/exclusionwindow_controller.go @@ -185,7 +185,7 @@ func (r *ExclusionWindowReconciler) handleDeleteWindow( if status != "" { err = r.API.DeleteExclusionWindow(ew.Status.ID) - if err != nil { + if err != nil && !errors.Is(err, instaclustr.NotFound) { l.Error(err, "cannot delete Exclusion Window resource", "Cluster ID", ew.Status.ClusterID, "Exclusion Window Spec", ew.Spec, diff --git a/controllers/clusterresources/gcpvpcpeering_controller.go b/controllers/clusterresources/gcpvpcpeering_controller.go index 52dfd181c..bcd228d4a 100644 --- a/controllers/clusterresources/gcpvpcpeering_controller.go +++ b/controllers/clusterresources/gcpvpcpeering_controller.go @@ -273,7 +273,7 @@ func (r *GCPVPCPeeringReconciler) handleDeletePeering( "id", gcp.Status.ID, "project ID", gcp.Spec.PeerProjectID, "network name", gcp.Spec.PeerVPCNetworkName, - "data centre ID", gcp.Spec.DataCentreID, + "data centre ID", gcp.Status.CDCID, "status", gcp.Status.PeeringStatus, ) diff --git a/controllers/clusterresources/gcpvpcpeering_controller_test.go b/controllers/clusterresources/gcpvpcpeering_controller_test.go index bbd84dced..4bd64ae0d 100644 --- a/controllers/clusterresources/gcpvpcpeering_controller_test.go +++ b/controllers/clusterresources/gcpvpcpeering_controller_test.go @@ -33,8 +33,7 @@ var _ = Describe("Successful creation of a GCP VPC Peering resource", func() { Context("When setting up a GCP VPC Peering CRD", func() { gcpVPCPeeringSpec := v1beta1.GCPVPCPeeringSpec{ VPCPeeringSpec: v1beta1.VPCPeeringSpec{ - DataCentreID: "375e4d1c-2f77-4d02-a6f2-1af617ff2ab2", - PeerSubnets: []string{"172.31.0.0/16", "192.168.0.0/16"}, + PeerSubnets: []string{"172.31.0.0/16", "192.168.0.0/16"}, }, PeerProjectID: "pid-132313", PeerVPCNetworkName: "vpc-123123123", diff --git a/controllers/clusters/cadence_controller.go b/controllers/clusters/cadence_controller.go index 35026415c..88d13c240 100644 --- a/controllers/clusters/cadence_controller.go +++ b/controllers/clusters/cadence_controller.go @@ -26,6 +26,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -36,7 +37,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" + clusterresourcesv1beta1 "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/apis/clusters/v1beta1" + "github.com/instaclustr/operator/controllers/clusterresources" "github.com/instaclustr/operator/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" "github.com/instaclustr/operator/pkg/models" @@ -362,6 +365,202 @@ func (r *CadenceReconciler) HandleUpdateCluster( return models.ExitReconcile } +func (r *CadenceReconciler) handleClusterResourcesEvents( + newObj *v1beta1.Cadence, + oldObjSpec *v1beta1.CadenceSpec, +) { + r.HandleResourceEvent(newObj, models.ClusterNetworkFirewallRuleref, oldObjSpec.ClusterResources.ClusterNetworkFirewallRules, newObj.Spec.ClusterResources.ClusterNetworkFirewallRules) + r.HandleResourceEvent(newObj, models.AWSVPCPeeringRef, oldObjSpec.ClusterResources.AWSVPCPeerings, newObj.Spec.ClusterResources.AWSVPCPeerings) + r.HandleResourceEvent(newObj, models.AWSSecurityGroupFirewallRuleRef, oldObjSpec.ClusterResources.AWSSecurityGroupFirewallRules, newObj.Spec.ClusterResources.AWSSecurityGroupFirewallRules) + r.HandleResourceEvent(newObj, models.ExclusionWindowRef, oldObjSpec.ClusterResources.ExclusionWindows, newObj.Spec.ClusterResources.ExclusionWindows) + r.HandleResourceEvent(newObj, models.GCPVPCPeeringRef, oldObjSpec.ClusterResources.GCPVPCPeerings, newObj.Spec.ClusterResources.GCPVPCPeerings) + r.HandleResourceEvent(newObj, models.AzureVNetPeeringRef, oldObjSpec.ClusterResources.AzureVNetPeerings, newObj.Spec.ClusterResources.AzureVNetPeerings) +} + +func (r *CadenceReconciler) HandleResourceEvent( + cadence *v1beta1.Cadence, + resourceKind string, + oldRefs, newRefs []*v1beta1.ClusterResourceRef, +) { + ctx := context.TODO() + l := log.FromContext(ctx) + + for _, ref := range newRefs { + exist := isClusterResourceRefExists(ref, oldRefs) + if exist { + continue + } + + err := r.handleCreateResource(ctx, l, resourceKind, ref, cadence) + if err != nil { + l.Error(err, "Cannot create clusterresource", "resource kind", resourceKind, "namespace and name", ref) + r.EventRecorder.Eventf(cadence, models.Warning, models.CreatingEvent, + "Cannot create resource. Reason: %v", err) + } + oldRefs = append(oldRefs, ref) + } + for _, oldRef := range oldRefs { + exist := isClusterResourceRefExists(oldRef, newRefs) + if exist { + continue + } + + err := r.handleDeleteResource(ctx, l, resourceKind, oldRef) + if err != nil { + l.Error(err, "Cannot delete clusterresource", "resource kind", resourceKind, "namespace and name", oldRef) + r.EventRecorder.Eventf(cadence, models.Warning, models.DeletingEvent, + "Cannot delete resource. Reason: %v", err) + } + } +} + +func (r *CadenceReconciler) handleCreateResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, + cadence *v1beta1.Cadence, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Provided resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + if isCDC { + resource.AttachToCluster(cadence.Status.DataCentres[0].ID) + } else { + resource.AttachToCluster(cadence.Status.ID) + } + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Cadence clusterresource was patched", + "Reference", ref, + "Resource Kind", kind, + "Event", models.CreatingEvent, + ) + + return nil +} + +func (r *CadenceReconciler) handleDeleteResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + default: + l.Info("Provided reference to resource that is not support deletion", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot get a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + resource.DetachFromCluster() + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Cadence clusterresource was updated", + "Reference", ref, + "Resource Kind", kind, + "Event", models.DeletingEvent, + ) + + return nil +} + +func (r *CadenceReconciler) DetachClusterresourcesFromCluster(ctx context.Context, l logr.Logger, cadence *v1beta1.Cadence) { + r.DetachClusterresources(ctx, l, cadence, cadence.Spec.ClusterResources.ClusterNetworkFirewallRules, models.ClusterNetworkFirewallRuleref) + r.DetachClusterresources(ctx, l, cadence, cadence.Spec.ClusterResources.AWSVPCPeerings, models.AWSVPCPeeringRef) + r.DetachClusterresources(ctx, l, cadence, cadence.Spec.ClusterResources.AWSSecurityGroupFirewallRules, models.AWSSecurityGroupFirewallRuleRef) + r.DetachClusterresources(ctx, l, cadence, cadence.Spec.ClusterResources.ExclusionWindows, models.ExclusionWindowRef) + r.DetachClusterresources(ctx, l, cadence, cadence.Spec.ClusterResources.GCPVPCPeerings, models.GCPVPCPeeringRef) + r.DetachClusterresources(ctx, l, cadence, cadence.Spec.ClusterResources.AzureVNetPeerings, models.AzureVNetPeeringRef) +} + +func (r *CadenceReconciler) DetachClusterresources(ctx context.Context, l logr.Logger, cadence *v1beta1.Cadence, refs []*v1beta1.ClusterResourceRef, kind string) { + for _, ref := range refs { + err := r.handleDeleteResource(ctx, l, kind, ref) + if err != nil { + l.Error(err, "Cannot detach clusterresource", "resource kind", kind, "namespace and name", ref) + r.EventRecorder.Eventf(cadence, models.Warning, models.DeletingEvent, + "Cannot detach resource. Reason: %v", err) + } + } +} + func (r *CadenceReconciler) handleExternalChanges(cadence, iCadence *v1beta1.Cadence, l logr.Logger) reconcile.Result { if !cadence.Spec.AreDCsEqual(iCadence.Spec.DataCentres) { l.Info(msgExternalChanges, @@ -419,6 +618,8 @@ func (r *CadenceReconciler) HandleDeleteCluster( return models.ReconcileRequeue } + r.DetachClusterresourcesFromCluster(ctx, logger, cadence) + if !errors.Is(err, instaclustr.NotFound) { logger.Info("Sending cluster deletion to the Instaclustr API", "cluster name", cadence.Spec.Name, @@ -1187,6 +1388,8 @@ func (r *CadenceReconciler) SetupWithManager(mgr ctrl.Manager) error { return true } + r.handleClusterResourcesEvents(newObj, &oldObj.Spec) + if oldObj.Generation == newObj.Generation { return false } diff --git a/controllers/clusters/cassandra_controller.go b/controllers/clusters/cassandra_controller.go index 77a1b0b2e..e57fbf875 100644 --- a/controllers/clusters/cassandra_controller.go +++ b/controllers/clusters/cassandra_controller.go @@ -38,6 +38,7 @@ import ( clusterresourcesv1beta1 "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/apis/clusters/v1beta1" + "github.com/instaclustr/operator/controllers/clusterresources" "github.com/instaclustr/operator/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" "github.com/instaclustr/operator/pkg/models" @@ -415,6 +416,215 @@ func (r *CassandraReconciler) handleUpdateCluster( return models.ExitReconcile, nil } +func (r *CassandraReconciler) handleClusterResourcesEvents( + newObj *v1beta1.Cassandra, + oldObjSpec *v1beta1.CassandraSpec, +) { + r.HandleResourceEvent(newObj, models.ClusterbackupRef, oldObjSpec.ClusterResources.ClusterBackups, newObj.Spec.ClusterResources.ClusterBackups) + r.HandleResourceEvent(newObj, models.ClusterNetworkFirewallRuleref, oldObjSpec.ClusterResources.ClusterNetworkFirewallRules, newObj.Spec.ClusterResources.ClusterNetworkFirewallRules) + r.HandleResourceEvent(newObj, models.AWSVPCPeeringRef, oldObjSpec.ClusterResources.AWSVPCPeerings, newObj.Spec.ClusterResources.AWSVPCPeerings) + r.HandleResourceEvent(newObj, models.AWSSecurityGroupFirewallRuleRef, oldObjSpec.ClusterResources.AWSSecurityGroupFirewallRules, newObj.Spec.ClusterResources.AWSSecurityGroupFirewallRules) + r.HandleResourceEvent(newObj, models.ExclusionWindowRef, oldObjSpec.ClusterResources.ExclusionWindows, newObj.Spec.ClusterResources.ExclusionWindows) + r.HandleResourceEvent(newObj, models.GCPVPCPeeringRef, oldObjSpec.ClusterResources.GCPVPCPeerings, newObj.Spec.ClusterResources.GCPVPCPeerings) + r.HandleResourceEvent(newObj, models.AzureVNetPeeringRef, oldObjSpec.ClusterResources.AzureVNetPeerings, newObj.Spec.ClusterResources.AzureVNetPeerings) +} + +func (r *CassandraReconciler) HandleResourceEvent( + redis *v1beta1.Cassandra, + resourceKind string, + oldRefs, newRefs []*v1beta1.ClusterResourceRef, +) { + ctx := context.TODO() + l := log.FromContext(ctx) + + for _, ref := range newRefs { + exist := isClusterResourceRefExists(ref, oldRefs) + if exist { + continue + } + + err := r.handleCreateResource(ctx, l, resourceKind, ref, redis) + if err != nil { + l.Error(err, "Cannot create clusterresource", "resource kind", resourceKind, "namespace and name", ref) + r.EventRecorder.Eventf(redis, models.Warning, models.CreatingEvent, + "Cannot create resource. Reason: %v", err) + } + oldRefs = append(oldRefs, ref) + } + for _, oldRef := range oldRefs { + exist := isClusterResourceRefExists(oldRef, newRefs) + if exist { + continue + } + + err := r.handleDeleteResource(ctx, l, resourceKind, oldRef) + if err != nil { + l.Error(err, "Cannot delete clusterresource", "resource kind", resourceKind, "namespace and name", oldRef) + r.EventRecorder.Eventf(redis, models.Warning, models.DeletingEvent, + "Cannot delete resource. Reason: %v", err) + } + } +} + +func (r *CassandraReconciler) handleCreateResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, + cassandra *v1beta1.Cassandra, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + cdcID := cassandra.Status.DataCentres[0].ID + + switch kind { + case models.ClusterbackupRef: + resource = &clusterresourcesv1beta1.ClusterBackup{} + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind) + return nil + } + + if isCDC && ref.DataCentreName != "" { + for _, cdc := range cassandra.Status.DataCentres { + if cdc.Name == ref.DataCentreName { + cdcID = cdc.ID + break + } + } + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Provided resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + if isCDC { + resource.AttachToCluster(cdcID) + } else { + resource.AttachToCluster(cassandra.Status.ID) + } + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Cassandra clusterresource was patched", + "Reference", ref, + "Resource Kind", kind, + "Event", models.CreatingEvent, + ) + + return nil +} + +func (r *CassandraReconciler) handleDeleteResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + default: + l.Info("Provided reference to resource that is not support deletion", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot get a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + resource.DetachFromCluster() + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Cassandra clusterresource was updated", + "Reference", ref, + "Resource Kind", kind, + "Event", models.DeletingEvent, + ) + + return nil +} + +func (r *CassandraReconciler) DetachClusterresourcesFromCluster(ctx context.Context, l logr.Logger, cassandra *v1beta1.Cassandra) { + r.DetachClusterresources(ctx, l, cassandra, cassandra.Spec.ClusterResources.ClusterNetworkFirewallRules, models.ClusterNetworkFirewallRuleref) + r.DetachClusterresources(ctx, l, cassandra, cassandra.Spec.ClusterResources.AWSVPCPeerings, models.AWSVPCPeeringRef) + r.DetachClusterresources(ctx, l, cassandra, cassandra.Spec.ClusterResources.AWSSecurityGroupFirewallRules, models.AWSSecurityGroupFirewallRuleRef) + r.DetachClusterresources(ctx, l, cassandra, cassandra.Spec.ClusterResources.ExclusionWindows, models.ExclusionWindowRef) + r.DetachClusterresources(ctx, l, cassandra, cassandra.Spec.ClusterResources.GCPVPCPeerings, models.GCPVPCPeeringRef) + r.DetachClusterresources(ctx, l, cassandra, cassandra.Spec.ClusterResources.AzureVNetPeerings, models.AzureVNetPeeringRef) +} + +func (r *CassandraReconciler) DetachClusterresources(ctx context.Context, l logr.Logger, cassandra *v1beta1.Cassandra, refs []*v1beta1.ClusterResourceRef, kind string) { + for _, ref := range refs { + err := r.handleDeleteResource(ctx, l, kind, ref) + if err != nil { + l.Error(err, "Cannot detach clusterresource", "resource kind", kind, "namespace and name", ref) + r.EventRecorder.Eventf(cassandra, models.Warning, models.DeletingEvent, + "Cannot detach resource. Reason: %v", err) + } + } +} + func (r *CassandraReconciler) handleExternalChanges(cassandra, iCassandra *v1beta1.Cassandra, l logr.Logger) (reconcile.Result, error) { if !cassandra.Spec.IsEqual(iCassandra.Spec) { l.Info(msgSpecStillNoMatch, @@ -564,6 +774,8 @@ func (r *CassandraReconciler) handleDeleteCluster( } } + r.DetachClusterresourcesFromCluster(ctx, l, cassandra) + controllerutil.RemoveFinalizer(cassandra, models.DeletionFinalizer) cassandra.Annotations[models.ResourceStateAnnotation] = models.DeletedEvent err = r.Patch(ctx, cassandra, patch) @@ -1275,6 +1487,7 @@ func (r *CassandraReconciler) SetupWithManager(mgr ctrl.Manager) error { oldObj := event.ObjectOld.(*v1beta1.Cassandra) r.handleUserEvent(newObj, oldObj.Spec.UserRefs) + r.handleClusterResourcesEvents(newObj, &oldObj.Spec) newObj.Annotations[models.ResourceStateAnnotation] = models.UpdatingEvent return true diff --git a/controllers/clusters/helpers.go b/controllers/clusters/helpers.go index f8fd9c7ea..179fa58f4 100644 --- a/controllers/clusters/helpers.go +++ b/controllers/clusters/helpers.go @@ -170,7 +170,7 @@ func createSpecDifferenceMessage(k8sSpec, iSpec any) (string, error) { return msg + specDifference, nil } -func isClusterResourceRefExists(ref *v1beta1.NamespacedName, compareRefs []*v1beta1.NamespacedName) bool { +func isClusterResourceRefExists(ref *v1beta1.ClusterResourceRef, compareRefs []*v1beta1.ClusterResourceRef) bool { var exist bool for _, compareRef := range compareRefs { if *ref == *compareRef { diff --git a/controllers/clusters/kafka_controller.go b/controllers/clusters/kafka_controller.go index 585016c5a..66bc79328 100644 --- a/controllers/clusters/kafka_controller.go +++ b/controllers/clusters/kafka_controller.go @@ -34,8 +34,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" + clusterresourcesv1beta1 "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/apis/clusters/v1beta1" kafkamanagementv1beta1 "github.com/instaclustr/operator/apis/kafkamanagement/v1beta1" + "github.com/instaclustr/operator/controllers/clusterresources" "github.com/instaclustr/operator/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" "github.com/instaclustr/operator/pkg/models" @@ -314,6 +316,204 @@ func (r *KafkaReconciler) handleUpdateCluster( return models.ExitReconcile } +func (r *KafkaReconciler) handleClusterResourcesEvents( + newObj *v1beta1.Kafka, + oldObjSpec *v1beta1.KafkaSpec, +) { + r.HandleResourceEvent(newObj, models.ClusterNetworkFirewallRuleref, oldObjSpec.ClusterResources.ClusterNetworkFirewallRules, newObj.Spec.ClusterResources.ClusterNetworkFirewallRules) + r.HandleResourceEvent(newObj, models.AWSVPCPeeringRef, oldObjSpec.ClusterResources.AWSVPCPeerings, newObj.Spec.ClusterResources.AWSVPCPeerings) + r.HandleResourceEvent(newObj, models.AWSSecurityGroupFirewallRuleRef, oldObjSpec.ClusterResources.AWSSecurityGroupFirewallRules, newObj.Spec.ClusterResources.AWSSecurityGroupFirewallRules) + r.HandleResourceEvent(newObj, models.ExclusionWindowRef, oldObjSpec.ClusterResources.ExclusionWindows, newObj.Spec.ClusterResources.ExclusionWindows) + r.HandleResourceEvent(newObj, models.GCPVPCPeeringRef, oldObjSpec.ClusterResources.GCPVPCPeerings, newObj.Spec.ClusterResources.GCPVPCPeerings) + r.HandleResourceEvent(newObj, models.AzureVNetPeeringRef, oldObjSpec.ClusterResources.AzureVNetPeerings, newObj.Spec.ClusterResources.AzureVNetPeerings) +} + +func (r *KafkaReconciler) HandleResourceEvent( + kafka *v1beta1.Kafka, + resourceKind string, + oldRefs, newRefs []*v1beta1.ClusterResourceRef, +) { + ctx := context.TODO() + l := log.FromContext(ctx) + + for _, ref := range newRefs { + exist := isClusterResourceRefExists(ref, oldRefs) + if exist { + continue + } + + err := r.handleCreateResource(ctx, l, resourceKind, ref, kafka) + if err != nil { + l.Error(err, "Cannot create clusterresource", "resource kind", resourceKind, "namespace and name", ref) + r.EventRecorder.Eventf(kafka, models.Warning, models.CreatingEvent, + "Cannot create resource. Reason: %v", err) + } + oldRefs = append(oldRefs, ref) + } + for _, oldRef := range oldRefs { + exist := isClusterResourceRefExists(oldRef, newRefs) + if exist { + continue + } + + err := r.handleDeleteResource(ctx, l, resourceKind, oldRef) + if err != nil { + l.Error(err, "Cannot delete clusterresource", "resource kind", resourceKind, "namespace and name", oldRef) + r.EventRecorder.Eventf(kafka, models.Warning, models.DeletingEvent, + "Cannot delete resource. Reason: %v", err) + } + } +} + +func (r *KafkaReconciler) handleCreateResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, + kafka *v1beta1.Kafka, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + + switch kind { + case models.ClusterbackupRef: + resource = &clusterresourcesv1beta1.ClusterBackup{} + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Provided resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + if isCDC { + resource.AttachToCluster(kafka.Status.DataCentres[0].ID) + } else { + resource.AttachToCluster(kafka.Status.ID) + } + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Kafka clusterresource was patched", + "Reference", ref, + "Resource Kind", kind, + "Event", models.CreatingEvent, + ) + + return nil +} + +func (r *KafkaReconciler) handleDeleteResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + default: + l.Info("Provided reference to resource that is not support deletion", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot get a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + resource.DetachFromCluster() + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Kafka clusterresource was updated", + "Reference", ref, + "Resource Kind", kind, + "Event", models.DeletingEvent, + ) + + return nil +} + +func (r *KafkaReconciler) DetachClusterresourcesFromCluster(ctx context.Context, l logr.Logger, kafka *v1beta1.Kafka) { + r.DetachClusterresources(ctx, l, kafka, kafka.Spec.ClusterResources.ClusterNetworkFirewallRules, models.ClusterNetworkFirewallRuleref) + r.DetachClusterresources(ctx, l, kafka, kafka.Spec.ClusterResources.AWSVPCPeerings, models.AWSVPCPeeringRef) + r.DetachClusterresources(ctx, l, kafka, kafka.Spec.ClusterResources.AWSSecurityGroupFirewallRules, models.AWSSecurityGroupFirewallRuleRef) + r.DetachClusterresources(ctx, l, kafka, kafka.Spec.ClusterResources.ExclusionWindows, models.ExclusionWindowRef) + r.DetachClusterresources(ctx, l, kafka, kafka.Spec.ClusterResources.GCPVPCPeerings, models.GCPVPCPeeringRef) + r.DetachClusterresources(ctx, l, kafka, kafka.Spec.ClusterResources.AzureVNetPeerings, models.AzureVNetPeeringRef) +} + +func (r *KafkaReconciler) DetachClusterresources(ctx context.Context, l logr.Logger, kafka *v1beta1.Kafka, refs []*v1beta1.ClusterResourceRef, kind string) { + for _, ref := range refs { + err := r.handleDeleteResource(ctx, l, kind, ref) + if err != nil { + l.Error(err, "Cannot detach clusterresource", "resource kind", kind, "namespace and name", ref) + r.EventRecorder.Eventf(kafka, models.Warning, models.DeletingEvent, + "Cannot detach resource. Reason: %v", err) + } + } +} + func (r *KafkaReconciler) handleCreateUser( ctx context.Context, kafka *v1beta1.Kafka, @@ -641,6 +841,8 @@ func (r *KafkaReconciler) handleDeleteCluster(ctx context.Context, kafka *v1beta } } + r.DetachClusterresourcesFromCluster(ctx, l, kafka) + r.Scheduler.RemoveJob(kafka.GetJobID(scheduler.StatusChecker)) r.Scheduler.RemoveJob(kafka.GetJobID(scheduler.UserCreator)) controllerutil.RemoveFinalizer(kafka, models.DeletionFinalizer) @@ -950,6 +1152,7 @@ func (r *KafkaReconciler) SetupWithManager(mgr ctrl.Manager) error { oldObj := event.ObjectOld.(*v1beta1.Kafka) r.handleUserEvent(newObj, oldObj.Spec.UserRefs) + r.handleClusterResourcesEvents(newObj, &oldObj.Spec) newObj.Annotations[models.ResourceStateAnnotation] = models.UpdatingEvent return true diff --git a/controllers/clusters/kafkaconnect_controller.go b/controllers/clusters/kafkaconnect_controller.go index a70a441bd..3d055ffaa 100644 --- a/controllers/clusters/kafkaconnect_controller.go +++ b/controllers/clusters/kafkaconnect_controller.go @@ -23,6 +23,7 @@ import ( "github.com/go-logr/logr" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -33,7 +34,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" + clusterresourcesv1beta1 "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/apis/clusters/v1beta1" + "github.com/instaclustr/operator/controllers/clusterresources" "github.com/instaclustr/operator/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" "github.com/instaclustr/operator/pkg/models" @@ -290,6 +293,204 @@ func (r *KafkaConnectReconciler) handleUpdateCluster(ctx context.Context, kc *v1 return models.ExitReconcile } +func (r *KafkaConnectReconciler) handleClusterResourcesEvents( + newObj *v1beta1.KafkaConnect, + oldObjSpec *v1beta1.KafkaConnectSpec, +) { + r.HandleResourceEvent(newObj, models.ClusterNetworkFirewallRuleref, oldObjSpec.ClusterResources.ClusterNetworkFirewallRules, newObj.Spec.ClusterResources.ClusterNetworkFirewallRules) + r.HandleResourceEvent(newObj, models.AWSVPCPeeringRef, oldObjSpec.ClusterResources.AWSVPCPeerings, newObj.Spec.ClusterResources.AWSVPCPeerings) + r.HandleResourceEvent(newObj, models.AWSSecurityGroupFirewallRuleRef, oldObjSpec.ClusterResources.AWSSecurityGroupFirewallRules, newObj.Spec.ClusterResources.AWSSecurityGroupFirewallRules) + r.HandleResourceEvent(newObj, models.ExclusionWindowRef, oldObjSpec.ClusterResources.ExclusionWindows, newObj.Spec.ClusterResources.ExclusionWindows) + r.HandleResourceEvent(newObj, models.GCPVPCPeeringRef, oldObjSpec.ClusterResources.GCPVPCPeerings, newObj.Spec.ClusterResources.GCPVPCPeerings) + r.HandleResourceEvent(newObj, models.AzureVNetPeeringRef, oldObjSpec.ClusterResources.AzureVNetPeerings, newObj.Spec.ClusterResources.AzureVNetPeerings) +} + +func (r *KafkaConnectReconciler) HandleResourceEvent( + kafkaConnect *v1beta1.KafkaConnect, + resourceKind string, + oldRefs, newRefs []*v1beta1.ClusterResourceRef, +) { + ctx := context.TODO() + l := log.FromContext(ctx) + + for _, ref := range newRefs { + exist := isClusterResourceRefExists(ref, oldRefs) + if exist { + continue + } + + err := r.handleCreateResource(ctx, l, resourceKind, ref, kafkaConnect) + if err != nil { + l.Error(err, "Cannot create clusterresource", "resource kind", resourceKind, "namespace and name", ref) + r.EventRecorder.Eventf(kafkaConnect, models.Warning, models.CreatingEvent, + "Cannot create resource. Reason: %v", err) + } + oldRefs = append(oldRefs, ref) + } + for _, oldRef := range oldRefs { + exist := isClusterResourceRefExists(oldRef, newRefs) + if exist { + continue + } + + err := r.handleDeleteResource(ctx, l, resourceKind, oldRef) + if err != nil { + l.Error(err, "Cannot delete clusterresource", "resource kind", resourceKind, "namespace and name", oldRef) + r.EventRecorder.Eventf(kafkaConnect, models.Warning, models.DeletingEvent, + "Cannot delete resource. Reason: %v", err) + } + } +} + +func (r *KafkaConnectReconciler) handleCreateResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, + kafkaConnect *v1beta1.KafkaConnect, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + + switch kind { + case models.ClusterbackupRef: + resource = &clusterresourcesv1beta1.ClusterBackup{} + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Provided resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + if isCDC { + resource.AttachToCluster(kafkaConnect.Status.DataCentres[0].ID) + } else { + resource.AttachToCluster(kafkaConnect.Status.ID) + } + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("KafkaConnect clusterresource was patched", + "Reference", ref, + "Resource Kind", kind, + "Event", models.CreatingEvent, + ) + + return nil +} + +func (r *KafkaConnectReconciler) handleDeleteResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + default: + l.Info("Provided reference to resource that is not support deletion", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot get a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + resource.DetachFromCluster() + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("KafkaConnect clusterresource was updated", + "Reference", ref, + "Resource Kind", kind, + "Event", models.DeletingEvent, + ) + + return nil +} + +func (r *KafkaConnectReconciler) DetachClusterresourcesFromCluster(ctx context.Context, l logr.Logger, kafkaConnect *v1beta1.KafkaConnect) { + r.DetachClusterresources(ctx, l, kafkaConnect, kafkaConnect.Spec.ClusterResources.ClusterNetworkFirewallRules, models.ClusterNetworkFirewallRuleref) + r.DetachClusterresources(ctx, l, kafkaConnect, kafkaConnect.Spec.ClusterResources.AWSVPCPeerings, models.AWSVPCPeeringRef) + r.DetachClusterresources(ctx, l, kafkaConnect, kafkaConnect.Spec.ClusterResources.AWSSecurityGroupFirewallRules, models.AWSSecurityGroupFirewallRuleRef) + r.DetachClusterresources(ctx, l, kafkaConnect, kafkaConnect.Spec.ClusterResources.ExclusionWindows, models.ExclusionWindowRef) + r.DetachClusterresources(ctx, l, kafkaConnect, kafkaConnect.Spec.ClusterResources.GCPVPCPeerings, models.GCPVPCPeeringRef) + r.DetachClusterresources(ctx, l, kafkaConnect, kafkaConnect.Spec.ClusterResources.AzureVNetPeerings, models.AzureVNetPeeringRef) +} + +func (r *KafkaConnectReconciler) DetachClusterresources(ctx context.Context, l logr.Logger, kafkaConnect *v1beta1.KafkaConnect, refs []*v1beta1.ClusterResourceRef, kind string) { + for _, ref := range refs { + err := r.handleDeleteResource(ctx, l, kind, ref) + if err != nil { + l.Error(err, "Cannot detach clusterresource", "resource kind", kind, "namespace and name", ref) + r.EventRecorder.Eventf(kafkaConnect, models.Warning, models.DeletingEvent, + "Cannot detach resource. Reason: %v", err) + } + } +} + func (r *KafkaConnectReconciler) handleExternalChanges(k, ik *v1beta1.KafkaConnect, l logr.Logger) reconcile.Result { if !k.Spec.IsEqual(ik.Spec) { l.Info(msgSpecStillNoMatch, @@ -345,6 +546,8 @@ func (r *KafkaConnectReconciler) handleDeleteCluster(ctx context.Context, kc *v1 patch := kc.NewPatch() + r.DetachClusterresourcesFromCluster(ctx, l, kc) + if !errors.Is(err, instaclustr.NotFound) { l.Info("Sending cluster deletion to the Instaclustr API", "cluster name", kc.Spec.Name, @@ -597,6 +800,10 @@ func (r *KafkaConnectReconciler) SetupWithManager(mgr ctrl.Manager) error { } newObj := event.ObjectNew.(*v1beta1.KafkaConnect) + oldObj := event.ObjectOld.(*v1beta1.KafkaConnect) + + r.handleClusterResourcesEvents(newObj, &oldObj.Spec) + if newObj.Generation == event.ObjectOld.GetGeneration() { return false } diff --git a/controllers/clusters/opensearch_controller.go b/controllers/clusters/opensearch_controller.go index d3ea525d9..a0fbcb6cf 100644 --- a/controllers/clusters/opensearch_controller.go +++ b/controllers/clusters/opensearch_controller.go @@ -37,6 +37,7 @@ import ( clusterresourcesv1beta1 "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/apis/clusters/v1beta1" + "github.com/instaclustr/operator/controllers/clusterresources" "github.com/instaclustr/operator/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" "github.com/instaclustr/operator/pkg/models" @@ -391,6 +392,205 @@ func (r *OpenSearchReconciler) HandleUpdateCluster( return models.ExitReconcile } +func (r *OpenSearchReconciler) handleClusterResourcesEvents( + newObj *v1beta1.OpenSearch, + oldObjSpec *v1beta1.OpenSearchSpec, +) { + r.HandleResourceEvent(newObj, models.ClusterbackupRef, oldObjSpec.ClusterResources.ClusterBackups, newObj.Spec.ClusterResources.ClusterBackups) + r.HandleResourceEvent(newObj, models.ClusterNetworkFirewallRuleref, oldObjSpec.ClusterResources.ClusterNetworkFirewallRules, newObj.Spec.ClusterResources.ClusterNetworkFirewallRules) + r.HandleResourceEvent(newObj, models.AWSVPCPeeringRef, oldObjSpec.ClusterResources.AWSVPCPeerings, newObj.Spec.ClusterResources.AWSVPCPeerings) + r.HandleResourceEvent(newObj, models.AWSSecurityGroupFirewallRuleRef, oldObjSpec.ClusterResources.AWSSecurityGroupFirewallRules, newObj.Spec.ClusterResources.AWSSecurityGroupFirewallRules) + r.HandleResourceEvent(newObj, models.ExclusionWindowRef, oldObjSpec.ClusterResources.ExclusionWindows, newObj.Spec.ClusterResources.ExclusionWindows) + r.HandleResourceEvent(newObj, models.GCPVPCPeeringRef, oldObjSpec.ClusterResources.GCPVPCPeerings, newObj.Spec.ClusterResources.GCPVPCPeerings) + r.HandleResourceEvent(newObj, models.AzureVNetPeeringRef, oldObjSpec.ClusterResources.AzureVNetPeerings, newObj.Spec.ClusterResources.AzureVNetPeerings) +} + +func (r *OpenSearchReconciler) HandleResourceEvent( + openSearch *v1beta1.OpenSearch, + resourceKind string, + oldRefs, newRefs []*v1beta1.ClusterResourceRef, +) { + ctx := context.TODO() + l := log.FromContext(ctx) + + for _, ref := range newRefs { + exist := isClusterResourceRefExists(ref, oldRefs) + if exist { + continue + } + + err := r.handleCreateResource(ctx, l, resourceKind, ref, openSearch) + if err != nil { + l.Error(err, "Cannot create clusterresource", "resource kind", resourceKind, "namespace and name", ref) + r.EventRecorder.Eventf(openSearch, models.Warning, models.CreatingEvent, + "Cannot create resource. Reason: %v", err) + } + oldRefs = append(oldRefs, ref) + } + for _, oldRef := range oldRefs { + exist := isClusterResourceRefExists(oldRef, newRefs) + if exist { + continue + } + + err := r.handleDeleteResource(ctx, l, resourceKind, oldRef) + if err != nil { + l.Error(err, "Cannot delete clusterresource", "resource kind", resourceKind, "namespace and name", oldRef) + r.EventRecorder.Eventf(openSearch, models.Warning, models.DeletingEvent, + "Cannot delete resource. Reason: %v", err) + } + } +} + +func (r *OpenSearchReconciler) handleCreateResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, + openSearch *v1beta1.OpenSearch, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + + switch kind { + case models.ClusterbackupRef: + resource = &clusterresourcesv1beta1.ClusterBackup{} + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Provided resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + if isCDC { + resource.AttachToCluster(openSearch.Status.DataCentres[0].ID) + } else { + resource.AttachToCluster(openSearch.Status.ID) + } + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Opensearch clusterresource was patched", + "Reference", ref, + "Resource Kind", kind, + "Event", models.CreatingEvent, + ) + + return nil +} + +func (r *OpenSearchReconciler) handleDeleteResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + default: + l.Info("Provided reference to resource that is not support deletion", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot get a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + resource.DetachFromCluster() + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Opensearch clusterresource was updated", + "Reference", ref, + "Resource Kind", kind, + "Event", models.DeletingEvent, + ) + + return nil +} + +func (r *OpenSearchReconciler) DetachClusterresourcesFromCluster(ctx context.Context, l logr.Logger, openSearch *v1beta1.OpenSearch) { + r.DetachClusterresources(ctx, l, openSearch, openSearch.Spec.ClusterResources.ClusterNetworkFirewallRules, models.ClusterNetworkFirewallRuleref) + r.DetachClusterresources(ctx, l, openSearch, openSearch.Spec.ClusterResources.AWSVPCPeerings, models.AWSVPCPeeringRef) + r.DetachClusterresources(ctx, l, openSearch, openSearch.Spec.ClusterResources.AWSSecurityGroupFirewallRules, models.AWSSecurityGroupFirewallRuleRef) + r.DetachClusterresources(ctx, l, openSearch, openSearch.Spec.ClusterResources.ExclusionWindows, models.ExclusionWindowRef) + r.DetachClusterresources(ctx, l, openSearch, openSearch.Spec.ClusterResources.GCPVPCPeerings, models.GCPVPCPeeringRef) + r.DetachClusterresources(ctx, l, openSearch, openSearch.Spec.ClusterResources.AzureVNetPeerings, models.AzureVNetPeeringRef) +} + +func (r *OpenSearchReconciler) DetachClusterresources(ctx context.Context, l logr.Logger, openSearch *v1beta1.OpenSearch, refs []*v1beta1.ClusterResourceRef, kind string) { + for _, ref := range refs { + err := r.handleDeleteResource(ctx, l, kind, ref) + if err != nil { + l.Error(err, "Cannot detach clusterresource", "resource kind", kind, "namespace and name", ref) + r.EventRecorder.Eventf(openSearch, models.Warning, models.DeletingEvent, + "Cannot detach resource. Reason: %v", err) + } + } +} + func (r *OpenSearchReconciler) handleExternalChanges(o, iO *v1beta1.OpenSearch, l logr.Logger) reconcile.Result { if !o.Spec.IsEqual(iO.Spec) { l.Info(msgSpecStillNoMatch, @@ -524,6 +724,8 @@ func (r *OpenSearchReconciler) HandleDeleteCluster( } } + r.DetachClusterresourcesFromCluster(ctx, logger, o) + controllerutil.RemoveFinalizer(o, models.DeletionFinalizer) err = r.Patch(ctx, o, patch) if err != nil { @@ -1190,6 +1392,7 @@ func (r *OpenSearchReconciler) SetupWithManager(mgr ctrl.Manager) error { oldObj := event.ObjectOld.(*v1beta1.OpenSearch) r.handleUserEvent(newObj, oldObj.Spec.UserRefs) + r.handleClusterResourcesEvents(newObj, &oldObj.Spec) newObj.Annotations[models.ResourceStateAnnotation] = models.UpdatingEvent return true diff --git a/controllers/clusters/postgresql_controller.go b/controllers/clusters/postgresql_controller.go index 1c716fab3..db3e1e81a 100644 --- a/controllers/clusters/postgresql_controller.go +++ b/controllers/clusters/postgresql_controller.go @@ -509,7 +509,7 @@ func (r *PostgreSQLReconciler) handleClusterResourcesEvents( func (r *PostgreSQLReconciler) HandleResourceEvent( pg *v1beta1.PostgreSQL, resourceKind string, - oldRefs, newRefs []*v1beta1.NamespacedName, + oldRefs, newRefs []*v1beta1.ClusterResourceRef, ) { ctx := context.TODO() l := log.FromContext(ctx) @@ -547,7 +547,7 @@ func (r *PostgreSQLReconciler) handleCreateResource( ctx context.Context, l logr.Logger, kind string, - ref *v1beta1.NamespacedName, + ref *v1beta1.ClusterResourceRef, pg *v1beta1.PostgreSQL, ) error { req := types.NamespacedName{ @@ -557,6 +557,7 @@ func (r *PostgreSQLReconciler) handleCreateResource( var resource clusterresources.Object var isCDC bool + cdcID := pg.Status.DataCentres[0].ID switch kind { case models.ClusterbackupRef: @@ -581,6 +582,15 @@ func (r *PostgreSQLReconciler) handleCreateResource( return nil } + if isCDC && ref.DataCentreName != "" { + for _, cdc := range pg.Status.DataCentres { + if cdc.Name == ref.DataCentreName { + cdcID = cdc.ID + break + } + } + } + err := r.Get(ctx, req, resource) if err != nil { if k8serrors.IsNotFound(err) { @@ -594,7 +604,7 @@ func (r *PostgreSQLReconciler) handleCreateResource( patch := resource.NewPatch() if isCDC { - resource.AttachToCluster(pg.Status.DataCentres[0].ID) + resource.AttachToCluster(cdcID) } else { resource.AttachToCluster(pg.Status.ID) } @@ -617,7 +627,7 @@ func (r *PostgreSQLReconciler) handleDeleteResource( ctx context.Context, l logr.Logger, kind string, - ref *v1beta1.NamespacedName, + ref *v1beta1.ClusterResourceRef, ) error { req := types.NamespacedName{ Namespace: ref.Namespace, @@ -672,6 +682,26 @@ func (r *PostgreSQLReconciler) handleDeleteResource( return nil } +func (r *PostgreSQLReconciler) DetachClusterresourcesFromCluster(ctx context.Context, l logr.Logger, pg *v1beta1.PostgreSQL) { + r.DetachClusterresources(ctx, l, pg, pg.Spec.ClusterResources.ClusterNetworkFirewallRules, models.ClusterNetworkFirewallRuleref) + r.DetachClusterresources(ctx, l, pg, pg.Spec.ClusterResources.AWSVPCPeerings, models.AWSVPCPeeringRef) + r.DetachClusterresources(ctx, l, pg, pg.Spec.ClusterResources.AWSSecurityGroupFirewallRules, models.AWSSecurityGroupFirewallRuleRef) + r.DetachClusterresources(ctx, l, pg, pg.Spec.ClusterResources.ExclusionWindows, models.ExclusionWindowRef) + r.DetachClusterresources(ctx, l, pg, pg.Spec.ClusterResources.GCPVPCPeerings, models.GCPVPCPeeringRef) + r.DetachClusterresources(ctx, l, pg, pg.Spec.ClusterResources.AzureVNetPeerings, models.AzureVNetPeeringRef) +} + +func (r *PostgreSQLReconciler) DetachClusterresources(ctx context.Context, l logr.Logger, pg *v1beta1.PostgreSQL, refs []*v1beta1.ClusterResourceRef, kind string) { + for _, ref := range refs { + err := r.handleDeleteResource(ctx, l, kind, ref) + if err != nil { + l.Error(err, "Cannot detach clusterresource", "resource kind", kind, "namespace and name", ref) + r.EventRecorder.Eventf(pg, models.Warning, models.DeletingEvent, + "Cannot detach resource. Reason: %v", err) + } + } +} + func (r *PostgreSQLReconciler) createUser( ctx context.Context, l logr.Logger, @@ -1077,6 +1107,8 @@ func (r *PostgreSQLReconciler) handleDeleteCluster( } } + r.DetachClusterresourcesFromCluster(ctx, logger, pg) + controllerutil.RemoveFinalizer(pg, models.DeletionFinalizer) pg.Annotations[models.ResourceStateAnnotation] = models.DeletedEvent err = r.patchClusterMetadata(ctx, pg, logger) diff --git a/controllers/clusters/redis_controller.go b/controllers/clusters/redis_controller.go index 820390a5d..a9cda2614 100644 --- a/controllers/clusters/redis_controller.go +++ b/controllers/clusters/redis_controller.go @@ -37,6 +37,7 @@ import ( clusterresourcesv1beta1 "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/apis/clusters/v1beta1" + "github.com/instaclustr/operator/controllers/clusterresources" "github.com/instaclustr/operator/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" "github.com/instaclustr/operator/pkg/models" @@ -473,6 +474,215 @@ func (r *RedisReconciler) handleCreateUsers( return nil } +func (r *RedisReconciler) handleClusterResourcesEvents( + newObj *v1beta1.Redis, + oldObjSpec *v1beta1.RedisSpec, +) { + r.HandleResourceEvent(newObj, models.ClusterbackupRef, oldObjSpec.ClusterResources.ClusterBackups, newObj.Spec.ClusterResources.ClusterBackups) + r.HandleResourceEvent(newObj, models.ClusterNetworkFirewallRuleref, oldObjSpec.ClusterResources.ClusterNetworkFirewallRules, newObj.Spec.ClusterResources.ClusterNetworkFirewallRules) + r.HandleResourceEvent(newObj, models.AWSVPCPeeringRef, oldObjSpec.ClusterResources.AWSVPCPeerings, newObj.Spec.ClusterResources.AWSVPCPeerings) + r.HandleResourceEvent(newObj, models.AWSSecurityGroupFirewallRuleRef, oldObjSpec.ClusterResources.AWSSecurityGroupFirewallRules, newObj.Spec.ClusterResources.AWSSecurityGroupFirewallRules) + r.HandleResourceEvent(newObj, models.ExclusionWindowRef, oldObjSpec.ClusterResources.ExclusionWindows, newObj.Spec.ClusterResources.ExclusionWindows) + r.HandleResourceEvent(newObj, models.GCPVPCPeeringRef, oldObjSpec.ClusterResources.GCPVPCPeerings, newObj.Spec.ClusterResources.GCPVPCPeerings) + r.HandleResourceEvent(newObj, models.AzureVNetPeeringRef, oldObjSpec.ClusterResources.AzureVNetPeerings, newObj.Spec.ClusterResources.AzureVNetPeerings) +} + +func (r *RedisReconciler) HandleResourceEvent( + redis *v1beta1.Redis, + resourceKind string, + oldRefs, newRefs []*v1beta1.ClusterResourceRef, +) { + ctx := context.TODO() + l := log.FromContext(ctx) + + for _, ref := range newRefs { + exist := isClusterResourceRefExists(ref, oldRefs) + if exist { + continue + } + + err := r.handleCreateResource(ctx, l, resourceKind, ref, redis) + if err != nil { + l.Error(err, "Cannot create clusterresource", "resource kind", resourceKind, "namespace and name", ref) + r.EventRecorder.Eventf(redis, models.Warning, models.CreatingEvent, + "Cannot create resource. Reason: %v", err) + } + oldRefs = append(oldRefs, ref) + } + for _, oldRef := range oldRefs { + exist := isClusterResourceRefExists(oldRef, newRefs) + if exist { + continue + } + + err := r.handleDeleteResource(ctx, l, resourceKind, oldRef) + if err != nil { + l.Error(err, "Cannot delete clusterresource", "resource kind", resourceKind, "namespace and name", oldRef) + r.EventRecorder.Eventf(redis, models.Warning, models.DeletingEvent, + "Cannot delete resource. Reason: %v", err) + } + } +} + +func (r *RedisReconciler) handleCreateResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, + redis *v1beta1.Redis, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + cdcID := redis.Status.DataCentres[0].ID + + switch kind { + case models.ClusterbackupRef: + resource = &clusterresourcesv1beta1.ClusterBackup{} + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind) + return nil + } + + if isCDC && ref.DataCentreName != "" { + for _, cdc := range redis.Status.DataCentres { + if cdc.Name == ref.DataCentreName { + cdcID = cdc.ID + break + } + } + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Provided resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + if isCDC { + resource.AttachToCluster(cdcID) + } else { + resource.AttachToCluster(redis.Status.ID) + } + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Redis clusterresource was patched", + "Reference", ref, + "Resource Kind", kind, + "Event", models.CreatingEvent, + ) + + return nil +} + +func (r *RedisReconciler) handleDeleteResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + default: + l.Info("Provided reference to resource that is not support deletion", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot get a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + resource.DetachFromCluster() + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Redis clusterresource was updated", + "Reference", ref, + "Resource Kind", kind, + "Event", models.DeletingEvent, + ) + + return nil +} + +func (r *RedisReconciler) DetachClusterresourcesFromCluster(ctx context.Context, l logr.Logger, redis *v1beta1.Redis) { + r.DetachClusterresources(ctx, l, redis, redis.Spec.ClusterResources.ClusterNetworkFirewallRules, models.ClusterNetworkFirewallRuleref) + r.DetachClusterresources(ctx, l, redis, redis.Spec.ClusterResources.AWSVPCPeerings, models.AWSVPCPeeringRef) + r.DetachClusterresources(ctx, l, redis, redis.Spec.ClusterResources.AWSSecurityGroupFirewallRules, models.AWSSecurityGroupFirewallRuleRef) + r.DetachClusterresources(ctx, l, redis, redis.Spec.ClusterResources.ExclusionWindows, models.ExclusionWindowRef) + r.DetachClusterresources(ctx, l, redis, redis.Spec.ClusterResources.GCPVPCPeerings, models.GCPVPCPeeringRef) + r.DetachClusterresources(ctx, l, redis, redis.Spec.ClusterResources.AzureVNetPeerings, models.AzureVNetPeeringRef) +} + +func (r *RedisReconciler) DetachClusterresources(ctx context.Context, l logr.Logger, redis *v1beta1.Redis, refs []*v1beta1.ClusterResourceRef, kind string) { + for _, ref := range refs { + err := r.handleDeleteResource(ctx, l, kind, ref) + if err != nil { + l.Error(err, "Cannot detach clusterresource", "resource kind", kind, "namespace and name", ref) + r.EventRecorder.Eventf(redis, models.Warning, models.DeletingEvent, + "Cannot detach resource. Reason: %v", err) + } + } +} + func (r *RedisReconciler) handleExternalChanges(redis, iRedis *v1beta1.Redis, l logr.Logger) reconcile.Result { if !redis.Spec.IsEqual(iRedis.Spec) { l.Info(msgSpecStillNoMatch, @@ -626,6 +836,8 @@ func (r *RedisReconciler) handleDeleteCluster( } } + r.DetachClusterresourcesFromCluster(ctx, logger, redis) + patch := redis.NewPatch() controllerutil.RemoveFinalizer(redis, models.DeletionFinalizer) redis.Annotations[models.ResourceStateAnnotation] = models.DeletedEvent @@ -1225,6 +1437,7 @@ func (r *RedisReconciler) SetupWithManager(mgr ctrl.Manager) error { oldObj := event.ObjectOld.(*v1beta1.Redis) r.handleUserEvent(newObj, oldObj.Spec.UserRefs) + r.handleClusterResourcesEvents(newObj, &oldObj.Spec) newObj.Annotations[models.ResourceStateAnnotation] = models.UpdatingEvent return true diff --git a/controllers/clusters/zookeeper_controller.go b/controllers/clusters/zookeeper_controller.go index d2252ce7b..68a4644f1 100644 --- a/controllers/clusters/zookeeper_controller.go +++ b/controllers/clusters/zookeeper_controller.go @@ -23,6 +23,7 @@ import ( "github.com/go-logr/logr" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" @@ -33,7 +34,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" + clusterresourcesv1beta1 "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/apis/clusters/v1beta1" + "github.com/instaclustr/operator/controllers/clusterresources" "github.com/instaclustr/operator/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" "github.com/instaclustr/operator/pkg/models" @@ -264,6 +267,202 @@ func (r *ZookeeperReconciler) handleUpdateCluster( return models.ExitReconcile } +func (r *ZookeeperReconciler) handleClusterResourcesEvents( + newObj *v1beta1.Zookeeper, + oldObjSpec *v1beta1.ZookeeperSpec, +) { + r.HandleResourceEvent(newObj, models.ClusterNetworkFirewallRuleref, oldObjSpec.ClusterResources.ClusterNetworkFirewallRules, newObj.Spec.ClusterResources.ClusterNetworkFirewallRules) + r.HandleResourceEvent(newObj, models.AWSVPCPeeringRef, oldObjSpec.ClusterResources.AWSVPCPeerings, newObj.Spec.ClusterResources.AWSVPCPeerings) + r.HandleResourceEvent(newObj, models.AWSSecurityGroupFirewallRuleRef, oldObjSpec.ClusterResources.AWSSecurityGroupFirewallRules, newObj.Spec.ClusterResources.AWSSecurityGroupFirewallRules) + r.HandleResourceEvent(newObj, models.ExclusionWindowRef, oldObjSpec.ClusterResources.ExclusionWindows, newObj.Spec.ClusterResources.ExclusionWindows) + r.HandleResourceEvent(newObj, models.GCPVPCPeeringRef, oldObjSpec.ClusterResources.GCPVPCPeerings, newObj.Spec.ClusterResources.GCPVPCPeerings) + r.HandleResourceEvent(newObj, models.AzureVNetPeeringRef, oldObjSpec.ClusterResources.AzureVNetPeerings, newObj.Spec.ClusterResources.AzureVNetPeerings) +} + +func (r *ZookeeperReconciler) HandleResourceEvent( + zookeeper *v1beta1.Zookeeper, + resourceKind string, + oldRefs, newRefs []*v1beta1.ClusterResourceRef, +) { + ctx := context.TODO() + l := log.FromContext(ctx) + + for _, ref := range newRefs { + exist := isClusterResourceRefExists(ref, oldRefs) + if exist { + continue + } + + err := r.handleCreateResource(ctx, l, resourceKind, ref, zookeeper) + if err != nil { + l.Error(err, "Cannot create clusterresource", "resource kind", resourceKind, "namespace and name", ref) + r.EventRecorder.Eventf(zookeeper, models.Warning, models.CreatingEvent, + "Cannot create resource. Reason: %v", err) + } + oldRefs = append(oldRefs, ref) + } + for _, oldRef := range oldRefs { + exist := isClusterResourceRefExists(oldRef, newRefs) + if exist { + continue + } + + err := r.handleDeleteResource(ctx, l, resourceKind, oldRef) + if err != nil { + l.Error(err, "Cannot delete clusterresource", "resource kind", resourceKind, "namespace and name", oldRef) + r.EventRecorder.Eventf(zookeeper, models.Warning, models.DeletingEvent, + "Cannot delete resource. Reason: %v", err) + } + } +} + +func (r *ZookeeperReconciler) handleCreateResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, + zookeeper *v1beta1.Zookeeper, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Provided resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + if isCDC { + resource.AttachToCluster(zookeeper.Status.DataCentres[0].ID) + } else { + resource.AttachToCluster(zookeeper.Status.ID) + } + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info("Cassandra clusterresource was patched", + "Reference", ref, + "Resource Kind", kind, + "Event", models.CreatingEvent, + ) + + return nil +} + +func (r *ZookeeperReconciler) handleDeleteResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.ClusterResourceRef, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + + switch kind { + case models.ClusterNetworkFirewallRuleref: + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case models.AWSVPCPeeringRef: + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + case models.AWSSecurityGroupFirewallRuleRef: + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case models.ExclusionWindowRef: + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case models.GCPVPCPeeringRef: + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + case models.AzureVNetPeeringRef: + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + default: + l.Info("Provided reference to resource that is not support deletion", "kind", kind) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot get a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "request", req) + return err + } + + patch := resource.NewPatch() + + resource.DetachFromCluster() + + err = r.Status().Patch(ctx, resource, patch) + if err != nil { + return err + } + + l.Info(" clusterresource was updated", + "Reference", ref, + "Resource Kind", kind, + "Event", models.DeletingEvent, + ) + + return nil +} + +func (r *ZookeeperReconciler) DetachClusterresourcesFromCluster(ctx context.Context, l logr.Logger, zookeeper *v1beta1.Zookeeper) { + r.DetachClusterresources(ctx, l, zookeeper, zookeeper.Spec.ClusterResources.ClusterNetworkFirewallRules, models.ClusterNetworkFirewallRuleref) + r.DetachClusterresources(ctx, l, zookeeper, zookeeper.Spec.ClusterResources.AWSVPCPeerings, models.AWSVPCPeeringRef) + r.DetachClusterresources(ctx, l, zookeeper, zookeeper.Spec.ClusterResources.AWSSecurityGroupFirewallRules, models.AWSSecurityGroupFirewallRuleRef) + r.DetachClusterresources(ctx, l, zookeeper, zookeeper.Spec.ClusterResources.ExclusionWindows, models.ExclusionWindowRef) + r.DetachClusterresources(ctx, l, zookeeper, zookeeper.Spec.ClusterResources.GCPVPCPeerings, models.GCPVPCPeeringRef) + r.DetachClusterresources(ctx, l, zookeeper, zookeeper.Spec.ClusterResources.AzureVNetPeerings, models.AzureVNetPeeringRef) +} + +func (r *ZookeeperReconciler) DetachClusterresources(ctx context.Context, l logr.Logger, zookeeper *v1beta1.Zookeeper, refs []*v1beta1.ClusterResourceRef, kind string) { + for _, ref := range refs { + err := r.handleDeleteResource(ctx, l, kind, ref) + if err != nil { + l.Error(err, "Cannot detach clusterresource", "resource kind", kind, "namespace and name", ref) + r.EventRecorder.Eventf(zookeeper, models.Warning, models.DeletingEvent, + "Cannot detach resource. Reason: %v", err) + } + } +} + func (r *ZookeeperReconciler) handleExternalChanges(zook *v1beta1.Zookeeper, l logr.Logger) reconcile.Result { iData, err := r.API.GetZookeeper(zook.Status.ID) if err != nil { @@ -336,6 +535,8 @@ func (r *ZookeeperReconciler) handleDeleteCluster( patch := zook.NewPatch() + r.DetachClusterresourcesFromCluster(ctx, l, zook) + if !errors.Is(err, instaclustr.NotFound) { l.Info("Sending cluster deletion to the Instaclustr API", "cluster name", zook.Spec.Name, @@ -565,6 +766,7 @@ func (r *ZookeeperReconciler) SetupWithManager(mgr ctrl.Manager) error { }, UpdateFunc: func(event event.UpdateEvent) bool { newObj := event.ObjectNew.(*v1beta1.Zookeeper) + oldObj := event.ObjectOld.(*v1beta1.Zookeeper) if event.ObjectNew.GetAnnotations()[models.ResourceStateAnnotation] == models.DeletedEvent { return false @@ -578,6 +780,8 @@ func (r *ZookeeperReconciler) SetupWithManager(mgr ctrl.Manager) error { return true } + r.handleClusterResourcesEvents(newObj, &oldObj.Spec) + if newObj.Generation == event.ObjectOld.GetGeneration() { return false }