From 84f42322bae9eccdd0342fafff511f3ccb7a9eb2 Mon Sep 17 00:00:00 2001 From: mgianluc Date: Fri, 26 Jul 2024 16:05:21 +0200 Subject: [PATCH] (feat): Add optional schedule for pausing and unpausing the cluster. Introduce optional schedule configuration for pausing and unpausing the cluster. A paused cluster will receive no updates from the management cluster. --- api/v1alpha1/sveltoscluster_type.go | 25 ++++++++ api/v1alpha1/zz_generated.conversion.go | 39 ++++++++++++ api/v1alpha1/zz_generated.deepcopy.go | 28 +++++++++ api/v1beta1/sveltoscluster_type.go | 25 ++++++++ api/v1beta1/zz_generated.deepcopy.go | 28 +++++++++ ...lib.projectsveltos.io_sveltosclusters.yaml | 60 +++++++++++++++++++ lib/crd/sveltosclusters.go | 60 +++++++++++++++++++ ...sveltosclusters.lib.projectsveltos.io.yaml | 60 +++++++++++++++++++ 8 files changed, 325 insertions(+) diff --git a/api/v1alpha1/sveltoscluster_type.go b/api/v1alpha1/sveltoscluster_type.go index 36cf916..b7c5217 100644 --- a/api/v1alpha1/sveltoscluster_type.go +++ b/api/v1alpha1/sveltoscluster_type.go @@ -24,6 +24,18 @@ const ( SveltosClusterKind = "SveltosCluster" ) +type ActiveWindow struct { + // From in Cron format, see https://en.wikipedia.org/wiki/Cron. + // Indicates when to un-pause the cluster (cluster in paused state receives no update from sveltos). + // +kubebuilder:validation:MinLength=1 + From string `json:"from"` + + // To in Cron format, see https://en.wikipedia.org/Cron. + // Indicates when to pause the cluster (cluster in paused state receives no update from sveltos). + // +kubebuilder:validation:MinLength=1 + To string `json:"to"` +} + type TokenRequestRenewalOption struct { // RenewTokenRequestInterval is the interval at which to renew the TokenRequest RenewTokenRequestInterval metav1.Duration `json:"renewTokenRequestInterval"` @@ -50,6 +62,11 @@ type SveltosClusterSpec struct { // ArbitraryData allows for arbitrary nested structures // +optional ArbitraryData map[string]string `json:"data,omitempty"` + + // ActiveWindow is an optional field for automatically pausing and unpausing + // the cluster. + // If not specified, the cluster will not be paused or unpaused automatically. + ActiveWindow *ActiveWindow `json:"activeWindow,omitempty"` } // SveltosClusterStatus defines the status of SveltosCluster @@ -71,6 +88,14 @@ type SveltosClusterStatus struct { // was renewed. // +optional LastReconciledTokenRequestAt string `json:"lastReconciledTokenRequestAt,omitempty"` + + // Information when next unpause cluster is scheduled + // +optional + NextUnpause *metav1.Time `json:"nextUnpause,omitempty"` + + // Information when next pause cluster is scheduled + // +optional + NextPause *metav1.Time `json:"nextPause,omitempty"` } //+kubebuilder:object:root=true diff --git a/api/v1alpha1/zz_generated.conversion.go b/api/v1alpha1/zz_generated.conversion.go index e8c9ea2..e5ec159 100644 --- a/api/v1alpha1/zz_generated.conversion.go +++ b/api/v1alpha1/zz_generated.conversion.go @@ -25,6 +25,7 @@ import ( v1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1" v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -76,6 +77,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*ActiveWindow)(nil), (*v1beta1.ActiveWindow)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ActiveWindow_To_v1beta1_ActiveWindow(a.(*ActiveWindow), b.(*v1beta1.ActiveWindow), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta1.ActiveWindow)(nil), (*ActiveWindow)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_ActiveWindow_To_v1alpha1_ActiveWindow(a.(*v1beta1.ActiveWindow), b.(*ActiveWindow), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*Classifier)(nil), (*v1beta1.Classifier)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_Classifier_To_v1beta1_Classifier(a.(*Classifier), b.(*v1beta1.Classifier), scope) }); err != nil { @@ -931,6 +942,28 @@ func Convert_v1beta1_AccessRequestStatus_To_v1alpha1_AccessRequestStatus(in *v1b return autoConvert_v1beta1_AccessRequestStatus_To_v1alpha1_AccessRequestStatus(in, out, s) } +func autoConvert_v1alpha1_ActiveWindow_To_v1beta1_ActiveWindow(in *ActiveWindow, out *v1beta1.ActiveWindow, s conversion.Scope) error { + out.From = in.From + out.To = in.To + return nil +} + +// Convert_v1alpha1_ActiveWindow_To_v1beta1_ActiveWindow is an autogenerated conversion function. +func Convert_v1alpha1_ActiveWindow_To_v1beta1_ActiveWindow(in *ActiveWindow, out *v1beta1.ActiveWindow, s conversion.Scope) error { + return autoConvert_v1alpha1_ActiveWindow_To_v1beta1_ActiveWindow(in, out, s) +} + +func autoConvert_v1beta1_ActiveWindow_To_v1alpha1_ActiveWindow(in *v1beta1.ActiveWindow, out *ActiveWindow, s conversion.Scope) error { + out.From = in.From + out.To = in.To + return nil +} + +// Convert_v1beta1_ActiveWindow_To_v1alpha1_ActiveWindow is an autogenerated conversion function. +func Convert_v1beta1_ActiveWindow_To_v1alpha1_ActiveWindow(in *v1beta1.ActiveWindow, out *ActiveWindow, s conversion.Scope) error { + return autoConvert_v1beta1_ActiveWindow_To_v1alpha1_ActiveWindow(in, out, s) +} + func autoConvert_v1alpha1_Classifier_To_v1beta1_Classifier(in *Classifier, out *v1beta1.Classifier, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha1_ClassifierSpec_To_v1beta1_ClassifierSpec(&in.Spec, &out.Spec, s); err != nil { @@ -2778,6 +2811,7 @@ func autoConvert_v1alpha1_SveltosClusterSpec_To_v1beta1_SveltosClusterSpec(in *S out.Paused = in.Paused out.TokenRequestRenewalOption = (*v1beta1.TokenRequestRenewalOption)(unsafe.Pointer(in.TokenRequestRenewalOption)) out.ArbitraryData = *(*map[string]string)(unsafe.Pointer(&in.ArbitraryData)) + out.ActiveWindow = (*v1beta1.ActiveWindow)(unsafe.Pointer(in.ActiveWindow)) return nil } @@ -2791,6 +2825,7 @@ func autoConvert_v1beta1_SveltosClusterSpec_To_v1alpha1_SveltosClusterSpec(in *v out.Paused = in.Paused out.TokenRequestRenewalOption = (*TokenRequestRenewalOption)(unsafe.Pointer(in.TokenRequestRenewalOption)) out.ArbitraryData = *(*map[string]string)(unsafe.Pointer(&in.ArbitraryData)) + out.ActiveWindow = (*ActiveWindow)(unsafe.Pointer(in.ActiveWindow)) return nil } @@ -2804,6 +2839,8 @@ func autoConvert_v1alpha1_SveltosClusterStatus_To_v1beta1_SveltosClusterStatus(i out.Ready = in.Ready out.FailureMessage = (*string)(unsafe.Pointer(in.FailureMessage)) out.LastReconciledTokenRequestAt = in.LastReconciledTokenRequestAt + out.NextUnpause = (*metav1.Time)(unsafe.Pointer(in.NextUnpause)) + out.NextPause = (*metav1.Time)(unsafe.Pointer(in.NextPause)) return nil } @@ -2817,6 +2854,8 @@ func autoConvert_v1beta1_SveltosClusterStatus_To_v1alpha1_SveltosClusterStatus(i out.Ready = in.Ready out.FailureMessage = (*string)(unsafe.Pointer(in.FailureMessage)) out.LastReconciledTokenRequestAt = in.LastReconciledTokenRequestAt + out.NextUnpause = (*metav1.Time)(unsafe.Pointer(in.NextUnpause)) + out.NextPause = (*metav1.Time)(unsafe.Pointer(in.NextPause)) return nil } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index e13367d..802af0e 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -125,6 +125,21 @@ func (in *AccessRequestStatus) DeepCopy() *AccessRequestStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActiveWindow) DeepCopyInto(out *ActiveWindow) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActiveWindow. +func (in *ActiveWindow) DeepCopy() *ActiveWindow { + if in == nil { + return nil + } + out := new(ActiveWindow) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Classifier) DeepCopyInto(out *Classifier) { *out = *in @@ -1910,6 +1925,11 @@ func (in *SveltosClusterSpec) DeepCopyInto(out *SveltosClusterSpec) { (*out)[key] = val } } + if in.ActiveWindow != nil { + in, out := &in.ActiveWindow, &out.ActiveWindow + *out = new(ActiveWindow) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SveltosClusterSpec. @@ -1930,6 +1950,14 @@ func (in *SveltosClusterStatus) DeepCopyInto(out *SveltosClusterStatus) { *out = new(string) **out = **in } + if in.NextUnpause != nil { + in, out := &in.NextUnpause, &out.NextUnpause + *out = (*in).DeepCopy() + } + if in.NextPause != nil { + in, out := &in.NextPause, &out.NextPause + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SveltosClusterStatus. diff --git a/api/v1beta1/sveltoscluster_type.go b/api/v1beta1/sveltoscluster_type.go index 12a23b1..5bfb355 100644 --- a/api/v1beta1/sveltoscluster_type.go +++ b/api/v1beta1/sveltoscluster_type.go @@ -24,6 +24,18 @@ const ( SveltosClusterKind = "SveltosCluster" ) +type ActiveWindow struct { + // From in Cron format, see https://en.wikipedia.org/wiki/Cron. + // Indicates when to un-pause the cluster (cluster in paused state receives no update from sveltos). + // +kubebuilder:validation:MinLength=1 + From string `json:"from"` + + // To in Cron format, see https://en.wikipedia.org/Cron. + // Indicates when to pause the cluster (cluster in paused state receives no update from sveltos). + // +kubebuilder:validation:MinLength=1 + To string `json:"to"` +} + type TokenRequestRenewalOption struct { // RenewTokenRequestInterval is the interval at which to renew the TokenRequest RenewTokenRequestInterval metav1.Duration `json:"renewTokenRequestInterval"` @@ -50,6 +62,11 @@ type SveltosClusterSpec struct { // ArbitraryData allows for arbitrary nested structures // +optional ArbitraryData map[string]string `json:"data,omitempty"` + + // ActiveWindow is an optional field for automatically pausing and unpausing + // the cluster. + // If not specified, the cluster will not be paused or unpaused automatically. + ActiveWindow *ActiveWindow `json:"activeWindow,omitempty"` } // SveltosClusterStatus defines the status of SveltosCluster @@ -71,6 +88,14 @@ type SveltosClusterStatus struct { // was renewed. // +optional LastReconciledTokenRequestAt string `json:"lastReconciledTokenRequestAt,omitempty"` + + // Information when next unpause cluster is scheduled + // +optional + NextUnpause *metav1.Time `json:"nextUnpause,omitempty"` + + // Information when next pause cluster is scheduled + // +optional + NextPause *metav1.Time `json:"nextPause,omitempty"` } //+kubebuilder:object:root=true diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 2822e2c..55cc12d 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -125,6 +125,21 @@ func (in *AccessRequestStatus) DeepCopy() *AccessRequestStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ActiveWindow) DeepCopyInto(out *ActiveWindow) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActiveWindow. +func (in *ActiveWindow) DeepCopy() *ActiveWindow { + if in == nil { + return nil + } + out := new(ActiveWindow) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Classifier) DeepCopyInto(out *Classifier) { *out = *in @@ -1964,6 +1979,11 @@ func (in *SveltosClusterSpec) DeepCopyInto(out *SveltosClusterSpec) { (*out)[key] = val } } + if in.ActiveWindow != nil { + in, out := &in.ActiveWindow, &out.ActiveWindow + *out = new(ActiveWindow) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SveltosClusterSpec. @@ -1984,6 +2004,14 @@ func (in *SveltosClusterStatus) DeepCopyInto(out *SveltosClusterStatus) { *out = new(string) **out = **in } + if in.NextUnpause != nil { + in, out := &in.NextUnpause, &out.NextUnpause + *out = (*in).DeepCopy() + } + if in.NextPause != nil { + in, out := &in.NextPause, &out.NextPause + *out = (*in).DeepCopy() + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SveltosClusterStatus. diff --git a/config/crd/bases/lib.projectsveltos.io_sveltosclusters.yaml b/config/crd/bases/lib.projectsveltos.io_sveltosclusters.yaml index 6cae34f..91ddfe4 100644 --- a/config/crd/bases/lib.projectsveltos.io_sveltosclusters.yaml +++ b/config/crd/bases/lib.projectsveltos.io_sveltosclusters.yaml @@ -48,6 +48,28 @@ spec: spec: description: SveltosClusterSpec defines the desired state of SveltosCluster properties: + activeWindow: + description: |- + ActiveWindow is an optional field for automatically pausing and unpausing + the cluster. + If not specified, the cluster will not be paused or unpaused automatically. + properties: + from: + description: |- + From in Cron format, see https://en.wikipedia.org/wiki/Cron. + Indicates when to un-pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + to: + description: |- + To in Cron format, see https://en.wikipedia.org/Cron. + Indicates when to pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + required: + - from + - to + type: object data: additionalProperties: type: string @@ -92,6 +114,14 @@ spec: LastReconciledTokenRequestAt is the last time the TokenRequest was renewed. type: string + nextPause: + description: Information when next pause cluster is scheduled + format: date-time + type: string + nextUnpause: + description: Information when next unpause cluster is scheduled + format: date-time + type: string ready: description: Ready is the state of the cluster. type: boolean @@ -138,6 +168,28 @@ spec: spec: description: SveltosClusterSpec defines the desired state of SveltosCluster properties: + activeWindow: + description: |- + ActiveWindow is an optional field for automatically pausing and unpausing + the cluster. + If not specified, the cluster will not be paused or unpaused automatically. + properties: + from: + description: |- + From in Cron format, see https://en.wikipedia.org/wiki/Cron. + Indicates when to un-pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + to: + description: |- + To in Cron format, see https://en.wikipedia.org/Cron. + Indicates when to pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + required: + - from + - to + type: object data: additionalProperties: type: string @@ -182,6 +234,14 @@ spec: LastReconciledTokenRequestAt is the last time the TokenRequest was renewed. type: string + nextPause: + description: Information when next pause cluster is scheduled + format: date-time + type: string + nextUnpause: + description: Information when next unpause cluster is scheduled + format: date-time + type: string ready: description: Ready is the state of the cluster. type: boolean diff --git a/lib/crd/sveltosclusters.go b/lib/crd/sveltosclusters.go index e35fabd..469fdd9 100644 --- a/lib/crd/sveltosclusters.go +++ b/lib/crd/sveltosclusters.go @@ -66,6 +66,28 @@ spec: spec: description: SveltosClusterSpec defines the desired state of SveltosCluster properties: + activeWindow: + description: |- + ActiveWindow is an optional field for automatically pausing and unpausing + the cluster. + If not specified, the cluster will not be paused or unpaused automatically. + properties: + from: + description: |- + From in Cron format, see https://en.wikipedia.org/wiki/Cron. + Indicates when to un-pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + to: + description: |- + To in Cron format, see https://en.wikipedia.org/Cron. + Indicates when to pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + required: + - from + - to + type: object data: additionalProperties: type: string @@ -110,6 +132,14 @@ spec: LastReconciledTokenRequestAt is the last time the TokenRequest was renewed. type: string + nextPause: + description: Information when next pause cluster is scheduled + format: date-time + type: string + nextUnpause: + description: Information when next unpause cluster is scheduled + format: date-time + type: string ready: description: Ready is the state of the cluster. type: boolean @@ -156,6 +186,28 @@ spec: spec: description: SveltosClusterSpec defines the desired state of SveltosCluster properties: + activeWindow: + description: |- + ActiveWindow is an optional field for automatically pausing and unpausing + the cluster. + If not specified, the cluster will not be paused or unpaused automatically. + properties: + from: + description: |- + From in Cron format, see https://en.wikipedia.org/wiki/Cron. + Indicates when to un-pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + to: + description: |- + To in Cron format, see https://en.wikipedia.org/Cron. + Indicates when to pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + required: + - from + - to + type: object data: additionalProperties: type: string @@ -200,6 +252,14 @@ spec: LastReconciledTokenRequestAt is the last time the TokenRequest was renewed. type: string + nextPause: + description: Information when next pause cluster is scheduled + format: date-time + type: string + nextUnpause: + description: Information when next unpause cluster is scheduled + format: date-time + type: string ready: description: Ready is the state of the cluster. type: boolean diff --git a/manifests/apiextensions.k8s.io_v1_customresourcedefinition_sveltosclusters.lib.projectsveltos.io.yaml b/manifests/apiextensions.k8s.io_v1_customresourcedefinition_sveltosclusters.lib.projectsveltos.io.yaml index b0395b6..93d894a 100644 --- a/manifests/apiextensions.k8s.io_v1_customresourcedefinition_sveltosclusters.lib.projectsveltos.io.yaml +++ b/manifests/apiextensions.k8s.io_v1_customresourcedefinition_sveltosclusters.lib.projectsveltos.io.yaml @@ -47,6 +47,28 @@ spec: spec: description: SveltosClusterSpec defines the desired state of SveltosCluster properties: + activeWindow: + description: |- + ActiveWindow is an optional field for automatically pausing and unpausing + the cluster. + If not specified, the cluster will not be paused or unpaused automatically. + properties: + from: + description: |- + From in Cron format, see https://en.wikipedia.org/wiki/Cron. + Indicates when to un-pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + to: + description: |- + To in Cron format, see https://en.wikipedia.org/Cron. + Indicates when to pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + required: + - from + - to + type: object data: additionalProperties: type: string @@ -91,6 +113,14 @@ spec: LastReconciledTokenRequestAt is the last time the TokenRequest was renewed. type: string + nextPause: + description: Information when next pause cluster is scheduled + format: date-time + type: string + nextUnpause: + description: Information when next unpause cluster is scheduled + format: date-time + type: string ready: description: Ready is the state of the cluster. type: boolean @@ -137,6 +167,28 @@ spec: spec: description: SveltosClusterSpec defines the desired state of SveltosCluster properties: + activeWindow: + description: |- + ActiveWindow is an optional field for automatically pausing and unpausing + the cluster. + If not specified, the cluster will not be paused or unpaused automatically. + properties: + from: + description: |- + From in Cron format, see https://en.wikipedia.org/wiki/Cron. + Indicates when to un-pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + to: + description: |- + To in Cron format, see https://en.wikipedia.org/Cron. + Indicates when to pause the cluster (cluster in paused state receives no update from sveltos). + minLength: 1 + type: string + required: + - from + - to + type: object data: additionalProperties: type: string @@ -181,6 +233,14 @@ spec: LastReconciledTokenRequestAt is the last time the TokenRequest was renewed. type: string + nextPause: + description: Information when next pause cluster is scheduled + format: date-time + type: string + nextUnpause: + description: Information when next unpause cluster is scheduled + format: date-time + type: string ready: description: Ready is the state of the cluster. type: boolean