From 518b189a3f809bacae501ba1475617886a0ce456 Mon Sep 17 00:00:00 2001 From: testisnullus Date: Wed, 13 Sep 2023 13:29:03 +0300 Subject: [PATCH] Maintenance Events resource was transfered to APIv2 --- .../v1beta1/maintenanceevents_types.go | 46 ++-- .../v1beta1/zz_generated.deepcopy.go | 74 ++++-- apis/clusters/v1beta1/structs.go | 160 ++++++++---- .../clusters/v1beta1/zz_generated.deepcopy.go | 55 +++- ...ces.instaclustr.com_maintenanceevents.yaml | 36 ++- .../clusters.instaclustr.com_cadences.yaml | 95 +++++-- .../clusters.instaclustr.com_cassandras.yaml | 93 +++++-- ...lusters.instaclustr.com_kafkaconnects.yaml | 93 +++++-- .../clusters.instaclustr.com_kafkas.yaml | 94 +++++-- ...clusters.instaclustr.com_opensearches.yaml | 93 +++++-- .../clusters.instaclustr.com_postgresqls.yaml | 93 +++++-- .../bases/clusters.instaclustr.com_redis.yaml | 93 +++++-- .../clusters.instaclustr.com_zookeepers.yaml | 93 +++++-- .../samples/clusters_v1beta1_cassandra.yaml | 2 +- .../maintenanceevents_controller.go | 238 ++++++------------ controllers/clusters/cadence_controller.go | 68 +++-- controllers/clusters/cassandra_controller.go | 67 +++-- controllers/clusters/kafka_controller.go | 68 +++-- .../clusters/kafkaconnect_controller.go | 68 +++-- controllers/clusters/opensearch_controller.go | 73 ++++-- controllers/clusters/postgresql_controller.go | 73 ++++-- controllers/clusters/redis_controller.go | 67 +++-- controllers/clusters/zookeeper_controller.go | 68 +++-- pkg/instaclustr/client.go | 64 +---- pkg/instaclustr/config.go | 6 +- pkg/instaclustr/interfaces.go | 5 +- pkg/instaclustr/mock/client.go | 14 +- pkg/models/operator.go | 6 + 28 files changed, 1372 insertions(+), 633 deletions(-) diff --git a/apis/clusterresources/v1beta1/maintenanceevents_types.go b/apis/clusterresources/v1beta1/maintenanceevents_types.go index 60fd1dfa5..4bbfb889d 100644 --- a/apis/clusterresources/v1beta1/maintenanceevents_types.go +++ b/apis/clusterresources/v1beta1/maintenanceevents_types.go @@ -18,26 +18,27 @@ package v1beta1 import ( "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/instaclustr/operator/pkg/validation" ) -type MaintenanceEventRescheduleSpec struct { - ScheduledStartTime string `json:"scheduledStartTime"` - ScheduleID string `json:"scheduleId"` -} - // MaintenanceEventsSpec defines the desired state of MaintenanceEvents type MaintenanceEventsSpec struct { - ClusterID string `json:"clusterId"` - MaintenanceEventsReschedules []*MaintenanceEventRescheduleSpec `json:"maintenanceEventsReschedule,omitempty"` + ClusterID string `json:"clusterId"` + MaintenanceEventsReschedules []*MaintenanceEventReschedule `json:"maintenanceEventsReschedule"` } // MaintenanceEventsStatus defines the observed state of MaintenanceEvents type MaintenanceEventsStatus struct { - EventsStatuses []*MaintenanceEventStatus `json:"eventsStatuses,omitempty"` + RescheduledEvent *MaintenanceEventReschedule `json:"rescheduled"` +} + +type MaintenanceEventReschedule struct { + ScheduledStartTime string `json:"scheduledStartTime"` + MaintenanceEventId string `json:"maintenanceEventId"` } type MaintenanceEventStatus struct { @@ -48,6 +49,15 @@ type MaintenanceEventStatus struct { ScheduledStartTimeMin string `json:"scheduledStartTimeMin,omitempty"` ScheduledStartTimeMax string `json:"scheduledStartTimeMax,omitempty"` IsFinalized bool `json:"isFinalized,omitempty"` + StartTime string `json:"startTime,omitempty"` + EndTime string `json:"endTime,omitempty"` + Outcome string `json:"outcome,omitempty"` +} + +type ClusteredMaintenanceEventStatus struct { + InProgress []*MaintenanceEventStatus `json:"inProgress"` + Past []*MaintenanceEventStatus `json:"past"` + Upcoming []*MaintenanceEventStatus `json:"Upcoming"` } //+kubebuilder:object:root=true @@ -80,26 +90,6 @@ func (me *MaintenanceEvents) NewPatch() client.Patch { return client.MergeFrom(old) } -func (me *MaintenanceEvents) AreMEventsStatusesEqual(instMEventsStatuses []*MaintenanceEventStatus) bool { - if len(instMEventsStatuses) != len(me.Status.EventsStatuses) { - return false - } - - for _, instMEvent := range instMEventsStatuses { - for _, k8sMEvent := range me.Status.EventsStatuses { - if instMEvent.ID == k8sMEvent.ID { - if *instMEvent != *k8sMEvent { - return false - } - - break - } - } - } - - return true -} - func (mes *MaintenanceEventsSpec) ValidateMaintenanceEventsReschedules() error { for _, event := range mes.MaintenanceEventsReschedules { if dateValid, err := validation.ValidateISODate(event.ScheduledStartTime); err != nil || !dateValid { diff --git a/apis/clusterresources/v1beta1/zz_generated.deepcopy.go b/apis/clusterresources/v1beta1/zz_generated.deepcopy.go index 27a8b69cc..458a49b72 100644 --- a/apis/clusterresources/v1beta1/zz_generated.deepcopy.go +++ b/apis/clusterresources/v1beta1/zz_generated.deepcopy.go @@ -758,6 +758,54 @@ func (in *ClusterNetworkFirewallRuleStatus) DeepCopy() *ClusterNetworkFirewallRu return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusteredMaintenanceEventStatus) DeepCopyInto(out *ClusteredMaintenanceEventStatus) { + *out = *in + if in.InProgress != nil { + in, out := &in.InProgress, &out.InProgress + *out = make([]*MaintenanceEventStatus, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MaintenanceEventStatus) + **out = **in + } + } + } + if in.Past != nil { + in, out := &in.Past, &out.Past + *out = make([]*MaintenanceEventStatus, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MaintenanceEventStatus) + **out = **in + } + } + } + if in.Upcoming != nil { + in, out := &in.Upcoming, &out.Upcoming + *out = make([]*MaintenanceEventStatus, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MaintenanceEventStatus) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusteredMaintenanceEventStatus. +func (in *ClusteredMaintenanceEventStatus) DeepCopy() *ClusteredMaintenanceEventStatus { + if in == nil { + return nil + } + out := new(ClusteredMaintenanceEventStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ExclusionWindow) DeepCopyInto(out *ExclusionWindow) { *out = *in @@ -969,16 +1017,16 @@ func (in *GCPVPCPeeringStatus) DeepCopy() *GCPVPCPeeringStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *MaintenanceEventRescheduleSpec) DeepCopyInto(out *MaintenanceEventRescheduleSpec) { +func (in *MaintenanceEventReschedule) DeepCopyInto(out *MaintenanceEventReschedule) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaintenanceEventRescheduleSpec. -func (in *MaintenanceEventRescheduleSpec) DeepCopy() *MaintenanceEventRescheduleSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MaintenanceEventReschedule. +func (in *MaintenanceEventReschedule) DeepCopy() *MaintenanceEventReschedule { if in == nil { return nil } - out := new(MaintenanceEventRescheduleSpec) + out := new(MaintenanceEventReschedule) in.DeepCopyInto(out) return out } @@ -1062,11 +1110,11 @@ func (in *MaintenanceEventsSpec) DeepCopyInto(out *MaintenanceEventsSpec) { *out = *in if in.MaintenanceEventsReschedules != nil { in, out := &in.MaintenanceEventsReschedules, &out.MaintenanceEventsReschedules - *out = make([]*MaintenanceEventRescheduleSpec, len(*in)) + *out = make([]*MaintenanceEventReschedule, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(MaintenanceEventRescheduleSpec) + *out = new(MaintenanceEventReschedule) **out = **in } } @@ -1086,16 +1134,10 @@ func (in *MaintenanceEventsSpec) DeepCopy() *MaintenanceEventsSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MaintenanceEventsStatus) DeepCopyInto(out *MaintenanceEventsStatus) { *out = *in - if in.EventsStatuses != nil { - in, out := &in.EventsStatuses, &out.EventsStatuses - *out = make([]*MaintenanceEventStatus, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(MaintenanceEventStatus) - **out = **in - } - } + if in.RescheduledEvent != nil { + in, out := &in.RescheduledEvent, &out.RescheduledEvent + *out = new(MaintenanceEventReschedule) + **out = **in } } diff --git a/apis/clusters/v1beta1/structs.go b/apis/clusters/v1beta1/structs.go index 2ed35a342..b20a574e8 100644 --- a/apis/clusters/v1beta1/structs.go +++ b/apis/clusters/v1beta1/structs.go @@ -19,7 +19,9 @@ package v1beta1 import ( "encoding/json" "net" + "time" + clusterresource "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "github.com/instaclustr/operator/pkg/models" ) @@ -90,24 +92,33 @@ type Cluster struct { } type ClusterStatus struct { - ID string `json:"id,omitempty"` - State string `json:"state,omitempty"` - DataCentres []*DataCentreStatus `json:"dataCentres,omitempty"` - CDCID string `json:"cdcid,omitempty"` - TwoFactorDeleteEnabled bool `json:"twoFactorDeleteEnabled,omitempty"` - Options *Options `json:"options,omitempty"` - CurrentClusterOperationStatus string `json:"currentClusterOperationStatus,omitempty"` - MaintenanceEvents []*MaintenanceEvent `json:"maintenanceEvents,omitempty"` + ID string `json:"id,omitempty"` + State string `json:"state,omitempty"` + DataCentres []*DataCentreStatus `json:"dataCentres,omitempty"` + CDCID string `json:"cdcid,omitempty"` + TwoFactorDeleteEnabled bool `json:"twoFactorDeleteEnabled,omitempty"` + Options *Options `json:"options,omitempty"` + CurrentClusterOperationStatus string `json:"currentClusterOperationStatus,omitempty"` + MaintenanceEvents []*clusterresource.ClusteredMaintenanceEventStatus `json:"maintenanceEvents,omitempty"` +} + +type ClusteredMaintenanceEvent struct { + InProgress []*MaintenanceEvent `json:"inProgress"` + Past []*MaintenanceEvent `json:"past"` + Upcoming []*MaintenanceEvent `json:"upcoming"` } type MaintenanceEvent struct { ID string `json:"id,omitempty"` Description string `json:"description,omitempty"` - ScheduledStartTime string `json:"scheduledStartTime,omitempty"` - ScheduledEndTime string `json:"scheduledEndTime,omitempty"` - ScheduledStartTimeMin string `json:"scheduledStartTimeMin,omitempty"` - ScheduledStartTimeMax string `json:"scheduledStartTimeMax,omitempty"` + ScheduledStartTime int64 `json:"scheduledStartTime,omitempty"` + ScheduledEndTime int64 `json:"scheduledEndTime,omitempty"` + ScheduledStartTimeMin int64 `json:"scheduledStartTimeMin,omitempty"` + ScheduledStartTimeMax int64 `json:"scheduledStartTimeMax,omitempty"` IsFinalized bool `json:"isFinalized,omitempty"` + StartTime int64 `json:"startTime,omitempty"` + EndTime int64 `json:"endTime,omitempty"` + Outcome string `json:"outcome,omitempty"` } type TwoFactorDelete struct { @@ -419,23 +430,82 @@ func (c *Cluster) newImmutableFields() immutableCluster { } } -func (cs *ClusterStatus) AreMaintenanceEventsEqual(iEvents []*MaintenanceEvent) bool { - if len(cs.MaintenanceEvents) != len(iEvents) { - return false +func (cs *ClusterStatus) MaintenanceEventStatusFromInstAPI(iEventStatuses []*MaintenanceEvent) []*clusterresource.MaintenanceEventStatus { + var meStatuses = make([]*clusterresource.MaintenanceEventStatus, 0) + for _, iEventStatus := range iEventStatuses { + meStatuses = append(meStatuses, &clusterresource.MaintenanceEventStatus{ + ID: iEventStatus.ID, + Description: iEventStatus.Description, + ScheduledStartTime: time.Unix(iEventStatus.ScheduledStartTime, 0).Format(time.RFC3339), + ScheduledEndTime: time.Unix(iEventStatus.ScheduledEndTime, 0).Format(time.RFC3339), + ScheduledStartTimeMax: time.Unix(iEventStatus.ScheduledStartTimeMax, 0).Format(time.RFC3339), + ScheduledStartTimeMin: time.Unix(iEventStatus.ScheduledStartTimeMin, 0).Format(time.RFC3339), + IsFinalized: iEventStatus.IsFinalized, + StartTime: time.Unix(iEventStatus.StartTime, 0).Format(time.RFC3339), + EndTime: time.Unix(iEventStatus.EndTime, 0).Format(time.RFC3339), + Outcome: iEventStatus.Outcome, + }) } - for _, iEvent := range iEvents { - for _, k8sEvent := range cs.MaintenanceEvents { - if iEvent.ID == k8sEvent.ID { - if *iEvent != *k8sEvent { - return false - } + return meStatuses +} + +func (cs *ClusterStatus) AreMaintenanceEventStatusesEqual( + iEventStatuses []*clusterresource.ClusteredMaintenanceEventStatus, +) bool { + if len(cs.MaintenanceEvents) != len(iEventStatuses) { + return false + } - break + for i, iES := range iEventStatuses { + if len(iES.Upcoming) != len(cs.MaintenanceEvents[i].Upcoming) || + len(iES.Past) != len(cs.MaintenanceEvents[i].Past) || + len(iES.InProgress) != len(cs.MaintenanceEvents[i].InProgress) { + return false + } + for j, ip := range iES.InProgress { + if ip.ID != cs.MaintenanceEvents[i].InProgress[j].ID || + ip.Description != cs.MaintenanceEvents[i].InProgress[j].Description || + ip.ScheduledStartTime != cs.MaintenanceEvents[i].InProgress[j].ScheduledStartTime || + ip.ScheduledEndTime != cs.MaintenanceEvents[i].InProgress[j].ScheduledEndTime || + ip.ScheduledStartTimeMax != cs.MaintenanceEvents[i].InProgress[j].ScheduledStartTimeMax || + ip.ScheduledStartTimeMin != cs.MaintenanceEvents[i].InProgress[j].ScheduledStartTimeMin || + ip.IsFinalized != cs.MaintenanceEvents[i].InProgress[j].IsFinalized || + ip.StartTime != cs.MaintenanceEvents[i].InProgress[j].StartTime || + ip.EndTime != cs.MaintenanceEvents[i].InProgress[j].EndTime || + ip.Outcome != cs.MaintenanceEvents[i].InProgress[j].Outcome { + return false + } + } + for k, p := range iES.Past { + if p.ID != cs.MaintenanceEvents[i].Past[k].ID || + p.Description != cs.MaintenanceEvents[i].Past[k].Description || + p.ScheduledStartTime != cs.MaintenanceEvents[i].Past[k].ScheduledStartTime || + p.ScheduledEndTime != cs.MaintenanceEvents[i].Past[k].ScheduledEndTime || + p.ScheduledStartTimeMax != cs.MaintenanceEvents[i].Past[k].ScheduledStartTimeMax || + p.ScheduledStartTimeMin != cs.MaintenanceEvents[i].Past[k].ScheduledStartTimeMin || + p.IsFinalized != cs.MaintenanceEvents[i].Past[k].IsFinalized || + p.StartTime != cs.MaintenanceEvents[i].Past[k].StartTime || + p.EndTime != cs.MaintenanceEvents[i].Past[k].EndTime || + p.Outcome != cs.MaintenanceEvents[i].Past[k].Outcome { + return false + } + } + for v, u := range iES.Upcoming { + if u.ID != cs.MaintenanceEvents[i].Upcoming[v].ID || + u.Description != cs.MaintenanceEvents[i].Upcoming[v].Description || + u.ScheduledStartTime != cs.MaintenanceEvents[i].Upcoming[v].ScheduledStartTime || + u.ScheduledEndTime != cs.MaintenanceEvents[i].Upcoming[v].ScheduledEndTime || + u.ScheduledStartTimeMax != cs.MaintenanceEvents[i].Upcoming[v].ScheduledStartTimeMax || + u.ScheduledStartTimeMin != cs.MaintenanceEvents[i].Upcoming[v].ScheduledStartTimeMin || + u.IsFinalized != cs.MaintenanceEvents[i].Upcoming[v].IsFinalized || + u.StartTime != cs.MaintenanceEvents[i].Upcoming[v].StartTime || + u.EndTime != cs.MaintenanceEvents[i].Upcoming[v].EndTime || + u.Outcome != cs.MaintenanceEvents[i].Upcoming[v].Outcome { + return false } } } - return true } @@ -509,6 +579,28 @@ func (c *Cluster) CloudProviderSettingsFromInstAPI(iDC models.DataCentre) (setti return } +func (c *Cluster) CloudProviderSettingsFromInstAPIv1(iProviders []*models.ClusterProviderV1) (accountName string, settings []*CloudProviderSettings) { + for _, iProvider := range iProviders { + accountName = iProvider.AccountName + switch iProvider.Name { + case models.AWSVPC: + settings = append(settings, &CloudProviderSettings{ + CustomVirtualNetworkID: iProvider.CustomVirtualNetworkID, + DiskEncryptionKey: iProvider.DiskEncryptionKey, + }) + case models.GCP: + settings = append(settings, &CloudProviderSettings{ + CustomVirtualNetworkID: iProvider.CustomVirtualNetworkID, + }) + case models.AZUREAZ: + settings = append(settings, &CloudProviderSettings{ + ResourceGroup: iProvider.ResourceGroup, + }) + } + } + return +} + func isCloudProviderSettingsEmpty(iDC models.DataCentre) bool { var empty bool @@ -536,28 +628,6 @@ func isCloudProviderSettingsEmpty(iDC models.DataCentre) bool { return true } -func (c *Cluster) CloudProviderSettingsFromInstAPIv1(iProviders []*models.ClusterProviderV1) (accountName string, settings []*CloudProviderSettings) { - for _, iProvider := range iProviders { - accountName = iProvider.AccountName - switch iProvider.Name { - case models.AWSVPC: - settings = append(settings, &CloudProviderSettings{ - CustomVirtualNetworkID: iProvider.CustomVirtualNetworkID, - DiskEncryptionKey: iProvider.DiskEncryptionKey, - }) - case models.GCP: - settings = append(settings, &CloudProviderSettings{ - CustomVirtualNetworkID: iProvider.CustomVirtualNetworkID, - }) - case models.AZUREAZ: - settings = append(settings, &CloudProviderSettings{ - ResourceGroup: iProvider.ResourceGroup, - }) - } - } - return -} - func (cs *ClusterStatus) NodesFromInstAPI(iNodes []*models.Node) (nodes []*Node) { for _, iNode := range iNodes { nodes = append(nodes, &Node{ diff --git a/apis/clusters/v1beta1/zz_generated.deepcopy.go b/apis/clusters/v1beta1/zz_generated.deepcopy.go index aeedbf2bb..476af3035 100644 --- a/apis/clusters/v1beta1/zz_generated.deepcopy.go +++ b/apis/clusters/v1beta1/zz_generated.deepcopy.go @@ -23,6 +23,7 @@ package v1beta1 import ( "encoding/json" + clusterresourcesv1beta1 "github.com/instaclustr/operator/apis/clusterresources/v1beta1" "k8s.io/apimachinery/pkg/runtime" ) @@ -593,12 +594,12 @@ func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { } if in.MaintenanceEvents != nil { in, out := &in.MaintenanceEvents, &out.MaintenanceEvents - *out = make([]*MaintenanceEvent, len(*in)) + *out = make([]*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(MaintenanceEvent) - **out = **in + *out = new(clusterresourcesv1beta1.ClusteredMaintenanceEventStatus) + (*in).DeepCopyInto(*out) } } } @@ -614,6 +615,54 @@ func (in *ClusterStatus) DeepCopy() *ClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusteredMaintenanceEvent) DeepCopyInto(out *ClusteredMaintenanceEvent) { + *out = *in + if in.InProgress != nil { + in, out := &in.InProgress, &out.InProgress + *out = make([]*MaintenanceEvent, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MaintenanceEvent) + **out = **in + } + } + } + if in.Past != nil { + in, out := &in.Past, &out.Past + *out = make([]*MaintenanceEvent, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MaintenanceEvent) + **out = **in + } + } + } + if in.Upcoming != nil { + in, out := &in.Upcoming, &out.Upcoming + *out = make([]*MaintenanceEvent, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MaintenanceEvent) + **out = **in + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusteredMaintenanceEvent. +func (in *ClusteredMaintenanceEvent) DeepCopy() *ClusteredMaintenanceEvent { + if in == nil { + return nil + } + out := new(ClusteredMaintenanceEvent) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CustomConnectors) DeepCopyInto(out *CustomConnectors) { *out = *in diff --git a/config/crd/bases/clusterresources.instaclustr.com_maintenanceevents.yaml b/config/crd/bases/clusterresources.instaclustr.com_maintenanceevents.yaml index 248a0492c..903af717d 100644 --- a/config/crd/bases/clusterresources.instaclustr.com_maintenanceevents.yaml +++ b/config/crd/bases/clusterresources.instaclustr.com_maintenanceevents.yaml @@ -40,40 +40,34 @@ spec: maintenanceEventsReschedule: items: properties: - scheduleId: + maintenanceEventId: type: string scheduledStartTime: type: string required: - - scheduleId + - maintenanceEventId - scheduledStartTime type: object type: array required: - clusterId + - maintenanceEventsReschedule type: object status: description: MaintenanceEventsStatus defines the observed state of MaintenanceEvents properties: - eventsStatuses: - items: - properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string - type: object - type: array + rescheduled: + properties: + maintenanceEventId: + type: string + scheduledStartTime: + type: string + required: + - maintenanceEventId + - scheduledStartTime + type: object + required: + - rescheduled type: object type: object served: true diff --git a/config/crd/bases/clusters.instaclustr.com_cadences.yaml b/config/crd/bases/clusters.instaclustr.com_cadences.yaml index f87d635d0..031a29d2f 100644 --- a/config/crd/bases/clusters.instaclustr.com_cadences.yaml +++ b/config/crd/bases/clusters.instaclustr.com_cadences.yaml @@ -104,6 +104,8 @@ spec: - nodesNumber - region type: object + maxItems: 1 + minItems: 1 type: array description: type: string @@ -334,20 +336,85 @@ spec: maintenanceEvents: items: properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string + Upcoming: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + inProgress: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + past: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + required: + - Upcoming + - inProgress + - past type: object type: array options: diff --git a/config/crd/bases/clusters.instaclustr.com_cassandras.yaml b/config/crd/bases/clusters.instaclustr.com_cassandras.yaml index a53b68e77..375742f23 100644 --- a/config/crd/bases/clusters.instaclustr.com_cassandras.yaml +++ b/config/crd/bases/clusters.instaclustr.com_cassandras.yaml @@ -248,20 +248,85 @@ spec: maintenanceEvents: items: properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string + Upcoming: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + inProgress: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + past: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + required: + - Upcoming + - inProgress + - past type: object type: array options: diff --git a/config/crd/bases/clusters.instaclustr.com_kafkaconnects.yaml b/config/crd/bases/clusters.instaclustr.com_kafkaconnects.yaml index 7b1ef9981..a2254ad11 100644 --- a/config/crd/bases/clusters.instaclustr.com_kafkaconnects.yaml +++ b/config/crd/bases/clusters.instaclustr.com_kafkaconnects.yaml @@ -303,20 +303,85 @@ spec: maintenanceEvents: items: properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string + Upcoming: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + inProgress: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + past: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + required: + - Upcoming + - inProgress + - past type: object type: array options: diff --git a/config/crd/bases/clusters.instaclustr.com_kafkas.yaml b/config/crd/bases/clusters.instaclustr.com_kafkas.yaml index 07c923f6c..052a1820c 100644 --- a/config/crd/bases/clusters.instaclustr.com_kafkas.yaml +++ b/config/crd/bases/clusters.instaclustr.com_kafkas.yaml @@ -95,6 +95,7 @@ spec: - region type: object maxItems: 1 + minItems: 1 type: array dedicatedZookeeper: description: Provision additional dedicated nodes for Apache Zookeeper @@ -296,20 +297,85 @@ spec: maintenanceEvents: items: properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string + Upcoming: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + inProgress: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + past: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + required: + - Upcoming + - inProgress + - past type: object type: array options: diff --git a/config/crd/bases/clusters.instaclustr.com_opensearches.yaml b/config/crd/bases/clusters.instaclustr.com_opensearches.yaml index e250c4814..a8edbbba6 100644 --- a/config/crd/bases/clusters.instaclustr.com_opensearches.yaml +++ b/config/crd/bases/clusters.instaclustr.com_opensearches.yaml @@ -282,20 +282,85 @@ spec: maintenanceEvents: items: properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string + Upcoming: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + inProgress: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + past: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + required: + - Upcoming + - inProgress + - past type: object type: array options: diff --git a/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml b/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml index 2d0fa3286..deadcecbf 100644 --- a/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml +++ b/config/crd/bases/clusters.instaclustr.com_postgresqls.yaml @@ -246,20 +246,85 @@ spec: maintenanceEvents: items: properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string + Upcoming: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + inProgress: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + past: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + required: + - Upcoming + - inProgress + - past type: object type: array options: diff --git a/config/crd/bases/clusters.instaclustr.com_redis.yaml b/config/crd/bases/clusters.instaclustr.com_redis.yaml index 82ff9c2fd..ad58fdfbc 100644 --- a/config/crd/bases/clusters.instaclustr.com_redis.yaml +++ b/config/crd/bases/clusters.instaclustr.com_redis.yaml @@ -245,20 +245,85 @@ spec: maintenanceEvents: items: properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string + Upcoming: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + inProgress: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + past: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + required: + - Upcoming + - inProgress + - past type: object type: array options: diff --git a/config/crd/bases/clusters.instaclustr.com_zookeepers.yaml b/config/crd/bases/clusters.instaclustr.com_zookeepers.yaml index 0dbff225b..b8dacaaca 100644 --- a/config/crd/bases/clusters.instaclustr.com_zookeepers.yaml +++ b/config/crd/bases/clusters.instaclustr.com_zookeepers.yaml @@ -180,20 +180,85 @@ spec: maintenanceEvents: items: properties: - description: - type: string - id: - type: string - isFinalized: - type: boolean - scheduledEndTime: - type: string - scheduledStartTime: - type: string - scheduledStartTimeMax: - type: string - scheduledStartTimeMin: - type: string + Upcoming: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + inProgress: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + past: + items: + properties: + description: + type: string + endTime: + type: string + id: + type: string + isFinalized: + type: boolean + outcome: + type: string + scheduledEndTime: + type: string + scheduledStartTime: + type: string + scheduledStartTimeMax: + type: string + scheduledStartTimeMin: + type: string + startTime: + type: string + type: object + type: array + required: + - Upcoming + - inProgress + - past type: object type: array options: diff --git a/config/samples/clusters_v1beta1_cassandra.yaml b/config/samples/clusters_v1beta1_cassandra.yaml index 13aad4f35..d79e56e8a 100644 --- a/config/samples/clusters_v1beta1_cassandra.yaml +++ b/config/samples/clusters_v1beta1_cassandra.yaml @@ -3,7 +3,7 @@ kind: Cassandra metadata: name: cassandra-cluster spec: - name: "username-Cassandra" + name: "danylo-Cassandra" version: "4.0.10" privateNetworkCluster: false dataCentres: diff --git a/controllers/clusterresources/maintenanceevents_controller.go b/controllers/clusterresources/maintenanceevents_controller.go index 26afd2e54..b70b964b1 100644 --- a/controllers/clusterresources/maintenanceevents_controller.go +++ b/controllers/clusterresources/maintenanceevents_controller.go @@ -21,12 +21,10 @@ import ( 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" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/predicate" @@ -69,204 +67,126 @@ func (r *MaintenanceEventsReconciler) Reconcile(ctx context.Context, req ctrl.Re l.Info("Maintenance Event resource is not found", "request", req, ) - return models.ExitReconcile, nil } - l.Error(err, "Cannot get Maintenance Event resource", "request", req, ) - return models.ReconcileRequeue, nil } - patch := me.NewPatch() - if me.DeletionTimestamp != nil { - r.EventRecorder.Eventf( - me, models.Normal, models.DeletionStarted, - "Exclusion windows deletion request is sent to the Instaclustr API.", - ) - - r.Scheduler.RemoveJob(me.GetJobID(scheduler.StatusChecker)) - controllerutil.RemoveFinalizer(me, models.DeletionFinalizer) - err = r.Patch(ctx, me, patch) + if len(me.Spec.MaintenanceEventsReschedules) == 0 { + err = r.Client.Delete(ctx, me) if err != nil { - l.Error(err, "Cannot patch Maintenance Event resource", - "resource", me, + l.Error(err, + "Cannot delete Maintenance Events resource from K8s cluster", + "Maintenance Events spec", me.Spec, ) - r.EventRecorder.Eventf( - me, models.Warning, models.PatchFailed, - "Resource patch is failed. Reason: %v", + me, models.Warning, models.DeletionFailed, + "Resource deletion is failed. Reason: %v", err, ) return models.ReconcileRequeue, nil } - - return models.ExitReconcile, nil - } - - err = r.reconcileMaintenanceEventsReschedules(me) - if err != nil { - l.Error(err, "Cannot reconcile Maintenance Events Reschedules", - "spec", me.Spec, - ) - r.EventRecorder.Eventf( - me, models.Warning, models.UpdateFailed, - "Maintenance events update is failed. Reason: %v", - err, - ) - return models.ReconcileRequeue, nil - } - - err = r.Status().Patch(ctx, me, patch) - if err != nil { - l.Error(err, "Cannot patch Maintenance Event status", - "status", me.Status, + me, models.Normal, models.DeletionStarted, + "Resource is deleted.", ) - - r.EventRecorder.Eventf( - me, models.Warning, models.PatchFailed, - "Resource status patch is failed. Reason: %v", - err, + l.Info( + "Maintenance Events were rescheduled, resource was deleted", + "Maintenance Events spec", me.Spec, ) - return models.ReconcileRequeue, nil - } - - controllerutil.AddFinalizer(me, models.DeletionFinalizer) - err = r.Patch(ctx, me, patch) - if err != nil { - l.Error(err, "Cannot patch Maintenance Event status", - "status", me.Status, - ) - - r.EventRecorder.Eventf( - me, models.Warning, models.PatchFailed, - "Resource patch is failed. Reason: %v", - err, - ) - return models.ReconcileRequeue, nil + return models.ExitReconcile, nil } - err = r.startMaintenanceEventStatusJob(me) + patch := me.NewPatch() + mEvents, err := r.API.GetMaintenanceEvents(me.Spec.ClusterID, models.UpcomingME) if err != nil { - l.Error(err, "Cannot start Maintenance Event status job", - "spec", me.Spec, + l.Error(err, + "Cannot get Maintenance Event list", + "rescheduledEvent", me.Status.RescheduledEvent, ) - r.EventRecorder.Eventf( - me, models.Warning, models.CreationFailed, - "Resource status check job is failed. Reason: %v", + me, models.Warning, models.FetchFailed, + "Fetch resource from the Instaclustr API is failed. Reason: %v", err, ) return models.ReconcileRequeue, nil } - r.EventRecorder.Eventf( - me, models.Normal, models.Created, - "Cluster maintenance events check job is started", - ) - - l.Info("Maintenance Event resource was reconciled", - "spec", me.Spec, - "status", me.Status, - ) - - return models.ExitReconcile, nil -} - -func (r *MaintenanceEventsReconciler) startMaintenanceEventStatusJob(me *v1beta1.MaintenanceEvents) error { - job := r.newWatchStatusJob(me) - - err := r.Scheduler.ScheduleJob(me.GetJobID(scheduler.StatusChecker), scheduler.ClusterStatusInterval, job) - if err != nil { - return err - } - - return nil -} - -func (r *MaintenanceEventsReconciler) newWatchStatusJob(me *v1beta1.MaintenanceEvents) scheduler.Job { - l := log.Log.WithValues("component", "MaintenanceEventStatusJob") - return func() error { - err := r.Get(context.TODO(), types.NamespacedName{ - Name: me.Name, - Namespace: me.Namespace, - }, me) - if err != nil { - l.Error(err, "Cannot get Maintenance Events resource", - "resource", me, - ) - - return err - } - - var updated bool - patch := me.NewPatch() - instMEventsStatuses, err := r.API.GetMaintenanceEventsStatuses(me.Spec.ClusterID) - if err != nil { - l.Error(err, "Cannot get Maintenance Events statuses", - "resource", me, - ) - - return err - } - - if !me.AreMEventsStatusesEqual(instMEventsStatuses) { - me.Status.EventsStatuses = instMEventsStatuses - updated = true - } + for _, meStatus := range mEvents { + if me.Status.RescheduledEvent.MaintenanceEventId == "" && !meStatus.IsFinalized { + mEvent := &v1beta1.MaintenanceEventReschedule{ + MaintenanceEventId: me.Spec.MaintenanceEventsReschedules[len(me.Spec.MaintenanceEventsReschedules)-1].MaintenanceEventId, + } + me.Status.RescheduledEvent.MaintenanceEventId = mEvent.MaintenanceEventId - if updated { - err = r.Status().Patch(context.TODO(), me, patch) + err = r.API.RescheduleMaintenanceEvent(mEvent) if err != nil { - l.Error(err, "Cannot get Maintenance Events resource status", - "resource", me, + l.Error(err, + "Cannot start Maintenance Event reschedule process", + "Maintenance Event ID", mEvent.MaintenanceEventId, ) - - return err + r.EventRecorder.Eventf( + me, models.Warning, models.CreationFailed, + "Resource creation on the Instaclustr is failed. Reason: %v", + err, + ) + return models.ReconcileRequeue, nil } - l.Info("Maintenance Events resource status was updated", - "resource", me, + r.EventRecorder.Eventf( + me, models.Normal, models.Created, + "Resource reschedule request is sent. Maintenance Event ID: %s", + me.Status.RescheduledEvent.MaintenanceEventId, ) - } - - return nil - } -} -func (r *MaintenanceEventsReconciler) reconcileMaintenanceEventsReschedules(mEvents *v1beta1.MaintenanceEvents) error { - var updatedMEventsStatuses []*v1beta1.MaintenanceEventStatus - instMEvents, err := r.API.GetMaintenanceEventsStatuses(mEvents.Spec.ClusterID) - if err != nil { - return err - } - - for _, k8sMEvent := range mEvents.Spec.MaintenanceEventsReschedules { - for _, instMEvent := range instMEvents { - if instMEvent.IsFinalized { - updatedMEventsStatuses = append(updatedMEventsStatuses, instMEvent) - - break + err = r.Status().Patch(ctx, me, patch) + if err != nil { + l.Error(err, + "Cannot patch Maintenance Event status", + "Maintenance Event ID", me.Status.RescheduledEvent.MaintenanceEventId, + ) + r.EventRecorder.Eventf( + me, models.Warning, models.PatchFailed, + "Resource status patch is failed. Reason: %v", + err, + ) + return models.ReconcileRequeue, nil } - if k8sMEvent.ScheduleID == instMEvent.ID && - (k8sMEvent.ScheduledStartTime != instMEvent.ScheduledStartTime) { - updatedMEventStatus, err := r.API.UpdateMaintenanceEvent(*k8sMEvent) - if err != nil { - return err - } + me.Status.RescheduledEvent.MaintenanceEventId = "" + err = r.Status().Patch(ctx, me, patch) + if err != nil { + l.Error(err, + "Cannot patch MaintenanceEvent status", + "Maintenance Event ID", me.Status.RescheduledEvent.MaintenanceEventId, + ) + r.EventRecorder.Eventf( + me, models.Warning, models.PatchFailed, + "Resource status patch is failed. Reason: %v", + err, + ) + return models.ReconcileRequeue, nil + } - updatedMEventsStatuses = append(updatedMEventsStatuses, updatedMEventStatus) + me.Spec.MaintenanceEventsReschedules = me.Spec.MaintenanceEventsReschedules[:len(me.Spec.MaintenanceEventsReschedules)-1] + err = r.Patch(ctx, me, patch) + if err != nil { + l.Error(err, "Cannot patch Maintenance Event", + "spec", me.Spec, + ) + r.EventRecorder.Eventf( + me, models.Warning, models.PatchFailed, + "Resource patch is failed. Reason: %v", + err, + ) + return models.ReconcileRequeue, nil } } } - - mEvents.Status.EventsStatuses = updatedMEventsStatuses - - return nil + return models.ExitReconcile, nil } // SetupWithManager sets up the controller with the Manager. diff --git a/controllers/clusters/cadence_controller.go b/controllers/clusters/cadence_controller.go index 250f3f691..de64f4c61 100644 --- a/controllers/clusters/cadence_controller.go +++ b/controllers/clusters/cadence_controller.go @@ -36,6 +36,7 @@ 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/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" @@ -904,35 +905,15 @@ func (r *CadenceReconciler) newWatchStatusJob(cadence *v1beta1.Cadence) schedule r.EventRecorder.Eventf(cadence, models.Warning, models.ExternalChanges, msgDiffSpecs) } - maintEvents, err := r.API.GetMaintenanceEvents(cadence.Status.ID) + err = r.reconcileMaintenanceEvents(context.Background(), cadence) if err != nil { - l.Error(err, "Cannot get Cadence cluster maintenance events", + l.Error(err, "Cannot reconcile cluster maintenance events", "cluster name", cadence.Spec.Name, "cluster ID", cadence.Status.ID, ) - return err } - if !cadence.Status.AreMaintenanceEventsEqual(maintEvents) { - patch := cadence.NewPatch() - cadence.Status.MaintenanceEvents = maintEvents - err = r.Status().Patch(context.TODO(), cadence, patch) - if err != nil { - l.Error(err, "Cannot patch Cadence cluster maintenance events", - "cluster name", cadence.Spec.Name, - "cluster ID", cadence.Status.ID, - ) - - return err - } - - l.Info("Cadence cluster maintenance events were updated", - "cluster ID", cadence.Status.ID, - "events", cadence.Status.MaintenanceEvents, - ) - } - return nil } } @@ -1241,3 +1222,46 @@ func (r *CadenceReconciler) SetupWithManager(mgr ctrl.Manager) error { })). Complete(r) } + +func (r *CadenceReconciler) reconcileMaintenanceEvents(ctx context.Context, c *v1beta1.Cadence) error { + l := log.FromContext(ctx) + + inProgressMEStatus, err := r.API.GetMaintenanceEvents(c.Status.ID, models.InProgressME) + if err != nil { + return err + } + + pastMEStatus, err := r.API.GetMaintenanceEvents(c.Status.ID, models.PastME) + if err != nil { + return err + } + + upcomingMEStatus, err := r.API.GetMaintenanceEvents(c.Status.ID, models.UpcomingME) + if err != nil { + return err + } + + iMEStatuses := []*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus{ + { + InProgress: c.Status.MaintenanceEventStatusFromInstAPI(inProgressMEStatus), + Past: c.Status.MaintenanceEventStatusFromInstAPI(pastMEStatus), + Upcoming: c.Status.MaintenanceEventStatusFromInstAPI(upcomingMEStatus), + }, + } + + if !c.Status.AreMaintenanceEventStatusesEqual(iMEStatuses) { + patch := c.NewPatch() + c.Status.MaintenanceEvents = iMEStatuses + err = r.Status().Patch(context.TODO(), c, patch) + if err != nil { + return err + } + + l.Info("Cluster maintenance events were reconciled", + "cluster ID", c.Status.ID, + "events", c.Status.MaintenanceEvents, + ) + } + + return nil +} diff --git a/controllers/clusters/cassandra_controller.go b/controllers/clusters/cassandra_controller.go index 42c8a0576..593180056 100644 --- a/controllers/clusters/cassandra_controller.go +++ b/controllers/clusters/cassandra_controller.go @@ -994,35 +994,15 @@ func (r *CassandraReconciler) newWatchStatusJob(cassandra *v1beta1.Cassandra) sc r.EventRecorder.Eventf(cassandra, models.Warning, models.ExternalChanges, msgDiffSpecs) } - maintEvents, err := r.API.GetMaintenanceEvents(cassandra.Status.ID) + err = r.reconcileMaintenanceEvents(context.Background(), cassandra) if err != nil { - l.Error(err, "Cannot get cluster maintenance events", + l.Error(err, "Cannot reconcile cluster maintenance events", "cluster name", cassandra.Spec.Name, "cluster ID", cassandra.Status.ID, ) - return err } - if !cassandra.Status.AreMaintenanceEventsEqual(maintEvents) { - patch := cassandra.NewPatch() - cassandra.Status.MaintenanceEvents = maintEvents - err = r.Status().Patch(context.TODO(), cassandra, patch) - if err != nil { - l.Error(err, "Cannot patch cluster maintenance events", - "cluster name", cassandra.Spec.Name, - "cluster ID", cassandra.Status.ID, - ) - - return err - } - - l.Info("Cluster maintenance events were updated", - "cluster ID", cassandra.Status.ID, - "events", cassandra.Status.MaintenanceEvents, - ) - } - return nil } } @@ -1224,6 +1204,49 @@ func (r *CassandraReconciler) deleteBackups(ctx context.Context, clusterID, name return nil } +func (r *CassandraReconciler) reconcileMaintenanceEvents(ctx context.Context, c *v1beta1.Cassandra) error { + l := log.FromContext(ctx) + + inProgressMEStatus, err := r.API.GetMaintenanceEvents(c.Status.ID, models.InProgressME) + if err != nil { + return err + } + + pastMEStatus, err := r.API.GetMaintenanceEvents(c.Status.ID, models.PastME) + if err != nil { + return err + } + + upcomingMEStatus, err := r.API.GetMaintenanceEvents(c.Status.ID, models.UpcomingME) + if err != nil { + return err + } + + iMEStatuses := []*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus{ + { + InProgress: c.Status.MaintenanceEventStatusFromInstAPI(inProgressMEStatus), + Past: c.Status.MaintenanceEventStatusFromInstAPI(pastMEStatus), + Upcoming: c.Status.MaintenanceEventStatusFromInstAPI(upcomingMEStatus), + }, + } + + if !c.Status.AreMaintenanceEventStatusesEqual(iMEStatuses) { + patch := c.NewPatch() + c.Status.MaintenanceEvents = iMEStatuses + err = r.Status().Patch(context.TODO(), c, patch) + if err != nil { + return err + } + + l.Info("Cluster maintenance events were reconciled", + "cluster ID", c.Status.ID, + "events", c.Status.MaintenanceEvents, + ) + } + + return nil +} + // SetupWithManager sets up the controller with the Manager. func (r *CassandraReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). diff --git a/controllers/clusters/kafka_controller.go b/controllers/clusters/kafka_controller.go index 9af9c5954..2088a64fc 100644 --- a/controllers/clusters/kafka_controller.go +++ b/controllers/clusters/kafka_controller.go @@ -34,6 +34,7 @@ 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/pkg/exposeservice" @@ -753,35 +754,15 @@ func (r *KafkaReconciler) newWatchStatusJob(kafka *v1beta1.Kafka) scheduler.Job r.EventRecorder.Eventf(kafka, models.Warning, models.ExternalChanges, msgDiffSpecs) } - maintEvents, err := r.API.GetMaintenanceEvents(kafka.Status.ID) + err = r.reconcileMaintenanceEvents(context.Background(), kafka) if err != nil { - l.Error(err, "Cannot get cluster maintenance events", + l.Error(err, "Cannot reconcile cluster maintenance events", "cluster name", kafka.Spec.Name, "cluster ID", kafka.Status.ID, ) - return err } - if !kafka.Status.AreMaintenanceEventsEqual(maintEvents) { - patch := kafka.NewPatch() - kafka.Status.MaintenanceEvents = maintEvents - err = r.Status().Patch(context.TODO(), kafka, patch) - if err != nil { - l.Error(err, "Cannot patch cluster maintenance events", - "cluster name", kafka.Spec.Name, - "cluster ID", kafka.Status.ID, - ) - - return err - } - - l.Info("Cluster maintenance events were updated", - "cluster ID", kafka.Status.ID, - "events", kafka.Status.MaintenanceEvents, - ) - } - return nil } } @@ -945,3 +926,46 @@ func (r *KafkaReconciler) SetupWithManager(mgr ctrl.Manager) error { }, })).Complete(r) } + +func (r *KafkaReconciler) reconcileMaintenanceEvents(ctx context.Context, k *v1beta1.Kafka) error { + l := log.FromContext(ctx) + + inProgressMEStatus, err := r.API.GetMaintenanceEvents(k.Status.ID, models.InProgressME) + if err != nil { + return err + } + + pastMEStatus, err := r.API.GetMaintenanceEvents(k.Status.ID, models.PastME) + if err != nil { + return err + } + + upcomingMEStatus, err := r.API.GetMaintenanceEvents(k.Status.ID, models.UpcomingME) + if err != nil { + return err + } + + iMEStatuses := []*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus{ + { + InProgress: k.Status.MaintenanceEventStatusFromInstAPI(inProgressMEStatus), + Past: k.Status.MaintenanceEventStatusFromInstAPI(pastMEStatus), + Upcoming: k.Status.MaintenanceEventStatusFromInstAPI(upcomingMEStatus), + }, + } + + if !k.Status.AreMaintenanceEventStatusesEqual(iMEStatuses) { + patch := k.NewPatch() + k.Status.MaintenanceEvents = iMEStatuses + err = r.Status().Patch(context.TODO(), k, patch) + if err != nil { + return err + } + + l.Info("Cluster maintenance events were reconciled", + "cluster ID", k.Status.ID, + "events", k.Status.MaintenanceEvents, + ) + } + + return nil +} diff --git a/controllers/clusters/kafkaconnect_controller.go b/controllers/clusters/kafkaconnect_controller.go index 3af39fb4b..a0bf0be77 100644 --- a/controllers/clusters/kafkaconnect_controller.go +++ b/controllers/clusters/kafkaconnect_controller.go @@ -33,6 +33,7 @@ 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/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" @@ -572,35 +573,15 @@ func (r *KafkaConnectReconciler) newWatchStatusJob(kc *v1beta1.KafkaConnect) sch r.EventRecorder.Eventf(kc, models.Warning, models.ExternalChanges, msgDiffSpecs) } - maintEvents, err := r.API.GetMaintenanceEvents(kc.Status.ID) + err = r.reconcileMaintenanceEvents(context.Background(), kc) if err != nil { - l.Error(err, "Cannot get Kafka Connect cluster maintenance events", + l.Error(err, "Cannot reconcile cluster maintenance events", "cluster name", kc.Spec.Name, "cluster ID", kc.Status.ID, ) - return err } - if !kc.Status.AreMaintenanceEventsEqual(maintEvents) { - patch := kc.NewPatch() - kc.Status.MaintenanceEvents = maintEvents - err = r.Status().Patch(context.TODO(), kc, patch) - if err != nil { - l.Error(err, "Cannot patch Kafka Connect cluster maintenance events", - "cluster name", kc.Spec.Name, - "cluster ID", kc.Status.ID, - ) - - return err - } - - l.Info("Kafka Connect cluster maintenance events were updated", - "cluster ID", kc.Status.ID, - "events", kc.Status.MaintenanceEvents, - ) - } - return nil } } @@ -644,3 +625,46 @@ func (r *KafkaConnectReconciler) SetupWithManager(mgr ctrl.Manager) error { }, })).Complete(r) } + +func (r *KafkaConnectReconciler) reconcileMaintenanceEvents(ctx context.Context, kc *v1beta1.KafkaConnect) error { + l := log.FromContext(ctx) + + inProgressMEStatus, err := r.API.GetMaintenanceEvents(kc.Status.ID, models.InProgressME) + if err != nil { + return err + } + + pastMEStatus, err := r.API.GetMaintenanceEvents(kc.Status.ID, models.PastME) + if err != nil { + return err + } + + upcomingMEStatus, err := r.API.GetMaintenanceEvents(kc.Status.ID, models.UpcomingME) + if err != nil { + return err + } + + iMEStatuses := []*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus{ + { + InProgress: kc.Status.MaintenanceEventStatusFromInstAPI(inProgressMEStatus), + Past: kc.Status.MaintenanceEventStatusFromInstAPI(pastMEStatus), + Upcoming: kc.Status.MaintenanceEventStatusFromInstAPI(upcomingMEStatus), + }, + } + + if !kc.Status.AreMaintenanceEventStatusesEqual(iMEStatuses) { + patch := kc.NewPatch() + kc.Status.MaintenanceEvents = iMEStatuses + err = r.Status().Patch(context.TODO(), kc, patch) + if err != nil { + return err + } + + l.Info("Cluster maintenance events were reconciled", + "cluster ID", kc.Status.ID, + "events", kc.Status.MaintenanceEvents, + ) + } + + return nil +} diff --git a/controllers/clusters/opensearch_controller.go b/controllers/clusters/opensearch_controller.go index dcbcd887b..e744d1fb6 100644 --- a/controllers/clusters/opensearch_controller.go +++ b/controllers/clusters/opensearch_controller.go @@ -682,16 +682,6 @@ func (r *OpenSearchReconciler) newWatchStatusJob(o *v1beta1.OpenSearch) schedule } } - maintEvents, err := r.API.GetMaintenanceEvents(o.Status.ID) - if err != nil { - l.Error(err, "Cannot get OpenSearch cluster maintenance events", - "cluster name", o.Spec.Name, - "cluster ID", o.Status.ID, - ) - - return err - } - if iO.Status.CurrentClusterOperationStatus == models.NoOperation && o.Annotations[models.UpdateQueuedAnnotation] != models.True && !o.Spec.IsEqual(iO.Spec) { @@ -717,23 +707,13 @@ func (r *OpenSearchReconciler) newWatchStatusJob(o *v1beta1.OpenSearch) schedule r.EventRecorder.Eventf(o, models.Warning, models.ExternalChanges, msgDiffSpecs) } - if !o.Status.AreMaintenanceEventsEqual(maintEvents) { - patch := o.NewPatch() - o.Status.MaintenanceEvents = maintEvents - err = r.Status().Patch(context.TODO(), o, patch) - if err != nil { - l.Error(err, "Cannot patch OpenSearch cluster maintenance events", - "cluster name", o.Spec.Name, - "cluster ID", o.Status.ID, - ) - - return err - } - - l.Info("OpenSearch cluster maintenance events were updated", + err = r.reconcileMaintenanceEvents(context.Background(), o) + if err != nil { + l.Error(err, "Cannot reconcile cluster maintenance events", + "cluster name", o.Spec.Name, "cluster ID", o.Status.ID, - "events", o.Status.MaintenanceEvents, ) + return err } return nil @@ -1206,3 +1186,46 @@ func (r *OpenSearchReconciler) SetupWithManager(mgr ctrl.Manager) error { })). Complete(r) } + +func (r *OpenSearchReconciler) reconcileMaintenanceEvents(ctx context.Context, o *v1beta1.OpenSearch) error { + l := log.FromContext(ctx) + + inProgressMEStatus, err := r.API.GetMaintenanceEvents(o.Status.ID, models.InProgressME) + if err != nil { + return err + } + + pastMEStatus, err := r.API.GetMaintenanceEvents(o.Status.ID, models.PastME) + if err != nil { + return err + } + + upcomingMEStatus, err := r.API.GetMaintenanceEvents(o.Status.ID, models.UpcomingME) + if err != nil { + return err + } + + iMEStatuses := []*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus{ + { + InProgress: o.Status.MaintenanceEventStatusFromInstAPI(inProgressMEStatus), + Past: o.Status.MaintenanceEventStatusFromInstAPI(pastMEStatus), + Upcoming: o.Status.MaintenanceEventStatusFromInstAPI(upcomingMEStatus), + }, + } + + if !o.Status.AreMaintenanceEventStatusesEqual(iMEStatuses) { + patch := o.NewPatch() + o.Status.MaintenanceEvents = iMEStatuses + err = r.Status().Patch(context.TODO(), o, patch) + if err != nil { + return err + } + + l.Info("Cluster maintenance events were reconciled", + "cluster ID", o.Status.ID, + "events", o.Status.MaintenanceEvents, + ) + } + + return nil +} diff --git a/controllers/clusters/postgresql_controller.go b/controllers/clusters/postgresql_controller.go index 64e538d5e..ddcac820e 100644 --- a/controllers/clusters/postgresql_controller.go +++ b/controllers/clusters/postgresql_controller.go @@ -901,16 +901,6 @@ func (r *PostgreSQLReconciler) newWatchStatusJob(pg *v1beta1.PostgreSQL) schedul } } - maintEvents, err := r.API.GetMaintenanceEvents(pg.Status.ID) - if err != nil { - l.Error(err, "Cannot get PostgreSQL cluster maintenance events", - "cluster name", pg.Spec.Name, - "cluster ID", pg.Status.ID, - ) - - return err - } - if iPg.Status.CurrentClusterOperationStatus == models.NoOperation && pg.Annotations[models.UpdateQueuedAnnotation] != models.True && !pg.Spec.IsEqual(iPg.Spec) { @@ -935,23 +925,13 @@ func (r *PostgreSQLReconciler) newWatchStatusJob(pg *v1beta1.PostgreSQL) schedul r.EventRecorder.Eventf(pg, models.Warning, models.ExternalChanges, msgDiffSpecs) } - if !pg.Status.AreMaintenanceEventsEqual(maintEvents) { - patch := pg.NewPatch() - pg.Status.MaintenanceEvents = maintEvents - err = r.Status().Patch(context.TODO(), pg, patch) - if err != nil { - l.Error(err, "Cannot patch PostgreSQL cluster maintenance events", - "cluster name", pg.Spec.Name, - "cluster ID", pg.Status.ID, - ) - - return err - } - - l.Info("PostgreSQL cluster maintenance events were updated", + err = r.reconcileMaintenanceEvents(context.Background(), pg) + if err != nil { + l.Error(err, "Cannot reconcile cluster maintenance events", + "cluster name", pg.Spec.Name, "cluster ID", pg.Status.ID, - "events", pg.Status.MaintenanceEvents, ) + return err } return nil @@ -1394,3 +1374,46 @@ func (r *PostgreSQLReconciler) SetupWithManager(mgr ctrl.Manager) error { ). Complete(r) } + +func (r *PostgreSQLReconciler) reconcileMaintenanceEvents(ctx context.Context, pg *v1beta1.PostgreSQL) error { + l := log.FromContext(ctx) + + inProgressMEStatus, err := r.API.GetMaintenanceEvents(pg.Status.ID, models.InProgressME) + if err != nil { + return err + } + + pastMEStatus, err := r.API.GetMaintenanceEvents(pg.Status.ID, models.PastME) + if err != nil { + return err + } + + upcomingMEStatus, err := r.API.GetMaintenanceEvents(pg.Status.ID, models.UpcomingME) + if err != nil { + return err + } + + iMEStatuses := []*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus{ + { + InProgress: pg.Status.MaintenanceEventStatusFromInstAPI(inProgressMEStatus), + Past: pg.Status.MaintenanceEventStatusFromInstAPI(pastMEStatus), + Upcoming: pg.Status.MaintenanceEventStatusFromInstAPI(upcomingMEStatus), + }, + } + + if !pg.Status.AreMaintenanceEventStatusesEqual(iMEStatuses) { + patch := pg.NewPatch() + pg.Status.MaintenanceEvents = iMEStatuses + err = r.Status().Patch(context.TODO(), pg, patch) + if err != nil { + return err + } + + l.Info("Cluster maintenance events were reconciled", + "cluster ID", pg.Status.ID, + "events", pg.Status.MaintenanceEvents, + ) + } + + return nil +} diff --git a/controllers/clusters/redis_controller.go b/controllers/clusters/redis_controller.go index ec6ad15b3..fd84d8a31 100644 --- a/controllers/clusters/redis_controller.go +++ b/controllers/clusters/redis_controller.go @@ -1008,35 +1008,15 @@ func (r *RedisReconciler) newWatchStatusJob(redis *v1beta1.Redis) scheduler.Job r.EventRecorder.Eventf(redis, models.Warning, models.ExternalChanges, msgDiffSpecs) } - maintEvents, err := r.API.GetMaintenanceEvents(redis.Status.ID) + err = r.reconcileMaintenanceEvents(context.Background(), redis) if err != nil { - l.Error(err, "Cannot get Redis cluster maintenance events", + l.Error(err, "Cannot reconcile cluster maintenance events", "cluster name", redis.Spec.Name, "cluster ID", redis.Status.ID, ) - return err } - if !redis.Status.AreMaintenanceEventsEqual(maintEvents) { - patch := redis.NewPatch() - redis.Status.MaintenanceEvents = maintEvents - err = r.Status().Patch(context.TODO(), redis, patch) - if err != nil { - l.Error(err, "Cannot patch Redis cluster maintenance events", - "cluster name", redis.Spec.Name, - "cluster ID", redis.Status.ID, - ) - - return err - } - - l.Info("Redis cluster maintenance events were updated", - "cluster ID", redis.Status.ID, - "events", redis.Status.MaintenanceEvents, - ) - } - return nil } } @@ -1243,3 +1223,46 @@ func (r *RedisReconciler) SetupWithManager(mgr ctrl.Manager) error { })). Complete(r) } + +func (r *RedisReconciler) reconcileMaintenanceEvents(ctx context.Context, redis *v1beta1.Redis) error { + l := log.FromContext(ctx) + + inProgressMEStatus, err := r.API.GetMaintenanceEvents(redis.Status.ID, models.InProgressME) + if err != nil { + return err + } + + pastMEStatus, err := r.API.GetMaintenanceEvents(redis.Status.ID, models.PastME) + if err != nil { + return err + } + + upcomingMEStatus, err := r.API.GetMaintenanceEvents(redis.Status.ID, models.UpcomingME) + if err != nil { + return err + } + + iMEStatuses := []*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus{ + { + InProgress: redis.Status.MaintenanceEventStatusFromInstAPI(inProgressMEStatus), + Past: redis.Status.MaintenanceEventStatusFromInstAPI(pastMEStatus), + Upcoming: redis.Status.MaintenanceEventStatusFromInstAPI(upcomingMEStatus), + }, + } + + if !redis.Status.AreMaintenanceEventStatusesEqual(iMEStatuses) { + patch := redis.NewPatch() + redis.Status.MaintenanceEvents = iMEStatuses + err = r.Status().Patch(context.TODO(), redis, patch) + if err != nil { + return err + } + + l.Info("Cluster maintenance events were reconciled", + "cluster ID", redis.Status.ID, + "events", redis.Status.MaintenanceEvents, + ) + } + + return nil +} diff --git a/controllers/clusters/zookeeper_controller.go b/controllers/clusters/zookeeper_controller.go index 977945b3b..eff9dd186 100644 --- a/controllers/clusters/zookeeper_controller.go +++ b/controllers/clusters/zookeeper_controller.go @@ -33,6 +33,7 @@ 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/pkg/exposeservice" "github.com/instaclustr/operator/pkg/instaclustr" @@ -493,35 +494,15 @@ func (r *ZookeeperReconciler) newWatchStatusJob(zook *v1beta1.Zookeeper) schedul r.EventRecorder.Eventf(zook, models.Warning, models.ExternalChanges, msgDiffSpecs) } - maintEvents, err := r.API.GetMaintenanceEvents(zook.Status.ID) + err = r.reconcileMaintenanceEvents(context.Background(), zook) if err != nil { - l.Error(err, "Cannot get Zookeeper cluster maintenance events", + l.Error(err, "Cannot reconcile cluster maintenance events", "cluster name", zook.Spec.Name, "cluster ID", zook.Status.ID, ) - return err } - if !zook.Status.AreMaintenanceEventsEqual(maintEvents) { - patch := zook.NewPatch() - zook.Status.MaintenanceEvents = maintEvents - err = r.Status().Patch(context.TODO(), zook, patch) - if err != nil { - l.Error(err, "Cannot patch Zookeeper cluster maintenance events", - "cluster name", zook.Spec.Name, - "cluster ID", zook.Status.ID, - ) - - return err - } - - l.Info("Zookeeper cluster maintenance events were updated", - "cluster ID", zook.Status.ID, - "events", zook.Status.MaintenanceEvents, - ) - } - return nil } } @@ -614,3 +595,46 @@ func (r *ZookeeperReconciler) SetupWithManager(mgr ctrl.Manager) error { }, })).Complete(r) } + +func (r *ZookeeperReconciler) reconcileMaintenanceEvents(ctx context.Context, z *v1beta1.Zookeeper) error { + l := log.FromContext(ctx) + + inProgressMEStatus, err := r.API.GetMaintenanceEvents(z.Status.ID, models.InProgressME) + if err != nil { + return err + } + + pastMEStatus, err := r.API.GetMaintenanceEvents(z.Status.ID, models.PastME) + if err != nil { + return err + } + + upcomingMEStatus, err := r.API.GetMaintenanceEvents(z.Status.ID, models.UpcomingME) + if err != nil { + return err + } + + iMEStatuses := []*clusterresourcesv1beta1.ClusteredMaintenanceEventStatus{ + { + InProgress: z.Status.MaintenanceEventStatusFromInstAPI(inProgressMEStatus), + Past: z.Status.MaintenanceEventStatusFromInstAPI(pastMEStatus), + Upcoming: z.Status.MaintenanceEventStatusFromInstAPI(upcomingMEStatus), + }, + } + + if !z.Status.AreMaintenanceEventStatusesEqual(iMEStatuses) { + patch := z.NewPatch() + z.Status.MaintenanceEvents = iMEStatuses + err = r.Status().Patch(context.TODO(), z, patch) + if err != nil { + return err + } + + l.Info("Cluster maintenance events were reconciled", + "cluster ID", z.Status.ID, + "events", z.Status.MaintenanceEvents, + ) + } + + return nil +} diff --git a/pkg/instaclustr/client.go b/pkg/instaclustr/client.go index 8cec1412b..21ea6fac1 100644 --- a/pkg/instaclustr/client.go +++ b/pkg/instaclustr/client.go @@ -1329,8 +1329,8 @@ func (c *Client) DeleteExclusionWindow(id string) error { return nil } -func (c *Client) GetMaintenanceEventsStatuses(clusterID string) ([]*clusterresourcesv1beta1.MaintenanceEventStatus, error) { - url := c.serverHostname + MaintenanceEventStatusEndpoint + clusterID +func (c *Client) GetMaintenanceEvents(clusterID, eventType string) ([]*v1beta1.MaintenanceEvent, error) { + url := fmt.Sprintf(MaintenanceEventStatusEndpoint, c.serverHostname, clusterID, eventType) resp, err := c.DoRequest(url, http.MethodGet, nil) if err != nil { @@ -1351,52 +1351,20 @@ func (c *Client) GetMaintenanceEventsStatuses(clusterID string) ([]*clusterresou return nil, fmt.Errorf("status code: %d, message: %s", resp.StatusCode, body) } - statuses := &struct { - MaintenanceEvents []*clusterresourcesv1beta1.MaintenanceEventStatus `json:"maintenanceEvents"` - }{} - err = json.Unmarshal(body, statuses) - if err != nil { - return nil, err - } - - return statuses.MaintenanceEvents, nil -} - -func (c *Client) GetMaintenanceEvents(clusterID string) ([]*v1beta1.MaintenanceEvent, error) { - url := c.serverHostname + MaintenanceEventStatusEndpoint + clusterID - - resp, err := c.DoRequest(url, http.MethodGet, nil) - 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.StatusNotFound { - return nil, NotFound - } - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("status code: %d, message: %s", resp.StatusCode, body) - } - - status := &struct { + holder := []struct { MaintenanceEvents []*v1beta1.MaintenanceEvent `json:"maintenanceEvents"` }{} - err = json.Unmarshal(body, status) + + err = json.Unmarshal(body, &holder) if err != nil { return nil, err } - return status.MaintenanceEvents, nil + return holder[0].MaintenanceEvents, nil } -func (c *Client) UpdateMaintenanceEvent(me clusterresourcesv1beta1.MaintenanceEventRescheduleSpec) (*clusterresourcesv1beta1.MaintenanceEventStatus, error) { - url := c.serverHostname + MaintenanceEventEndpoint + me.ScheduleID +func (c *Client) RescheduleMaintenanceEvent(me *clusterresourcesv1beta1.MaintenanceEventReschedule) error { + url := fmt.Sprintf(MaintenanceEventRescheduleEndpoint, c.serverHostname, me.MaintenanceEventId) requestBody := &struct { ScheduledStartTime string `json:"scheduledStartTime,omitempty"` @@ -1406,31 +1374,25 @@ func (c *Client) UpdateMaintenanceEvent(me clusterresourcesv1beta1.MaintenanceEv data, err := json.Marshal(requestBody) if err != nil { - return nil, err + return err } resp, err := c.DoRequest(url, http.MethodPut, data) if err != nil { - return nil, err + return err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { - return nil, err + return err } if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("me code: %d, message: %s", resp.StatusCode, body) - } - - response := &clusterresourcesv1beta1.MaintenanceEventStatus{} - err = json.Unmarshal(body, response) - if err != nil { - return nil, err + return fmt.Errorf("me code: %d, message: %s", resp.StatusCode, body) } - return response, nil + return nil } func (c *Client) CreateNodeReload(nr *clusterresourcesv1beta1.Node) error { diff --git a/pkg/instaclustr/config.go b/pkg/instaclustr/config.go index f2c768abf..1c0fabb82 100644 --- a/pkg/instaclustr/config.go +++ b/pkg/instaclustr/config.go @@ -66,9 +66,9 @@ const ( APIv1RestoreEndpoint = "%s/provisioning/v1/%s/backups/restore" - ExclusionWindowEndpoint = "/cluster-management/v2/resources/exclusion-windows/v2/" - MaintenanceEventEndpoint = "/v1/maintenance-events/events/" - MaintenanceEventStatusEndpoint = "/v1/maintenance-events/events?clusterId=" + ExclusionWindowEndpoint = "/cluster-management/v2/resources/exclusion-windows/v2/" + MaintenanceEventRescheduleEndpoint = "%s/cluster-management/v2/operations/maintenance-events/%s/v2/reschedule-maintenance-event/v2/" + MaintenanceEventStatusEndpoint = "%s/cluster-management/v2/data-sources/cluster/%s/maintenance-events/v2/%s/v2/" ) const ( diff --git a/pkg/instaclustr/interfaces.go b/pkg/instaclustr/interfaces.go index 77a405923..1a7086175 100644 --- a/pkg/instaclustr/interfaces.go +++ b/pkg/instaclustr/interfaces.go @@ -59,10 +59,9 @@ type API interface { TriggerClusterBackup(url, clusterID string) error CreateExclusionWindow(clusterID string, window *clusterresourcesv1beta1.ExclusionWindowSpec) (string, error) GetExclusionWindowsStatus(windowID string) (string, error) - GetMaintenanceEventsStatuses(clusterID string) ([]*clusterresourcesv1beta1.MaintenanceEventStatus, error) - GetMaintenanceEvents(clusterID string) ([]*v1beta1.MaintenanceEvent, error) DeleteExclusionWindow(id string) error - UpdateMaintenanceEvent(me clusterresourcesv1beta1.MaintenanceEventRescheduleSpec) (*clusterresourcesv1beta1.MaintenanceEventStatus, error) + GetMaintenanceEvents(clusterID, eventType string) ([]*v1beta1.MaintenanceEvent, error) + RescheduleMaintenanceEvent(me *clusterresourcesv1beta1.MaintenanceEventReschedule) error RestorePgCluster(restoreData *v1beta1.PgRestoreFrom) (string, error) RestoreRedisCluster(restoreData *v1beta1.RedisRestoreFrom) (string, error) RestoreOpenSearchCluster(restoreData *v1beta1.OpenSearchRestoreFrom) (string, error) diff --git a/pkg/instaclustr/mock/client.go b/pkg/instaclustr/mock/client.go index 98ed45563..490dcc926 100644 --- a/pkg/instaclustr/mock/client.go +++ b/pkg/instaclustr/mock/client.go @@ -212,20 +212,16 @@ func (c *mockClient) GetExclusionWindowsStatus(windowID string) (string, error) panic("GetExclusionWindowsStatus: is not implemented") } -func (c *mockClient) GetMaintenanceEventsStatuses(clusterID string) ([]*clusterresourcesv1beta1.MaintenanceEventStatus, error) { - panic("GetMaintenanceEventsStatuses: is not implemented") +func (c *mockClient) DeleteExclusionWindow(id string) error { + panic("DeleteExclusionWindow: is not implemented") } -func (c *mockClient) GetMaintenanceEvents(clusterID string) ([]*clustersv1beta1.MaintenanceEvent, error) { +func (c *mockClient) GetMaintenanceEvents(clusterID, eventType string) ([]*clustersv1beta1.MaintenanceEvent, error) { panic("GetMaintenanceEvents: is not implemented") } -func (c *mockClient) DeleteExclusionWindow(id string) error { - panic("DeleteExclusionWindow: is not implemented") -} - -func (c *mockClient) UpdateMaintenanceEvent(me clusterresourcesv1beta1.MaintenanceEventRescheduleSpec) (*clusterresourcesv1beta1.MaintenanceEventStatus, error) { - panic("UpdateMaintenanceEvent: is not implemented") +func (c *mockClient) RescheduleMaintenanceEvent(me *clusterresourcesv1beta1.MaintenanceEventReschedule) error { + panic("GetMaintenanceEvents: is not implemented") } func (c *mockClient) RestorePgCluster(restoreData *clustersv1beta1.PgRestoreFrom) (string, error) { diff --git a/pkg/models/operator.go b/pkg/models/operator.go index 8fb93e50a..2712b5b82 100644 --- a/pkg/models/operator.go +++ b/pkg/models/operator.go @@ -143,6 +143,12 @@ const ( Password = "password" ) +const ( + InProgressME = "in-progress" + PastME = "past" + UpcomingME = "upcoming" +) + const Requeue60 = time.Second * 60 var (