diff --git a/Makefile b/Makefile index 49f81dad1..e6465e64e 100644 --- a/Makefile +++ b/Makefile @@ -117,6 +117,13 @@ PHONY: stop-server-stub stop-server-stub: ## Stop an Instaclustr server-stub from your host. docker stop instaclustr-server-stub +.PHONY dev-build: +dev-build: docker-build kind-load deploy ## builds docker-image, loads it to kind cluster and deploys operator + +.PHONY: kind-load +kind-load: ## loads given image to kind cluster + kind load docker-image ${IMG} + ##@ Deployment ifndef ignore-not-found diff --git a/apis/clusterresources/v1beta1/awsvpcpeering_types.go b/apis/clusterresources/v1beta1/awsvpcpeering_types.go index bc9083fb9..df5b55b81 100644 --- a/apis/clusterresources/v1beta1/awsvpcpeering_types.go +++ b/apis/clusterresources/v1beta1/awsvpcpeering_types.go @@ -91,9 +91,7 @@ func (aws *AWSVPCPeeringSpec) newImmutableFields() *immutableAWSVPCPeeringFields peerAWSAccountID: aws.PeerAWSAccountID, peerRegion: aws.PeerRegion, }, - immutablePeeringFields{ - DataCentreID: aws.DataCentreID, - }, + immutablePeeringFields{}, } } @@ -125,11 +123,6 @@ func (aws *AWSVPCPeeringSpec) Validate(availableRegions []string) error { return fmt.Errorf("VPC ID must begin with 'vpc-' and fit pattern: %s. %v", models.PeerVPCIDRegExp, err) } - dataCentreIDMatched, err := regexp.Match(models.UUIDStringRegExp, []byte(aws.DataCentreID)) - if !dataCentreIDMatched || err != nil { - return fmt.Errorf("data centre ID is a UUID formated string. It must fit the pattern: %s. %v", models.UUIDStringRegExp, err) - } - if !validation.Contains(aws.PeerRegion, availableRegions) { return fmt.Errorf("AWS Region to peer: %s is unavailable, available regions: %v", aws.PeerRegion, availableRegions) diff --git a/apis/clusterresources/v1beta1/awsvpcpeering_webhook.go b/apis/clusterresources/v1beta1/awsvpcpeering_webhook.go index edda260c7..af23491a3 100644 --- a/apis/clusterresources/v1beta1/awsvpcpeering_webhook.go +++ b/apis/clusterresources/v1beta1/awsvpcpeering_webhook.go @@ -67,10 +67,6 @@ func (r *AWSVPCPeering) ValidateCreate() error { return fmt.Errorf("peer AWS Account Region 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/azurevnetpeering_types.go b/apis/clusterresources/v1beta1/azurevnetpeering_types.go index 4de680fb0..e9139597e 100644 --- a/apis/clusterresources/v1beta1/azurevnetpeering_types.go +++ b/apis/clusterresources/v1beta1/azurevnetpeering_types.go @@ -76,14 +76,6 @@ func init() { } func (azure *AzureVNetPeeringSpec) Validate() error { - dataCentreIDMatched, err := regexp.Match(models.UUIDStringRegExp, []byte(azure.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 azure.PeerSubnets { peerSubnetMatched, err := regexp.Match(models.PeerSubnetsRegExp, []byte(subnet)) if err != nil { diff --git a/apis/clusterresources/v1beta1/azurevnetpeering_webhook.go b/apis/clusterresources/v1beta1/azurevnetpeering_webhook.go index 39ab9c7e3..7be21f7a1 100644 --- a/apis/clusterresources/v1beta1/azurevnetpeering_webhook.go +++ b/apis/clusterresources/v1beta1/azurevnetpeering_webhook.go @@ -71,10 +71,6 @@ func (r *AzureVNetPeering) ValidateCreate() error { return fmt.Errorf("peer Subscription 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/clusterbackup_types.go b/apis/clusterresources/v1beta1/clusterbackup_types.go index be942299d..c2b30ea3c 100644 --- a/apis/clusterresources/v1beta1/clusterbackup_types.go +++ b/apis/clusterresources/v1beta1/clusterbackup_types.go @@ -27,7 +27,7 @@ import ( // ClusterBackupSpec defines the desired state of ClusterBackup type ClusterBackupSpec struct { - ClusterID string `json:"clusterId"` + ClusterID string `json:"clusterId,omitempty"` ClusterKind string `json:"clusterKind"` } diff --git a/apis/clusterresources/v1beta1/clusterbackup_webhook.go b/apis/clusterresources/v1beta1/clusterbackup_webhook.go index e969452d0..efca2b4a1 100644 --- a/apis/clusterresources/v1beta1/clusterbackup_webhook.go +++ b/apis/clusterresources/v1beta1/clusterbackup_webhook.go @@ -17,12 +17,11 @@ limitations under the License. package v1beta1 import ( + "github.com/instaclustr/operator/pkg/models" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/webhook" - - "github.com/instaclustr/operator/pkg/models" ) // log is for logging in this package. diff --git a/apis/clusterresources/v1beta1/exclusionwindow_types.go b/apis/clusterresources/v1beta1/exclusionwindow_types.go index c4b9c3b9f..91a3613b1 100644 --- a/apis/clusterresources/v1beta1/exclusionwindow_types.go +++ b/apis/clusterresources/v1beta1/exclusionwindow_types.go @@ -23,7 +23,7 @@ import ( // ExclusionWindowSpec defines the desired state of ExclusionWindow type ExclusionWindowSpec struct { - ClusterID string `json:"clusterId"` + ClusterID string `json:"clusterId,omitempty"` DayOfWeek string `json:"dayOfWeek"` //+kubebuilder:validation:Minimum:=0 //+kubebuilder:validation:Maximum:=23 diff --git a/apis/clusterresources/v1beta1/maintenanceevents_types.go b/apis/clusterresources/v1beta1/maintenanceevents_types.go index 2c59bd541..ea830688d 100644 --- a/apis/clusterresources/v1beta1/maintenanceevents_types.go +++ b/apis/clusterresources/v1beta1/maintenanceevents_types.go @@ -23,7 +23,6 @@ import ( // MaintenanceEventsSpec defines the desired state of MaintenanceEvents type MaintenanceEventsSpec struct { - ClusterID string `json:"clusterId"` MaintenanceEventsReschedules []*MaintenanceEventReschedule `json:"maintenanceEventsReschedule"` } diff --git a/apis/clusterresources/v1beta1/structs.go b/apis/clusterresources/v1beta1/structs.go index 0670d6da4..3f5b03620 100644 --- a/apis/clusterresources/v1beta1/structs.go +++ b/apis/clusterresources/v1beta1/structs.go @@ -21,7 +21,7 @@ import ( ) type VPCPeeringSpec struct { - DataCentreID string `json:"cdcId"` + DataCentreID string `json:"cdcId,omitempty"` PeerSubnets []string `json:"peerSubnets"` } @@ -39,7 +39,7 @@ type PatchRequest struct { } type FirewallRuleSpec struct { - ClusterID string `json:"clusterId"` + ClusterID string `json:"clusterId,omitempty"` Type string `json:"type"` } diff --git a/apis/clusters/v1beta1/postgresql_types.go b/apis/clusters/v1beta1/postgresql_types.go index 91924f5d7..e712d4df1 100644 --- a/apis/clusters/v1beta1/postgresql_types.go +++ b/apis/clusters/v1beta1/postgresql_types.go @@ -79,10 +79,21 @@ type PgSpec struct { ClusterConfigurations map[string]string `json:"clusterConfigurations,omitempty"` SynchronousModeStrict bool `json:"synchronousModeStrict,omitempty"` UserRefs []*UserReference `json:"userRefs,omitempty"` + ClusterResourceRefs *ClusterResourceRefs `json:"clusterResourceRefs,omitempty"` //+kubebuilder:validate:MaxItems:=1 ResizeSettings []*ResizeSettings `json:"resizeSettings,omitempty"` } +type ClusterResourceRefs struct { + ClusterBackups []*UserReference `json:"clusterBackups,omitempty"` + ClusterNetworkFirewallRules []*UserReference `json:"clusterNetworkFirewallRules,omitempty"` + AWSVPCPeerings []*UserReference `json:"awsVPCPeerings,omitempty"` + AWSSecurityGroupFirewallRules []*UserReference `json:"awsSecurityGroupFirewallRules,omitempty"` + ExclusionWindows []*UserReference `json:"exclusionWindows,omitempty"` + GCPVPCPeerings []*UserReference `json:"gcpVPCPeerings,omitempty"` + AzureVNetPeerings []*UserReference `json:"azureVNetPeerings,omitempty"` +} + // PgStatus defines the observed state of PostgreSQL type PgStatus struct { ClusterStatus `json:",inline"` @@ -154,12 +165,11 @@ func (pg *PostgreSQL) NewBackupSpec(startTimestamp int) *clusterresourcesv1beta1 ObjectMeta: ctrl.ObjectMeta{ Name: models.PgBackupPrefix + pg.Status.ID + "-" + strconv.Itoa(startTimestamp), Namespace: pg.Namespace, - Annotations: map[string]string{models.StartTimestampAnnotation: strconv.Itoa(startTimestamp)}, + Annotations: map[string]string{models.StartTimestampAnnotation: strconv.Itoa(startTimestamp), models.ClusterIDAnnotation: pg.Status.ID}, Labels: map[string]string{models.ClusterIDLabel: pg.Status.ID}, Finalizers: []string{models.DeletionFinalizer}, }, Spec: clusterresourcesv1beta1.ClusterBackupSpec{ - ClusterID: pg.Status.ID, ClusterKind: models.PgClusterKind, }, } @@ -195,7 +205,6 @@ func (pgs *PgSpec) ToInstAPI() *models.PGCluster { PostgreSQLVersion: pgs.Version, DataCentres: pgs.DCsToInstAPI(), SynchronousModeStrict: pgs.SynchronousModeStrict, - Description: pgs.Description, PrivateNetworkCluster: pgs.PrivateNetworkCluster, SLATier: pgs.SLATier, TwoFactorDelete: pgs.TwoFactorDeletesToInstAPI(), @@ -555,7 +564,6 @@ func (pgs *PgSpec) FromInstAPI(iPg *models.PGCluster) PgSpec { Version: iPg.PostgreSQLVersion, PCICompliance: iPg.PCIComplianceMode, PrivateNetworkCluster: iPg.PrivateNetworkCluster, - Description: iPg.Description, SLATier: iPg.SLATier, TwoFactorDelete: pgs.Cluster.TwoFactorDeleteFromInstAPI(iPg.TwoFactorDelete), }, diff --git a/apis/clusters/v1beta1/zz_generated.deepcopy.go b/apis/clusters/v1beta1/zz_generated.deepcopy.go index eb4beebbd..cd6b64ea1 100644 --- a/apis/clusters/v1beta1/zz_generated.deepcopy.go +++ b/apis/clusters/v1beta1/zz_generated.deepcopy.go @@ -586,6 +586,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 *ClusterResourceRefs) DeepCopyInto(out *ClusterResourceRefs) { + *out = *in + if in.ClusterBackups != nil { + in, out := &in.ClusterBackups, &out.ClusterBackups + *out = make([]*UserReference, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(UserReference) + **out = **in + } + } + } + if in.ClusterNetworkFirewallRules != nil { + in, out := &in.ClusterNetworkFirewallRules, &out.ClusterNetworkFirewallRules + *out = make([]*UserReference, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(UserReference) + **out = **in + } + } + } + if in.AWSVPCPeerings != nil { + in, out := &in.AWSVPCPeerings, &out.AWSVPCPeerings + *out = make([]*UserReference, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(UserReference) + **out = **in + } + } + } + if in.AWSSecurityGroupFirewallRules != nil { + in, out := &in.AWSSecurityGroupFirewallRules, &out.AWSSecurityGroupFirewallRules + *out = make([]*UserReference, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(UserReference) + **out = **in + } + } + } + if in.ExclusionWindows != nil { + in, out := &in.ExclusionWindows, &out.ExclusionWindows + *out = make([]*UserReference, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(UserReference) + **out = **in + } + } + } + if in.GCPVPCPeerings != nil { + in, out := &in.GCPVPCPeerings, &out.GCPVPCPeerings + *out = make([]*UserReference, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(UserReference) + **out = **in + } + } + } + if in.AzureVNetPeerings != nil { + in, out := &in.AzureVNetPeerings, &out.AzureVNetPeerings + *out = make([]*UserReference, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(UserReference) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResourceRefs. +func (in *ClusterResourceRefs) DeepCopy() *ClusterResourceRefs { + if in == nil { + return nil + } + out := new(ClusterResourceRefs) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { *out = *in @@ -1761,6 +1853,11 @@ func (in *PgSpec) DeepCopyInto(out *PgSpec) { } } } + if in.ClusterResourceRefs != nil { + in, out := &in.ClusterResourceRefs, &out.ClusterResourceRefs + *out = new(ClusterResourceRefs) + (*in).DeepCopyInto(*out) + } if in.ResizeSettings != nil { in, out := &in.ResizeSettings, &out.ResizeSettings *out = make([]*ResizeSettings, len(*in)) diff --git a/config/crd/bases/clusterresources.instaclustr.com_awssecuritygroupfirewallrules.yaml b/config/crd/bases/clusterresources.instaclustr.com_awssecuritygroupfirewallrules.yaml index 66567ac8c..f6ff28a84 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_awssecuritygroupfirewallrules.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_awssecuritygroupfirewallrules.yaml @@ -44,7 +44,6 @@ spec: type: type: string required: - - clusterId - securityGroupId - type type: object diff --git a/config/crd/bases/clusterresources.instaclustr.com_awsvpcpeerings.yaml b/config/crd/bases/clusterresources.instaclustr.com_awsvpcpeerings.yaml index 4bde626a6..00d62ba65 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_awsvpcpeerings.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_awsvpcpeerings.yaml @@ -48,7 +48,6 @@ spec: peerVpcId: type: string required: - - cdcId - peerAwsAccountId - peerSubnets - peerVpcId diff --git a/config/crd/bases/clusterresources.instaclustr.com_azurevnetpeerings.yaml b/config/crd/bases/clusterresources.instaclustr.com_azurevnetpeerings.yaml index b29ca2c93..524c141d8 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_azurevnetpeerings.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_azurevnetpeerings.yaml @@ -50,7 +50,6 @@ spec: peerVirtualNetworkName: type: string required: - - cdcId - peerResourceGroup - peerSubnets - peerSubscriptionId diff --git a/config/crd/bases/clusterresources.instaclustr.com_clusterbackups.yaml b/config/crd/bases/clusterresources.instaclustr.com_clusterbackups.yaml index 8e9b8bc17..cff890e8b 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_clusterbackups.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_clusterbackups.yaml @@ -40,7 +40,6 @@ spec: clusterKind: type: string required: - - clusterId - clusterKind type: object status: diff --git a/config/crd/bases/clusterresources.instaclustr.com_clusternetworkfirewallrules.yaml b/config/crd/bases/clusterresources.instaclustr.com_clusternetworkfirewallrules.yaml index 714e426fa..75f5573ae 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_clusternetworkfirewallrules.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_clusternetworkfirewallrules.yaml @@ -44,7 +44,6 @@ spec: type: type: string required: - - clusterId - network - type type: object diff --git a/config/crd/bases/clusterresources.instaclustr.com_exclusionwindows.yaml b/config/crd/bases/clusterresources.instaclustr.com_exclusionwindows.yaml index 81d6e8ab1..808d3d562 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_exclusionwindows.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_exclusionwindows.yaml @@ -49,7 +49,6 @@ spec: minimum: 0 type: integer required: - - clusterId - dayOfWeek - durationInHours - startHour diff --git a/config/crd/bases/clusterresources.instaclustr.com_gcpvpcpeerings.yaml b/config/crd/bases/clusterresources.instaclustr.com_gcpvpcpeerings.yaml index 1fbad4150..7dbcca238 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_gcpvpcpeerings.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_gcpvpcpeerings.yaml @@ -46,7 +46,6 @@ spec: peerVpcNetworkName: type: string required: - - cdcId - peerProjectId - peerSubnets - peerVpcNetworkName diff --git a/config/crd/bases/clusterresources.instaclustr.com_maintenanceevents.yaml b/config/crd/bases/clusterresources.instaclustr.com_maintenanceevents.yaml index e7a5ce71c..f1eac4d71 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_maintenanceevents.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_maintenanceevents.yaml @@ -35,8 +35,6 @@ spec: spec: description: MaintenanceEventsSpec defines the desired state of MaintenanceEvents properties: - clusterId: - type: string maintenanceEventsReschedule: items: properties: @@ -50,7 +48,6 @@ spec: type: object type: array required: - - clusterId - maintenanceEventsReschedule type: object status: diff --git a/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml b/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml index 86fbce8df..582bac744 100644 --- a/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml +++ b/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml @@ -52,6 +52,93 @@ spec: additionalProperties: type: string type: object + clusterResourceRefs: + properties: + awsSecurityGroupFirewallRules: + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + awsVPCPeerings: + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + azureVNetPeerings: + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterBackups: + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + clusterNetworkFirewallRules: + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + exclusionWindows: + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + gcpVPCPeerings: + items: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + type: object dataCentres: items: properties: diff --git a/config/samples/clusterresources_v1beta1_awssecuritygroupfirewallrule.yaml b/config/samples/clusterresources_v1beta1_awssecuritygroupfirewallrule.yaml index d90f56e8c..81645a5ad 100644 --- a/config/samples/clusterresources_v1beta1_awssecuritygroupfirewallrule.yaml +++ b/config/samples/clusterresources_v1beta1_awssecuritygroupfirewallrule.yaml @@ -9,6 +9,6 @@ metadata: app.kubernetes.io/created-by: operator name: awssecuritygroupfirewallrule-sample spec: - securityGroupId: sg-0d681e2d0fe0f0a39 - clusterId: ef924204-3139-43e9-8e03-c29278e6eccd + securityGroupId: sg-0ab978e9e4f443cc8 +# clusterId: ef924204-3139-43e9-8e03-c29278e6eccd type: POSTGRESQL diff --git a/config/samples/clusterresources_v1beta1_awsvpcpeering.yaml b/config/samples/clusterresources_v1beta1_awsvpcpeering.yaml index b0112bdd7..6dfe90004 100644 --- a/config/samples/clusterresources_v1beta1_awsvpcpeering.yaml +++ b/config/samples/clusterresources_v1beta1_awsvpcpeering.yaml @@ -15,4 +15,4 @@ spec: - "192.168.0.0/16" peerVpcId: "vpc-87241ae1" peerRegion: "US_EAST_1" - cdcId: "85b26d7e-f8ff-4ce6-9fd1-b0d25e6659a9" \ No newline at end of file +# cdcId: "249e86af-7afa-4674-8fab-10250661c5b4" \ No newline at end of file diff --git a/config/samples/clusterresources_v1beta1_azurevnetpeering.yaml b/config/samples/clusterresources_v1beta1_azurevnetpeering.yaml index 69330698e..5e06b3d25 100644 --- a/config/samples/clusterresources_v1beta1_azurevnetpeering.yaml +++ b/config/samples/clusterresources_v1beta1_azurevnetpeering.yaml @@ -1,11 +1,11 @@ apiVersion: clusterresources.instaclustr.com/v1beta1 kind: AzureVNetPeering metadata: - name: azurevnetpeering-sample + name: azurevnetpeering-sample-trough spec: - cdcId: f8581465-098c-4576-9e52-ea8308a27d8a +# cdcId: f8581465-098c-4576-9e52-ea8308a27d8a peerResourceGroup: rnd peerSubnets: - 10.224.0.0/16 peerSubscriptionId: 1a2f3ab8-6815-49c5-a47e-b1a354b51240 - peerVirtualNetworkName: aks-vnet-17973335 + peerVirtualNetworkName: aks-vnet-17973335222666 diff --git a/config/samples/clusterresources_v1beta1_clusterbackup.yaml b/config/samples/clusterresources_v1beta1_clusterbackup.yaml index 5c1afa170..9ee13b783 100644 --- a/config/samples/clusterresources_v1beta1_clusterbackup.yaml +++ b/config/samples/clusterresources_v1beta1_clusterbackup.yaml @@ -3,5 +3,5 @@ kind: ClusterBackup metadata: name: clusterbackup-sample spec: - clusterId: 2ae611cf-ac91-4325-941c-a35c043f9c34 +# clusterId: 2ae611cf-ac91-4325-941c-a35c043f9c34 clusterKind: PostgreSQL \ No newline at end of file diff --git a/config/samples/clusterresources_v1beta1_clusternetworkfirewallrule.yaml b/config/samples/clusterresources_v1beta1_clusternetworkfirewallrule.yaml index b475ddf1f..d5412190c 100644 --- a/config/samples/clusterresources_v1beta1_clusternetworkfirewallrule.yaml +++ b/config/samples/clusterresources_v1beta1_clusternetworkfirewallrule.yaml @@ -9,6 +9,6 @@ metadata: app.kubernetes.io/created-by: operator name: clusternetworkfirewallrule-sample spec: - network: 62.212.64.19/32 - clusterId: 944cfe6b-441f-4c5a-865b-42fd40c7d816 - type: KAFKA + network: 54.198.214.167/32 +# clusterId: c47c6a1c-9e2b-4a5c-aa5e-7013bceecd09 + type: POSTGRESQL diff --git a/config/samples/clusterresources_v1beta1_exclusionwindow.yaml b/config/samples/clusterresources_v1beta1_exclusionwindow.yaml index 56abb7e9a..022f6821f 100644 --- a/config/samples/clusterresources_v1beta1_exclusionwindow.yaml +++ b/config/samples/clusterresources_v1beta1_exclusionwindow.yaml @@ -3,7 +3,7 @@ kind: ExclusionWindow metadata: name: exclusionwindow-sample spec: - clusterId: "4b453851-9002-475a-a603-f8fb1e0ae7df" +# clusterId: "d72b0c01-d263-40c7-8d3d-adb837602647" dayOfWeek: "MONDAY" startHour: 10 durationInHours: 40 diff --git a/config/samples/clusterresources_v1beta1_gcpvpcpeering.yaml b/config/samples/clusterresources_v1beta1_gcpvpcpeering.yaml index 7b6cd3318..1c420836a 100644 --- a/config/samples/clusterresources_v1beta1_gcpvpcpeering.yaml +++ b/config/samples/clusterresources_v1beta1_gcpvpcpeering.yaml @@ -1,11 +1,11 @@ apiVersion: clusterresources.instaclustr.com/v1beta1 kind: GCPVPCPeering metadata: - name: gcpvpcpeering-sample + name: gcpvpcpeering-sample-two spec: cdcId: ab974700-1ba9-4fcd-8399-3dc83fc2a3c3 peerProjectId: netapp-hcl-seclab peerSubnets: - - 192.168.0.0/16 - - 172.16.0.0/16 - peerVpcNetworkName: hcl-seclab-client-vpc1 + - 192.169.0.0/16 + - 172.17.0.0/16 + peerVpcNetworkName: hcl-seclab-client-vpc57x diff --git a/config/samples/clusterresources_v1beta1_maintenanceevents.yaml b/config/samples/clusterresources_v1beta1_maintenanceevents.yaml index 307734950..a24c60d04 100644 --- a/config/samples/clusterresources_v1beta1_maintenanceevents.yaml +++ b/config/samples/clusterresources_v1beta1_maintenanceevents.yaml @@ -3,9 +3,6 @@ kind: MaintenanceEvents metadata: name: maintenanceevents-sample spec: - clusterId: "9cf09a53-a09e-450a-ba7d-e98b3c724911" maintenanceEventsReschedule: - - scheduledStartTime: "2023-11-09T04:30:00Z" - maintenanceEventId: "0d25b466-bc22-44a8-b15d-8f92e815cb6e" - - scheduledStartTime: "2023-11-15T06:00:00Z" - maintenanceEventId: "d4806381-cd1e-48df-b9ba-70f9b0829c72" + - scheduledStartTime: "2023-11-09T02:30:00Z" + maintenanceEventId: "b48a8a3e-b159-4b5f-a398-a816d1ffb50b" diff --git a/config/samples/clusters_v1beta1_postgresql.yaml b/config/samples/clusters_v1beta1_postgresql.yaml index 11c3b5859..ba676596b 100644 --- a/config/samples/clusters_v1beta1_postgresql.yaml +++ b/config/samples/clusters_v1beta1_postgresql.yaml @@ -6,7 +6,7 @@ metadata: # annotations: # testAnnotation: test spec: - name: "username-test" + name: "oleksandr-pg" version: "15.4.0" dataCentres: - region: "US_WEST_2" @@ -45,6 +45,32 @@ spec: # userRefs: # - namespace: default # name: postgresqluser-sample + clusterResourceRefs: + 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-two privateNetworkCluster: false synchronousModeStrict: false # resizeSettings: diff --git a/controllers/clusterresources/awssecuritygroupfirewallrule_controller.go b/controllers/clusterresources/awssecuritygroupfirewallrule_controller.go index 11da47237..6895973a8 100644 --- a/controllers/clusterresources/awssecuritygroupfirewallrule_controller.go +++ b/controllers/clusterresources/awssecuritygroupfirewallrule_controller.go @@ -74,6 +74,13 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) Reconcile(ctx context.Context, return models.ReconcileRequeue, err } + if firewallRule.Annotations[models.ClusterIDAnnotation] == "" { + return models.ExitReconcile, nil + } + if firewallRule.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return r.handleDeleteFirewallRule(ctx, firewallRule, &l), nil + } + switch firewallRule.Annotations[models.ResourceStateAnnotation] { case models.CreatingEvent: reconcileResult := r.handleCreateFirewallRule(ctx, firewallRule, &l) @@ -83,7 +90,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) Reconcile(ctx context.Context, return reconcileResult, nil case models.GenericEvent: l.Info("AWS security group firewall rule event isn't handled", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, "request", req, "event", firewallRule.Annotations[models.ResourceStateAnnotation]) @@ -101,13 +108,13 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleCreateFirewallRule( if firewallRule.Status.ID == "" { l.Info( "Creating AWS security group firewall rule", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) patch := firewallRule.NewPatch() - firewallRuleStatus, err := r.API.CreateFirewallRule(instaclustr.AWSSecurityGroupFirewallRuleEndpoint, &firewallRule.Spec) + firewallRuleStatus, err := r.API.CreateAWSSecurityGroupFirewallRule(instaclustr.AWSSecurityGroupFirewallRuleEndpoint, &firewallRule.Spec, firewallRule.Annotations[models.ClusterIDAnnotation]) if err != nil { l.Error( err, "Cannot create AWS security group firewall rule", @@ -143,7 +150,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleCreateFirewallRule( err = r.Patch(ctx, firewallRule, patch) if err != nil { l.Error(err, "Cannot patch AWS security group firewall rule", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) r.EventRecorder.Eventf( @@ -156,7 +163,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleCreateFirewallRule( l.Info( "AWS security group firewall rule resource has been created", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) } @@ -190,7 +197,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleDeleteFirewallRule( err := r.Patch(ctx, firewallRule, patch) if err != nil { l.Error(err, "Cannot patch AWS security group firewall rule metadata", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) @@ -206,7 +213,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleDeleteFirewallRule( if err != nil && !errors.Is(err, instaclustr.NotFound) { l.Error( err, "Cannot get AWS security group firewall rule status from the Instaclustr API", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) @@ -223,7 +230,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleDeleteFirewallRule( if err != nil { l.Error(err, "Cannot delete AWS security group firewall rule", "rule ID", firewallRule.Status.ID, - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) @@ -246,7 +253,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleDeleteFirewallRule( err = r.Patch(ctx, firewallRule, patch) if err != nil { l.Error(err, "Cannot patch AWS security group firewall rule metadata", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, "status", firewallRule.Status, ) @@ -260,7 +267,7 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) handleDeleteFirewallRule( } l.Info("AWS security group firewall rule has been deleted", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, "status", firewallRule.Status, ) @@ -364,6 +371,16 @@ func (r *AWSSecurityGroupFirewallRuleReconciler) SetupWithManager(mgr ctrl.Manag }, UpdateFunc: func(event event.UpdateEvent) bool { newObj := event.ObjectNew.(*v1beta1.AWSSecurityGroupFirewallRule) + + if newObj.Annotations[models.ResourceStateAnnotation] == models.CreatingEvent { + if newObj.Annotations[models.ClusterIDAnnotation] != "" { + return true + } + } + if newObj.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return true + } + if newObj.Generation == event.ObjectOld.GetGeneration() { return false } diff --git a/controllers/clusterresources/awsvpcpeering_controller.go b/controllers/clusterresources/awsvpcpeering_controller.go index 7aa4708fd..96aae6269 100644 --- a/controllers/clusterresources/awsvpcpeering_controller.go +++ b/controllers/clusterresources/awsvpcpeering_controller.go @@ -72,6 +72,13 @@ func (r *AWSVPCPeeringReconciler) Reconcile(ctx context.Context, req ctrl.Reques return models.ReconcileRequeue, err } + if aws.Annotations[models.CDCIDAnnotation] == "" { + return models.ExitReconcile, err + } + if aws.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return r.handleDeletePeering(ctx, aws, l), nil + } + switch aws.Annotations[models.ResourceStateAnnotation] { case models.CreatingEvent: return r.handleCreatePeering(ctx, aws, l), nil @@ -103,7 +110,7 @@ func (r *AWSVPCPeeringReconciler) handleCreatePeering( "Region", aws.Spec.PeerRegion, ) - awsStatus, err := r.API.CreatePeering(instaclustr.AWSPeeringEndpoint, &aws.Spec) + awsStatus, err := r.API.CreateAWSVPCPeering(&aws.Spec, aws.Annotations[models.CDCIDAnnotation]) if err != nil { l.Error( err, "cannot create AWS VPC Peering resource", @@ -286,7 +293,7 @@ func (r *AWSVPCPeeringReconciler) handleUpdatePeering( "AWS Account ID", aws.Spec.PeerAWSAccountID, "VPC ID", aws.Spec.PeerVPCID, "Region", aws.Spec.PeerRegion, - "AWS VPC Peering Data Centre ID", aws.Spec.DataCentreID, + "AWS VPC Peering Data Centre ID", aws.Annotations[models.CDCIDAnnotation], "AWS VPC Peering Status", aws.Status.PeeringStatus, ) @@ -365,7 +372,7 @@ func (r *AWSVPCPeeringReconciler) handleDeletePeering( "AWS VPC Peering ID", aws.Status.ID, "VPC ID", aws.Spec.PeerVPCID, "Region", aws.Spec.PeerRegion, - "AWS VPC Peering Data Centre ID", aws.Spec.DataCentreID, + "AWS VPC Peering Data Centre ID", aws.Annotations[models.CDCIDAnnotation], "AWS VPC Peering Status", aws.Status.PeeringStatus, ) @@ -491,6 +498,15 @@ func (r *AWSVPCPeeringReconciler) SetupWithManager(mgr ctrl.Manager) error { return true } + if newObj.Annotations[models.ResourceStateAnnotation] == models.CreatingEvent { + if newObj.Annotations[models.CDCIDAnnotation] != "" { + return true + } + } + if newObj.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return true + } + if newObj.Generation == event.ObjectOld.GetGeneration() { return false } diff --git a/controllers/clusterresources/azurevnetpeering_controller.go b/controllers/clusterresources/azurevnetpeering_controller.go index f3871baa9..a36b7856f 100644 --- a/controllers/clusterresources/azurevnetpeering_controller.go +++ b/controllers/clusterresources/azurevnetpeering_controller.go @@ -72,9 +72,16 @@ func (r *AzureVNetPeeringReconciler) Reconcile(ctx context.Context, req ctrl.Req return models.ReconcileRequeue, err } + if azure.Annotations[models.CDCIDAnnotation] == "" { + return models.ExitReconcile, err + } + if azure.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return r.handleDeletePeering(ctx, azure, &l), nil + } + switch azure.Annotations[models.ResourceStateAnnotation] { case models.CreatingEvent: - return r.handleCreatePeering(ctx, azure, l), nil + return r.handleCreatePeering(ctx, azure, &l), nil case models.UpdatingEvent: return r.handleUpdatePeering(ctx, azure, &l), nil @@ -96,7 +103,7 @@ func (r *AzureVNetPeeringReconciler) Reconcile(ctx context.Context, req ctrl.Req func (r *AzureVNetPeeringReconciler) handleCreatePeering( ctx context.Context, azure *v1beta1.AzureVNetPeering, - l logr.Logger, + l *logr.Logger, ) reconcile.Result { if azure.Status.ID == "" { l.Info( @@ -107,7 +114,7 @@ func (r *AzureVNetPeeringReconciler) handleCreatePeering( "Vnet Name", azure.Spec.PeerVirtualNetworkName, ) - azureStatus, err := r.API.CreatePeering(instaclustr.AzurePeeringEndpoint, &azure.Spec) + azureStatus, err := r.API.CreateAzureVNetPeering(&azure.Spec, azure.Annotations[models.CDCIDAnnotation]) if err != nil { l.Error( err, "cannot create Azure VNet Peering resource", @@ -390,6 +397,15 @@ func (r *AzureVNetPeeringReconciler) SetupWithManager(mgr ctrl.Manager) error { return true } + if newObj.Annotations[models.ResourceStateAnnotation] == models.CreatingEvent { + if newObj.Annotations[models.CDCIDAnnotation] != "" { + return true + } + } + if newObj.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return true + } + if newObj.Generation == event.ObjectOld.GetGeneration() { return false } diff --git a/controllers/clusterresources/clusterbackup_controller.go b/controllers/clusterresources/clusterbackup_controller.go index cbd72f2c6..6cd4cee1f 100644 --- a/controllers/clusterresources/clusterbackup_controller.go +++ b/controllers/clusterresources/clusterbackup_controller.go @@ -77,11 +77,15 @@ func (r *ClusterBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reques patch := backup.NewPatch() - if backup.Labels[models.ClusterIDLabel] != backup.Spec.ClusterID { + if backup.Annotations[models.ClusterIDAnnotation] == "" { + return models.ExitReconcile, nil + } + + if backup.Labels[models.ClusterIDLabel] != backup.Annotations[models.ClusterIDAnnotation] { if backup.Labels == nil { - backup.Labels = map[string]string{models.ClusterIDLabel: backup.Spec.ClusterID} + backup.Labels = map[string]string{models.ClusterIDLabel: backup.Annotations[models.ClusterIDAnnotation]} } else { - backup.Labels[models.ClusterIDLabel] = backup.Spec.ClusterID + backup.Labels[models.ClusterIDLabel] = backup.Annotations[models.ClusterIDAnnotation] } err = r.Patch(ctx, backup, patch) if err != nil { @@ -98,11 +102,11 @@ func (r *ClusterBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reques } } - backupsList, err := r.listClusterBackups(ctx, backup.Spec.ClusterID, backup.Namespace) + backupsList, err := r.listClusterBackups(ctx, backup.Annotations[models.ClusterIDAnnotation], backup.Namespace) if err != nil { logger.Error(err, "Cannot get cluster backups", "backup name", backup.Name, - "cluster ID", backup.Spec.ClusterID, + "cluster ID", backup.Annotations[models.ClusterIDAnnotation], ) r.EventRecorder.Eventf( @@ -118,11 +122,11 @@ func (r *ClusterBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reques clusterKind = models.PgAppKind } - iBackup, err := r.API.GetClusterBackups(backup.Spec.ClusterID, clusterKind) + iBackup, err := r.API.GetClusterBackups(backup.Annotations[models.ClusterIDAnnotation], clusterKind) if err != nil { logger.Error(err, "Cannot get cluster backups from Instaclustr", "backup name", backup.Name, - "cluster ID", backup.Spec.ClusterID, + "cluster ID", backup.Annotations[models.ClusterIDAnnotation], ) r.EventRecorder.Eventf( @@ -136,11 +140,11 @@ func (r *ClusterBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reques iBackupEvents := iBackup.GetBackupEvents(backup.Spec.ClusterKind) if len(iBackupEvents) < len(backupsList.Items) { - err = r.API.TriggerClusterBackup(backup.Spec.ClusterID, models.ClusterKindsMap[backup.Spec.ClusterKind]) + err = r.API.TriggerClusterBackup(backup.Annotations[models.ClusterIDAnnotation], models.ClusterKindsMap[backup.Spec.ClusterKind]) if err != nil { logger.Error(err, "Cannot trigger cluster backup", "backup name", backup.Name, - "cluster ID", backup.Spec.ClusterID, + "cluster ID", backup.Annotations[models.ClusterIDAnnotation], ) r.EventRecorder.Eventf( @@ -156,7 +160,7 @@ func (r *ClusterBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reques "Resource creation request is sent", ) logger.Info("New cluster backup request was sent", - "cluster ID", backup.Spec.ClusterID, + "cluster ID", backup.Annotations[models.ClusterIDAnnotation], ) } @@ -214,7 +218,7 @@ func (r *ClusterBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reques logger.Info("Cluster backup resource was reconciled", "backup name", backup.Name, - "cluster ID", backup.Spec.ClusterID, + "cluster ID", backup.Annotations[models.ClusterIDAnnotation], ) return models.ExitReconcile, nil @@ -239,6 +243,12 @@ func (r *ClusterBackupReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&v1beta1.ClusterBackup{}, builder.WithPredicates(predicate.Funcs{ UpdateFunc: func(event event.UpdateEvent) bool { + newObj := event.ObjectNew.(*v1beta1.ClusterBackup) + if newObj.Annotations[models.ResourceStateAnnotation] == models.CreatingEvent { + if newObj.Annotations[models.ClusterIDAnnotation] != "" { + return true + } + } return false }, })). diff --git a/controllers/clusterresources/clusternetworkfirewallrule_controller.go b/controllers/clusterresources/clusternetworkfirewallrule_controller.go index 2e8afe312..5fb73fdc3 100644 --- a/controllers/clusterresources/clusternetworkfirewallrule_controller.go +++ b/controllers/clusterresources/clusternetworkfirewallrule_controller.go @@ -78,6 +78,14 @@ func (r *ClusterNetworkFirewallRuleReconciler) Reconcile(ctx context.Context, re return models.ReconcileRequeue, err } + if firewallRule.Annotations[models.ClusterIDAnnotation] == "" { + return models.ExitReconcile, nil + } + if firewallRule.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + reconcileResult := r.HandleDeleteFirewallRule(ctx, firewallRule, &l) + return reconcileResult, nil + } + switch firewallRule.Annotations[models.ResourceStateAnnotation] { case models.CreatingEvent: reconcileResult := r.HandleCreateFirewallRule(ctx, firewallRule, &l) @@ -90,7 +98,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) Reconcile(ctx context.Context, re return reconcileResult, nil case models.GenericEvent: l.Info("Cluster network firewall rule event isn't handled", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, "request", req, "event", firewallRule.Annotations[models.ResourceStateAnnotation]) @@ -108,13 +116,13 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleCreateFirewallRule( if firewallRule.Status.ID == "" { l.Info( "Creating cluster network firewall rule", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) patch := firewallRule.NewPatch() - firewallRuleStatus, err := r.API.CreateFirewallRule(instaclustr.ClusterNetworkFirewallRuleEndpoint, &firewallRule.Spec) + firewallRuleStatus, err := r.API.CreateClusterNetworkFirewallRule(&firewallRule.Spec, firewallRule.Annotations[models.ClusterIDAnnotation]) if err != nil { l.Error( err, "Cannot create cluster network firewall rule", @@ -152,7 +160,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleCreateFirewallRule( err = r.Patch(ctx, firewallRule, patch) if err != nil { l.Error(err, "Cannot patch cluster network firewall rule", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) r.EventRecorder.Eventf( @@ -165,7 +173,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleCreateFirewallRule( l.Info( "Cluster network firewall rule resource has been created", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) } @@ -196,7 +204,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleUpdateFirewallRule( l *logr.Logger, ) reconcile.Result { l.Info("Cluster network firewall rule update is not implemented", - "firewall rule ID", firewallRule.Spec.ClusterID, + "firewall rule ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) @@ -212,7 +220,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleDeleteFirewallRule( err := r.Patch(ctx, firewallRule, patch) if err != nil { l.Error(err, "Cannot patch cluster network firewall rule metadata", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) r.EventRecorder.Eventf( @@ -227,7 +235,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleDeleteFirewallRule( if err != nil && !errors.Is(err, instaclustr.NotFound) { l.Error( err, "Cannot get cluster network firewall rule status from the Instaclustr API", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) r.EventRecorder.Eventf( @@ -243,7 +251,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleDeleteFirewallRule( if err != nil { l.Error(err, "Cannot delete cluster network firewall rule", "rule ID", firewallRule.Status.ID, - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, ) r.EventRecorder.Eventf( @@ -266,7 +274,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleDeleteFirewallRule( err = r.Patch(ctx, firewallRule, patch) if err != nil { l.Error(err, "Cannot patch cluster network firewall rule metadata", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, "status", firewallRule.Status, ) @@ -279,7 +287,7 @@ func (r *ClusterNetworkFirewallRuleReconciler) HandleDeleteFirewallRule( } l.Info("Cluster network firewall rule has been deleted", - "cluster ID", firewallRule.Spec.ClusterID, + "cluster ID", firewallRule.Annotations[models.ClusterIDAnnotation], "type", firewallRule.Spec.Type, "status", firewallRule.Status, ) @@ -347,6 +355,16 @@ func (r *ClusterNetworkFirewallRuleReconciler) SetupWithManager(mgr ctrl.Manager return true } + if newObj.Annotations[models.ResourceStateAnnotation] == models.CreatingEvent { + if newObj.Annotations[models.ClusterIDAnnotation] != "" { + return true + } + } + + if newObj.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return true + } + if newObj.Status.ID == "" { newObj.Annotations[models.ResourceStateAnnotation] = models.CreatingEvent return true diff --git a/controllers/clusterresources/exclusionwindow_controller.go b/controllers/clusterresources/exclusionwindow_controller.go index d2600c2d2..e243c7a0b 100644 --- a/controllers/clusterresources/exclusionwindow_controller.go +++ b/controllers/clusterresources/exclusionwindow_controller.go @@ -74,6 +74,14 @@ func (r *ExclusionWindowReconciler) Reconcile(ctx context.Context, req ctrl.Requ return models.ReconcileRequeue, nil } + if ew.Annotations[models.ClusterIDAnnotation] == "" { + return models.ExitReconcile, nil + } + + if ew.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return r.handleDeleteWindow(ctx, ew, l), nil + } + switch ew.Annotations[models.ResourceStateAnnotation] { case models.CreatingEvent: return r.handleCreateWindow(ctx, ew, l), nil @@ -81,7 +89,7 @@ func (r *ExclusionWindowReconciler) Reconcile(ctx context.Context, req ctrl.Requ return r.handleDeleteWindow(ctx, ew, l), nil default: l.Info("event isn't handled", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, "Request", req, "event", ew.Annotations[models.ResourceStateAnnotation]) @@ -97,11 +105,11 @@ func (r *ExclusionWindowReconciler) handleCreateWindow( if ew.Status.ID == "" { l.Info( "Creating Exclusion Window resource", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, ) - id, err := r.API.CreateExclusionWindow(ew.Spec.ClusterID, &ew.Spec) + id, err := r.API.CreateExclusionWindow(ew.Annotations[models.ClusterIDAnnotation], &ew.Spec) if err != nil { l.Error( err, "cannot create Exclusion Window resource", @@ -125,7 +133,7 @@ func (r *ExclusionWindowReconciler) handleCreateWindow( err = r.Status().Patch(ctx, ew, patch) if err != nil { l.Error(err, "cannot patch Exclusion Window resource status after creation", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, "Exclusion Window metadata", ew.ObjectMeta, ) @@ -142,7 +150,7 @@ func (r *ExclusionWindowReconciler) handleCreateWindow( err = r.Patch(ctx, ew, patch) if err != nil { l.Error(err, "cannot patch Exclusion Window resource metadata with created event", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, "Exclusion Window metadata", ew.ObjectMeta, ) @@ -156,7 +164,7 @@ func (r *ExclusionWindowReconciler) handleCreateWindow( l.Info( "Exclusion Window resource was created", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, ) } @@ -172,7 +180,7 @@ func (r *ExclusionWindowReconciler) handleDeleteWindow( if err != nil && !errors.Is(err, instaclustr.NotFound) { l.Error( err, "cannot get Exclusion Window status from the Instaclustr API", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, ) r.EventRecorder.Eventf( @@ -187,7 +195,7 @@ func (r *ExclusionWindowReconciler) handleDeleteWindow( err = r.API.DeleteExclusionWindow(ew.Status.ID) if err != nil { l.Error(err, "cannot delete Exclusion Window resource", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, "Exclusion Window metadata", ew.ObjectMeta, ) @@ -210,7 +218,7 @@ func (r *ExclusionWindowReconciler) handleDeleteWindow( err = r.Patch(ctx, ew, patch) if err != nil { l.Error(err, "cannot patch Exclusion Window resource metadata with deleted event", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, "Exclusion Window metadata", ew.ObjectMeta, ) @@ -223,7 +231,7 @@ func (r *ExclusionWindowReconciler) handleDeleteWindow( } l.Info("Exclusion Window has been deleted", - "Cluster ID", ew.Spec.ClusterID, + "Cluster ID", ew.Annotations[models.ClusterIDAnnotation], "Exclusion Window Spec", ew.Spec, "Exclusion Window Status", ew.Status, ) @@ -259,6 +267,15 @@ func (r *ExclusionWindowReconciler) SetupWithManager(mgr ctrl.Manager) error { return true } + if newObj.Annotations[models.ResourceStateAnnotation] == models.CreatingEvent { + if newObj.Annotations[models.ClusterIDAnnotation] != "" { + return true + } + } + if newObj.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return true + } + if newObj.Generation == event.ObjectOld.GetGeneration() { return false } diff --git a/controllers/clusterresources/gcpvpcpeering_controller.go b/controllers/clusterresources/gcpvpcpeering_controller.go index f2ce92a0d..9f3dcddb7 100644 --- a/controllers/clusterresources/gcpvpcpeering_controller.go +++ b/controllers/clusterresources/gcpvpcpeering_controller.go @@ -72,15 +72,22 @@ func (r *GCPVPCPeeringReconciler) Reconcile(ctx context.Context, req ctrl.Reques return models.ReconcileRequeue, err } + if gcp.Annotations[models.CDCIDAnnotation] == "" { + return models.ExitReconcile, err + } + if gcp.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return r.handleDeletePeering(ctx, gcp, l), nil + } + switch gcp.Annotations[models.ResourceStateAnnotation] { case models.CreatingEvent: - return r.handleCreateCluster(ctx, gcp, l), nil + return r.handleCreatePeering(ctx, gcp, l), nil case models.UpdatingEvent: - return r.handleUpdateCluster(ctx, gcp, l), nil + return r.handleUpdatePeering(ctx, gcp, l), nil case models.DeletingEvent: - return r.handleDeleteCluster(ctx, gcp, l), nil + return r.handleDeletePeering(ctx, gcp, l), nil default: l.Info("Event isn't handled", "project ID", gcp.Spec.PeerProjectID, @@ -91,7 +98,7 @@ func (r *GCPVPCPeeringReconciler) Reconcile(ctx context.Context, req ctrl.Reques } } -func (r *GCPVPCPeeringReconciler) handleCreateCluster( +func (r *GCPVPCPeeringReconciler) handleCreatePeering( ctx context.Context, gcp *v1beta1.GCPVPCPeering, l logr.Logger, @@ -103,7 +110,7 @@ func (r *GCPVPCPeeringReconciler) handleCreateCluster( "network name", gcp.Spec.PeerVPCNetworkName, ) - gcpStatus, err := r.API.CreatePeering(instaclustr.GCPPeeringEndpoint, &gcp.Spec) + gcpStatus, err := r.API.CreateGCPVPCPeering(&gcp.Spec, gcp.Annotations[models.CDCIDAnnotation]) if err != nil { l.Error( err, "Cannot create GCP VPC Peering resource", @@ -184,7 +191,7 @@ func (r *GCPVPCPeeringReconciler) handleCreateCluster( return models.ExitReconcile } -func (r *GCPVPCPeeringReconciler) handleUpdateCluster( +func (r *GCPVPCPeeringReconciler) handleUpdatePeering( ctx context.Context, gcp *v1beta1.GCPVPCPeering, l logr.Logger, @@ -194,7 +201,7 @@ func (r *GCPVPCPeeringReconciler) handleUpdateCluster( return models.ExitReconcile } -func (r *GCPVPCPeeringReconciler) handleDeleteCluster( +func (r *GCPVPCPeeringReconciler) handleDeletePeering( ctx context.Context, gcp *v1beta1.GCPVPCPeering, l logr.Logger, @@ -203,7 +210,7 @@ func (r *GCPVPCPeeringReconciler) handleDeleteCluster( if err != nil && !errors.Is(err, instaclustr.NotFound) { l.Error( err, "Cannot get GCP VPC Peering status from the Instaclustr API", - "id", status.ID, + "id", gcp.Status.ID, "project ID", gcp.Spec.PeerProjectID, "network name", gcp.Spec.PeerVPCNetworkName, ) @@ -373,6 +380,15 @@ func (r *GCPVPCPeeringReconciler) SetupWithManager(mgr ctrl.Manager) error { return true } + if newObj.Annotations[models.ResourceStateAnnotation] == models.CreatingEvent { + if newObj.Annotations[models.CDCIDAnnotation] != "" { + return true + } + } + if newObj.Annotations[models.ClusterEventAnnotation] == models.DeletingEvent { + return true + } + if newObj.Generation == event.ObjectOld.GetGeneration() { return false } diff --git a/controllers/clusterresources/helpers.go b/controllers/clusterresources/helpers.go index 799ae9bae..6a67b2671 100644 --- a/controllers/clusterresources/helpers.go +++ b/controllers/clusterresources/helpers.go @@ -21,6 +21,7 @@ import ( k8sCore "k8s.io/api/core/v1" "k8s.io/utils/strings/slices" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/pkg/instaclustr" @@ -119,3 +120,8 @@ func subnetsEqual(subnets1, subnets2 []string) bool { return true } + +type Object interface { + client.Object + NewPatch() client.Patch +} diff --git a/controllers/clusterresources/postgresqluser_controller.go b/controllers/clusterresources/postgresqluser_controller.go index 6269b4e7a..a87dc1fc7 100644 --- a/controllers/clusterresources/postgresqluser_controller.go +++ b/controllers/clusterresources/postgresqluser_controller.go @@ -412,14 +412,13 @@ func (r *PostgreSQLUserReconciler) createPostgreSQLFirewallRule( ObjectMeta: ctrl.ObjectMeta{ Name: firewallRuleName, Namespace: ns, - Annotations: map[string]string{models.ResourceStateAnnotation: models.CreatingEvent}, + Annotations: map[string]string{models.ResourceStateAnnotation: models.CreatingEvent, models.ClusterIDAnnotation: clusterID, models.ClusterEventAnnotation: models.CreatingEvent}, Labels: map[string]string{models.ClusterIDLabel: clusterID}, Finalizers: []string{models.DeletionFinalizer}, }, Spec: clusterresourcesv1beta1.ClusterNetworkFirewallRuleSpec{ FirewallRuleSpec: clusterresourcesv1beta1.FirewallRuleSpec{ - ClusterID: clusterID, - Type: models.PgAppType, + Type: models.PgAppType, }, Network: fmt.Sprintf("%s/%s", nodeAddress, "32"), }, diff --git a/controllers/clusters/postgresql_controller.go b/controllers/clusters/postgresql_controller.go index d90296410..2c7407a91 100644 --- a/controllers/clusters/postgresql_controller.go +++ b/controllers/clusters/postgresql_controller.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "errors" + "github.com/instaclustr/operator/controllers/clusterresources" "strconv" "github.com/go-logr/logr" @@ -492,6 +493,210 @@ func (r *PostgreSQLReconciler) handleUpdateCluster( return models.ExitReconcile } +func (r *PostgreSQLReconciler) handleClusterResourcesEvents( + newObj *v1beta1.PostgreSQL, + oldRefs *v1beta1.ClusterResourceRefs, +) { + r.HandleResourceEvent(newObj, "ClusterBackup", oldRefs.ClusterBackups, newObj.Spec.ClusterResourceRefs.ClusterBackups) + r.HandleResourceEvent(newObj, "ClusterNetworkFirewallRule", oldRefs.ClusterNetworkFirewallRules, newObj.Spec.ClusterResourceRefs.ClusterNetworkFirewallRules) + r.HandleResourceEvent(newObj, "AWSVPCPeering", oldRefs.AWSVPCPeerings, newObj.Spec.ClusterResourceRefs.AWSVPCPeerings) + r.HandleResourceEvent(newObj, "AWSSecurityGroupFirewallRule", oldRefs.AWSSecurityGroupFirewallRules, newObj.Spec.ClusterResourceRefs.AWSSecurityGroupFirewallRules) + r.HandleResourceEvent(newObj, "ExclusionWindow", oldRefs.ExclusionWindows, newObj.Spec.ClusterResourceRefs.ExclusionWindows) + r.HandleResourceEvent(newObj, "GCPVPCPeering", oldRefs.GCPVPCPeerings, newObj.Spec.ClusterResourceRefs.GCPVPCPeerings) + r.HandleResourceEvent(newObj, "AzureVNetPeering", oldRefs.AzureVNetPeerings, newObj.Spec.ClusterResourceRefs.AzureVNetPeerings) +} + +func (r *PostgreSQLReconciler) HandleResourceEvent( + pg *v1beta1.PostgreSQL, + resourceKind string, + oldRefs, newRefs []*v1beta1.UserReference, +) { + ctx := context.TODO() + l := log.FromContext(ctx) + + for _, ref := range newRefs { + var exist bool + for _, oldRef := range oldRefs { + if *ref == *oldRef { + exist = true + break + } + } + + if exist { + continue + } + + err := r.handleCreateResource(ctx, l, resourceKind, ref, pg) + if err != nil { + l.Error(err, "Cannot create clusterresource", "resource kind", resourceKind, "namespace and name", ref) + r.EventRecorder.Eventf(pg, models.Warning, models.CreatingEvent, + "Cannot create resource. Reason: %v", err) + } + oldRefs = append(oldRefs, ref) + } + for _, oldRef := range oldRefs { + var exist bool + for _, ref := range newRefs { + if *oldRef == *ref { + exist = true + break + } + } + + if exist { + continue + } + + err := r.handleDeleteResource(ctx, l, resourceKind, oldRef, pg) + if err != nil { + l.Error(err, "Cannot delete clusterresource", "resource kind", resourceKind, "namespace and name", oldRef) + r.EventRecorder.Eventf(pg, models.Warning, models.DeletingEvent, + "Cannot delete resource. Reason: %v", err) + } + } +} + +func (r *PostgreSQLReconciler) handleCreateResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.UserReference, + pg *v1beta1.PostgreSQL, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + + switch kind { + case "ClusterBackup": + resource = &clusterresourcesv1beta1.ClusterBackup{} + case "ClusterNetworkFirewallRule": + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case "AWSVPCPeering": + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case "AWSSecurityGroupFirewallRule": + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case "ExclusionWindow": + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case "GCPVPCPeering": + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case "AzureVNetPeering": + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind, "resource", resource) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot create a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "Resource", resource) + return err + } + + annots := resource.GetAnnotations() + + if isCDC { + annots[models.CDCIDAnnotation] = pg.Status.DataCentres[0].ID + } else { + annots[models.ClusterIDAnnotation] = pg.Status.ID + } + annots[models.ClusterEventAnnotation] = models.CreatingEvent + + err = r.Update(ctx, resource) + if err != nil { + return err + } + + l.Info("PostgreSQL clusterresource was updated", + "Resource name:", ref.Name, + "Resource Kind:", kind, + "Event:", models.CreatingEvent, + ) + + return nil +} + +func (r *PostgreSQLReconciler) handleDeleteResource( + ctx context.Context, + l logr.Logger, + kind string, + ref *v1beta1.UserReference, + pg *v1beta1.PostgreSQL, +) error { + req := types.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } + + var resource clusterresources.Object + var isCDC bool + + switch kind { + case "ClusterNetworkFirewallRule": + resource = &clusterresourcesv1beta1.ClusterNetworkFirewallRule{} + case "AWSVPCPeering": + resource = &clusterresourcesv1beta1.AWSVPCPeering{} + isCDC = true + case "AWSSecurityGroupFirewallRule": + resource = &clusterresourcesv1beta1.AWSSecurityGroupFirewallRule{} + case "ExclusionWindow": + resource = &clusterresourcesv1beta1.ExclusionWindow{} + case "GCPVPCPeering": + resource = &clusterresourcesv1beta1.GCPVPCPeering{} + isCDC = true + case "AzureVNetPeering": + resource = &clusterresourcesv1beta1.AzureVNetPeering{} + isCDC = true + default: + l.Info("Provided reference to resource that is not supported", "kind", kind, "resource", resource) + return nil + } + + err := r.Get(ctx, req, resource) + if err != nil { + if k8serrors.IsNotFound(err) { + l.Error(err, "Cannot create a cluster resource. The resource is not found", "request", req) + return err + } + l.Error(err, "Cannot get cluster resource", "Resource", resource) + return err + } + + annots := resource.GetAnnotations() + + if isCDC { + annots[models.CDCIDAnnotation] = pg.Status.DataCentres[0].ID + } else { + annots[models.ClusterIDAnnotation] = pg.Status.ID + } + annots[models.ClusterEventAnnotation] = models.DeletingEvent + + err = r.Update(ctx, resource) + if err != nil { + return err + } + + l.Info("PostgreSQL clusterresource was updated", + "Resource name:", ref.Name, + "Resource Kind:", kind, + "Event:", models.DeletingEvent, + ) + + return nil +} + func (r *PostgreSQLReconciler) createUser( ctx context.Context, l logr.Logger, @@ -1675,6 +1880,7 @@ func (r *PostgreSQLReconciler) SetupWithManager(mgr ctrl.Manager) error { oldObj := event.ObjectOld.(*v1beta1.PostgreSQL) r.handleUserEvent(newObj, oldObj.Spec.UserRefs) + r.handleClusterResourcesEvents(newObj, oldObj.Spec.ClusterResourceRefs) event.ObjectNew.GetAnnotations()[models.ResourceStateAnnotation] = models.UpdatingEvent return true diff --git a/pkg/instaclustr/client.go b/pkg/instaclustr/client.go index 4bfa8119c..2cafadc33 100644 --- a/pkg/instaclustr/client.go +++ b/pkg/instaclustr/client.go @@ -598,14 +598,117 @@ func (c *Client) GetPeeringStatus(peerID, return &peeringStatus, nil } -func (c *Client) CreatePeering(url string, peeringSpec any) (*clusterresourcesv1beta1.PeeringStatus, error) { +func (c *Client) CreateAzureVNetPeering(peeringSpec *clusterresourcesv1beta1.AzureVNetPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) { + payload := &struct { + PeerSubnets []string `json:"peerSubnets"` + PeerResourceGroup string `json:"peerResourceGroup"` + PeerSubscriptionID string `json:"peerSubscriptionId"` + PeerADObjectID string `json:"peerAdObjectId,omitempty"` + PeerVirtualNetworkName string `json:"peerVirtualNetworkName"` + CDCid string `json:"cdcId"` + }{ + PeerSubnets: peeringSpec.PeerSubnets, + PeerResourceGroup: peeringSpec.PeerResourceGroup, + PeerADObjectID: peeringSpec.PeerADObjectID, + PeerSubscriptionID: peeringSpec.PeerSubscriptionID, + PeerVirtualNetworkName: peeringSpec.PeerVirtualNetworkName, + CDCid: cdcId, + } - jsonDataCreate, err := json.Marshal(peeringSpec) + jsonDataCreate, err := json.Marshal(payload) if err != nil { return nil, err } - url = c.serverHostname + url + url := c.serverHostname + AzurePeeringEndpoint + resp, err := c.DoRequest(url, http.MethodPost, jsonDataCreate) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusAccepted { + return nil, fmt.Errorf("status code: %d, message: %s", resp.StatusCode, body) + } + + var creationResponse *clusterresourcesv1beta1.PeeringStatus + err = json.Unmarshal(body, &creationResponse) + if err != nil { + return nil, err + } + + return creationResponse, nil +} + +func (c *Client) CreateAWSVPCPeering(peeringSpec *clusterresourcesv1beta1.AWSVPCPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) { + payload := &struct { + PeerSubnets []string `json:"peerSubnets"` + PeerAWSAccountID string `json:"peerAwsAccountId"` + PeerVPCID string `json:"peerVpcId"` + PeerRegion string `json:"peerRegion,omitempty"` + CDCid string `json:"cdcId"` + }{ + PeerSubnets: peeringSpec.PeerSubnets, + PeerAWSAccountID: peeringSpec.PeerAWSAccountID, + PeerVPCID: peeringSpec.PeerVPCID, + PeerRegion: peeringSpec.PeerRegion, + CDCid: cdcId, + } + + jsonDataCreate, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + url := c.serverHostname + AWSPeeringEndpoint + resp, err := c.DoRequest(url, http.MethodPost, jsonDataCreate) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusAccepted { + return nil, fmt.Errorf("status code: %d, message: %s", resp.StatusCode, body) + } + + var creationResponse *clusterresourcesv1beta1.PeeringStatus + err = json.Unmarshal(body, &creationResponse) + if err != nil { + return nil, err + } + + return creationResponse, nil +} + +func (c *Client) CreateGCPVPCPeering(peeringSpec *clusterresourcesv1beta1.GCPVPCPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) { + payload := &struct { + PeerSubnets []string `json:"peerSubnets"` + PeerVPCNetworkName string `json:"peerVpcNetworkName"` + PeerProjectID string `json:"peerProjectId"` + CDCid string `json:"cdcId"` + }{ + PeerSubnets: peeringSpec.PeerSubnets, + PeerVPCNetworkName: peeringSpec.PeerVPCNetworkName, + PeerProjectID: peeringSpec.PeerProjectID, + CDCid: cdcId, + } + + jsonDataCreate, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + url := c.serverHostname + GCPPeeringEndpoint resp, err := c.DoRequest(url, http.MethodPost, jsonDataCreate) if err != nil { return nil, err @@ -718,11 +821,22 @@ func (c *Client) GetFirewallRuleStatus( return firewallRuleStatus, nil } -func (c *Client) CreateFirewallRule( +func (c *Client) CreateAWSSecurityGroupFirewallRule( url string, - firewallRuleSpec any, + firewallRuleSpec *clusterresourcesv1beta1.AWSSecurityGroupFirewallRuleSpec, + clusterID string, ) (*clusterresourcesv1beta1.FirewallRuleStatus, error) { - jsonFirewallRule, err := json.Marshal(firewallRuleSpec) + payload := &struct { + SecurityGroupID string `json:"securityGroupId"` + ClusterID string `json:"clusterId,omitempty"` + Type string `json:"type"` + }{ + SecurityGroupID: firewallRuleSpec.SecurityGroupID, + ClusterID: clusterID, + Type: firewallRuleSpec.Type, + } + + jsonFirewallRule, err := json.Marshal(payload) if err != nil { return nil, err } @@ -752,6 +866,50 @@ func (c *Client) CreateFirewallRule( return creationResponse, nil } +func (c *Client) CreateClusterNetworkFirewallRule( + firewallRuleSpec *clusterresourcesv1beta1.ClusterNetworkFirewallRuleSpec, + clusterID string, +) (*clusterresourcesv1beta1.FirewallRuleStatus, error) { + payload := &struct { + ClusterID string `json:"clusterId"` + Type string `json:"type"` + Network string `json:"network"` + }{ + ClusterID: clusterID, + Type: firewallRuleSpec.Type, + Network: firewallRuleSpec.Network, + } + + jsonFirewallRule, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + url := c.serverHostname + ClusterNetworkFirewallRuleEndpoint + resp, err := c.DoRequest(url, http.MethodPost, jsonFirewallRule) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusAccepted { + return nil, fmt.Errorf("status code: %d, message: %s", resp.StatusCode, body) + } + + var creationResponse *clusterresourcesv1beta1.FirewallRuleStatus + err = json.Unmarshal(body, &creationResponse) + if err != nil { + return nil, err + } + + return creationResponse, nil +} + func (c *Client) DeleteFirewallRule( firewallRuleID string, firewallRuleEndpoint string, diff --git a/pkg/instaclustr/interfaces.go b/pkg/instaclustr/interfaces.go index 6e19e5041..7c502aa86 100644 --- a/pkg/instaclustr/interfaces.go +++ b/pkg/instaclustr/interfaces.go @@ -37,9 +37,12 @@ type API interface { GetAWSVPCPeering(peerID string) (*models.AWSVPCPeering, error) UpdatePeering(peerID, peeringEndpoint string, peerSpec any) error DeletePeering(peerID, peeringEndpoint string) error - CreatePeering(url string, peeringSpec any) (*clusterresourcesv1beta1.PeeringStatus, error) + CreateAzureVNetPeering(peeringSpec *clusterresourcesv1beta1.AzureVNetPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) + CreateGCPVPCPeering(peeringSpec *clusterresourcesv1beta1.GCPVPCPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) + CreateAWSVPCPeering(peeringSpec *clusterresourcesv1beta1.AWSVPCPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) GetFirewallRuleStatus(firewallRuleID string, firewallRuleEndpoint string) (*clusterresourcesv1beta1.FirewallRuleStatus, error) - CreateFirewallRule(url string, firewallRuleSpec any) (*clusterresourcesv1beta1.FirewallRuleStatus, error) + CreateAWSSecurityGroupFirewallRule(url string, firewallRuleSpec *clusterresourcesv1beta1.AWSSecurityGroupFirewallRuleSpec, clusterID string) (*clusterresourcesv1beta1.FirewallRuleStatus, error) + CreateClusterNetworkFirewallRule(firewallRuleSpec *clusterresourcesv1beta1.ClusterNetworkFirewallRuleSpec, clusterID string) (*clusterresourcesv1beta1.FirewallRuleStatus, error) DeleteFirewallRule(firewallRuleID string, firewallRuleEndpoint string) error CreateKafkaUser(url string, kafkaUser *models.KafkaUser) (*kafkamanagementv1beta1.KafkaUserStatus, error) UpdateKafkaUser(kafkaUserID string, kafkaUserSpec *models.KafkaUser) error diff --git a/pkg/instaclustr/mock/client.go b/pkg/instaclustr/mock/client.go index 36c8b1e32..39166a83a 100644 --- a/pkg/instaclustr/mock/client.go +++ b/pkg/instaclustr/mock/client.go @@ -77,7 +77,27 @@ func (c *mockClient) DeletePeering(peerID, peeringEndpoint string) error { panic("DeletePeering: is not implemented") } -func (c *mockClient) CreatePeering(url string, peeringSpec any) (*clusterresourcesv1beta1.PeeringStatus, error) { +func (c *mockClient) CreateAzureVNetPeering(peeringSpec *clusterresourcesv1beta1.AzureVNetPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) { + ps := &clusterresourcesv1beta1.PeeringStatus{ + ID: StatusID, + Name: "name", + StatusCode: "statusCode", + FailureReason: "failureReason", + } + return ps, nil +} + +func (c *mockClient) CreateAWSVPCPeering(peeringSpec *clusterresourcesv1beta1.AWSVPCPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) { + ps := &clusterresourcesv1beta1.PeeringStatus{ + ID: StatusID, + Name: "name", + StatusCode: "statusCode", + FailureReason: "failureReason", + } + return ps, nil +} + +func (c *mockClient) CreateGCPVPCPeering(peeringSpec *clusterresourcesv1beta1.GCPVPCPeeringSpec, cdcId string) (*clusterresourcesv1beta1.PeeringStatus, error) { ps := &clusterresourcesv1beta1.PeeringStatus{ ID: StatusID, Name: "name", @@ -96,7 +116,15 @@ func (c *mockClient) GetFirewallRuleStatus(firewallRuleID string, firewallRuleEn return fwRule, nil } -func (c *mockClient) CreateFirewallRule(url string, firewallRuleSpec any) (*clusterresourcesv1beta1.FirewallRuleStatus, error) { +func (c *mockClient) CreateAWSSecurityGroupFirewallRule(url string, firewallRuleSpec *clusterresourcesv1beta1.AWSSecurityGroupFirewallRuleSpec, clusterID string) (*clusterresourcesv1beta1.FirewallRuleStatus, error) { + fwRule := &clusterresourcesv1beta1.FirewallRuleStatus{ + ID: StatusID, + Status: "OK", + DeferredReason: "NO", + } + return fwRule, nil +} +func (c *mockClient) CreateClusterNetworkFirewallRule(firewallRuleSpec *clusterresourcesv1beta1.ClusterNetworkFirewallRuleSpec, clusterID string) (*clusterresourcesv1beta1.FirewallRuleStatus, error) { fwRule := &clusterresourcesv1beta1.FirewallRuleStatus{ ID: StatusID, Status: "OK", diff --git a/pkg/models/operator.go b/pkg/models/operator.go index 435480682..6dc0f0d8d 100644 --- a/pkg/models/operator.go +++ b/pkg/models/operator.go @@ -29,6 +29,9 @@ const ( DeletionFinalizer = "instaclustr.com/deletionFinalizer" StartTimestampAnnotation = "instaclustr.com/startTimestamp" UpdateQueuedAnnotation = "instaclustr.com/updateQueued" + ClusterIDAnnotation = "clusterID" + CDCIDAnnotation = "cdcId" + ClusterEventAnnotation = "clusterEvent" DefaultSecretLabel = "instaclustr.com/defaultSecret" ControlledByLabel = "instaclustr.com/controlledBy"