diff --git a/.gitignore b/.gitignore index 65ed960f0..82ac13a20 100644 --- a/.gitignore +++ b/.gitignore @@ -48,7 +48,7 @@ testbin/* *~ # Omit some fully generated files -config/crd/bases/vertica.com_verticadbs.yaml +config/crd/bases/*.yaml config/rbac/role.yaml api/v1beta1/zz_generated.deepcopy.go diff --git a/PROJECT b/PROJECT index bbfebeded..e898c1f42 100644 --- a/PROJECT +++ b/PROJECT @@ -19,4 +19,15 @@ resources: defaulting: true validation: true webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: vertica.com + kind: VerticaAutoscaler + path: github.com/vertica/vertica-kubernetes/api/v1beta1 + version: v1beta1 + webhooks: + validation: true + webhookVersion: v1 version: "3" diff --git a/api/v1beta1/groupversion_info.go b/api/v1beta1/groupversion_info.go index aad6f5420..d76837aa6 100644 --- a/api/v1beta1/groupversion_info.go +++ b/api/v1beta1/groupversion_info.go @@ -24,9 +24,17 @@ import ( "sigs.k8s.io/controller-runtime/pkg/scheme" ) +const ( + Group = "vertica.com" + Version = "v1beta1" + + VerticaDBKind = "VerticaDB" + VerticaAutoscalerKind = "VerticaAutoscaler" +) + var ( // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "vertica.com", Version: "v1beta1"} + GroupVersion = schema.GroupVersion{Group: Group, Version: Version} // SchemeBuilder is used to add go types to the GroupVersionKind scheme SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/api/v1beta1/verticaarchive_types.go b/api/v1beta1/verticaarchive_types.go new file mode 100644 index 000000000..6bba09a54 --- /dev/null +++ b/api/v1beta1/verticaarchive_types.go @@ -0,0 +1,71 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +const VerticaArchiveKind = "VerticaArchive" + +// VerticaArchiveSpec defines the desired state of VerticaArchive +type VerticaArchiveSpec struct { + // Important: Run "make" to regenerate code after modifying this file + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // The path where the archive is stored. This parameter is required. + // For S3-compatible or cloud locations, provide the bucket name and backup path. + // For HDFS locations, provide the appropriate protocol and backup path. + Path string `json:"path,omitempty"` + + // +kubebuilder:default:=1 + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:number" + // Number of earlier backups to retain with the most recent backup. + // If set to 1 (the default), we maintains two backups: the latest backup and the one before it + RestorePointLimit int `json:"restorePointLimit"` +} + +// VerticaArchiveStatus defines the observed state of VerticaArchive +type VerticaArchiveStatus struct { + // +operator-sdk:csv:customresourcedefinitions:type=status + // The number of backups existing in the archive. + BackupCount int `json:"backupCount"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:resource:categories=all;vertica,shortName=va +//+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +//+kubebuilder:printcolumn:name="Backup Count",type="integer",JSONPath=".status.backupCount" + +// VerticaArchive is the schema for verticaarchives API +type VerticaArchive struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VerticaArchiveSpec `json:"spec,omitempty"` + Status VerticaArchiveStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// VerticaArchiveList contains a list of VerticaArchive +type VerticaArchiveList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VerticaArchive `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VerticaArchive{}, &VerticaArchiveList{}) +} diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go new file mode 100644 index 000000000..e1a36985d --- /dev/null +++ b/api/v1beta1/verticaautoscaler_types.go @@ -0,0 +1,200 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// nolint:lll +package v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// VerticaAutoscalerSpec defines the desired state of VerticaAutoscaler +type VerticaAutoscalerSpec struct { + // Important: Run "make" to regenerate code after modifying this file + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:text" + // The name of the VerticaDB CR that this autoscaler is defined for. The + // VerticaDB object must exist in the same namespace as this object. + VerticaDBName string `json:"verticaDBName,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +kubebuilder:default:="Subcluster" + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:select:Pod","urn:alm:descriptor:com.tectonic.ui:select:Subcluster"} + // This defines how the scaling will happen. This can be one of the following: + // - Subcluster: Scaling will be achieved by creating or deleting entire subclusters. + // The template for new subclusters are either the template if filled out + // or an existing subcluster that matches the service name. + // - Pod: Only increase or decrease the size of an existing subcluster. + // If multiple subclusters are selected by the serviceName, this will grow + // the last subcluster only. + ScalingGranularity ScalingGranularityType `json:"scalingGranularity"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:text" + // This acts as a selector for the subclusters that are being scaled together. + // Each subcluster has a service name field, which if omitted is the same + // name as the subcluster name. Multiple subclusters that have the same + // service name use the same service object. + ServiceName string `json:"serviceName"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +kubebuilder:validation:Optional + // When the scaling granularity is Subcluster, this field defines a template + // to use for when a new subcluster needs to be created. If size is 0, then + // the operator will use an existing subcluster to use as the template. If + // size is > 0, the service name must match the serviceName parameter. The + // name of the new subcluster is always auto generated. If the name is set + // here it will be used as a prefix for the new subcluster. Otherwise, we + // use the name of this VerticaAutoscaler object as a prefix for all + // subclusters. + Template Subcluster `json:"template"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:podCount" + // This is the total pod count for all subclusters that match the + // serviceName. Changing this value may trigger a change in the + // VerticaDB that is associated with this object. This value is generally + // left as zero. It will get initialized in the operator and then modified + // via the /scale subresource. + TargetSize int32 `json:"targetSize"` +} + +type ScalingGranularityType string + +const ( + PodScalingGranularity = "Pod" + SubclusterScalingGranularity = "Subcluster" +) + +// VerticaAutoscalerStatus defines the observed state of VerticaAutoscaler +type VerticaAutoscalerStatus struct { + // +operator-sdk:csv:customresourcedefinitions:type=status + // The total number of times the operator has scaled up/down the VerticaDB. + ScalingCount int `json:"scalingCount"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // The observed size of all pods that are routed through the service name. + CurrentSize int32 `json:"currentSize"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // The selector used to find all of the pods for this autoscaler. + Selector string `json:"selector"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Conditions for VerticaAutoscaler + Conditions []VerticaAutoscalerCondition `json:"conditions,omitempty"` +} + +// VerticaAutoscalerCondition defines condition for VerticaAutoscaler +type VerticaAutoscalerCondition struct { + // +operator-sdk:csv:customresourcedefinitions:type=status + // Type is the type of the condition + Type VerticaAutoscalerConditionType `json:"type"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Status is the status of the condition + // can be True, False or Unknown + Status corev1.ConditionStatus `json:"status"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` +} + +type VerticaAutoscalerConditionType string + +const ( + // TargetSizeInitialized indicates whether the operator has initialized targetSize in the spec + TargetSizeInitialized VerticaAutoscalerConditionType = "TargetSizeInitialized" +) + +// Fixed index entries for each condition. +const ( + TargetSizeInitializedIndex = iota +) + +//+kubebuilder:object:root=true +//+kubebuilder:resource:categories=all;vertica,shortName=vas +//+kubebuilder:subresource:status +//+kubebuilder:subresource:scale:specpath=.spec.targetSize,statuspath=.status.currentSize,selectorpath=.status.selector +//+kubebuilder:printcolumn:name="Granularity",type="string",JSONPath=".spec.scalingGranularity" +//+kubebuilder:printcolumn:name="Current Size",type="integer",JSONPath=".status.currentSize" +//+kubebuilder:printcolumn:name="Target Size",type="integer",JSONPath=".spec.targetSize" +//+kubebuilder:printcolumn:name="Scaling Count",type="integer",JSONPath=".status.scalingCount" +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +//+operator-sdk:csv:customresourcedefinitions:resources={{VerticaDB,vertica.com/v1beta1,""}} + +// VerticaAutoscaler is the Schema for the verticaautoscalers API +type VerticaAutoscaler struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VerticaAutoscalerSpec `json:"spec,omitempty"` + Status VerticaAutoscalerStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// VerticaAutoscalerList contains a list of VerticaAutoscaler +type VerticaAutoscalerList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VerticaAutoscaler `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VerticaAutoscaler{}, &VerticaAutoscalerList{}) +} + +// MakeVASName is a helper that creates a sample name for test purposes +func MakeVASName() types.NamespacedName { + return types.NamespacedName{Name: "vertica-vas-sample", Namespace: "default"} +} + +// MakeVAS is a helper that constructs a fully formed VerticaAutoscaler struct using the sample name. +// This is intended for test purposes. +func MakeVAS() *VerticaAutoscaler { + vasNm := MakeVASName() + vdbNm := MakeVDBName() + return &VerticaAutoscaler{ + TypeMeta: metav1.TypeMeta{ + APIVersion: GroupVersion.String(), + Kind: VerticaAutoscalerKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: vasNm.Name, + Namespace: vasNm.Namespace, + UID: "abcdef-ghi", + Annotations: make(map[string]string), + }, + Spec: VerticaAutoscalerSpec{ + VerticaDBName: vdbNm.Name, + ScalingGranularity: "Pod", + ServiceName: "sc1", + }, + } +} + +// CanUseTemplate returns true if we can use the template provided in the spec +func (v *VerticaAutoscaler) CanUseTemplate() bool { + return v.Spec.Template.Size > 0 +} diff --git a/api/v1beta1/verticaautoscaler_webhook.go b/api/v1beta1/verticaautoscaler_webhook.go new file mode 100644 index 000000000..9f9323ca4 --- /dev/null +++ b/api/v1beta1/verticaautoscaler_webhook.go @@ -0,0 +1,123 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint:lll +package v1beta1 + +import ( + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" + ctrl "sigs.k8s.io/controller-runtime" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +// log is for logging in this package. +var verticaautoscalerlog = logf.Log.WithName("verticaautoscaler-resource") + +func (v *VerticaAutoscaler) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(v). + Complete() +} + +//+kubebuilder:webhook:path=/mutate-vertica-com-v1beta1-verticaautoscaler,mutating=true,failurePolicy=fail,sideEffects=None,groups=vertica.com,resources=verticaautoscalers,verbs=create;update,versions=v1beta1,name=mverticaautoscaler.kb.io,admissionReviewVersions=v1 +var _ webhook.Defaulter = &VerticaDB{} + +// Default implements webhook.Defaulter so a webhook will be registered for the type +func (v *VerticaAutoscaler) Default() { + verticaautoscalerlog.Info("default", "name", v.Name) + + if v.Spec.Template.ServiceName == "" { + v.Spec.Template.ServiceName = v.Spec.ServiceName + } +} + +//+kubebuilder:webhook:path=/validate-vertica-com-v1beta1-verticaautoscaler,mutating=false,failurePolicy=fail,sideEffects=None,groups=vertica.com,resources=verticaautoscalers,verbs=create;update,versions=v1beta1,name=vverticaautoscaler.kb.io,admissionReviewVersions=v1 +var _ webhook.Validator = &VerticaAutoscaler{} + +// ValidateCreate implements webhook.Validator so a webhook will be registered for the type +func (v *VerticaAutoscaler) ValidateCreate() error { + verticaautoscalerlog.Info("validate create", "name", v.Name) + + allErrs := v.validateSpec(true) + if len(allErrs) == 0 { + return nil + } + return apierrors.NewInvalid(schema.GroupKind{Group: Group, Kind: VerticaAutoscalerKind}, v.Name, allErrs) +} + +// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type +func (v *VerticaAutoscaler) ValidateUpdate(old runtime.Object) error { + verticaautoscalerlog.Info("validate update", "name", v.Name) + + allErrs := v.validateSpec(false) + if len(allErrs) == 0 { + return nil + } + return apierrors.NewInvalid(schema.GroupKind{Group: Group, Kind: VerticaAutoscalerKind}, v.Name, allErrs) +} + +// ValidateDelete implements webhook.Validator so a webhook will be registered for the type +func (v *VerticaAutoscaler) ValidateDelete() error { + verticaautoscalerlog.Info("validate delete", "name", v.Name) + + return nil +} + +// validateSpec will validate the current VerticaAutoscaler to see if it is valid +func (v *VerticaAutoscaler) validateSpec(isCreate bool) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = v.validateScalingGranularity(allErrs) + allErrs = v.validateSubclusterTemplate(allErrs, isCreate) + return allErrs +} + +// validateScalingGranularity will check if the scalingGranularity field is valid +func (v *VerticaAutoscaler) validateScalingGranularity(allErrs field.ErrorList) field.ErrorList { + switch v.Spec.ScalingGranularity { + case PodScalingGranularity, SubclusterScalingGranularity: + return allErrs + default: + err := field.Invalid(field.NewPath("spec").Child("scalingGranularity"), + v.Spec.ScalingGranularity, + fmt.Sprintf("scalingGranularity must be set to either %s or %s", + SubclusterScalingGranularity, + PodScalingGranularity)) + return append(allErrs, err) + } +} + +// validateSubclusterTemplate will validate the subcluster template +func (v *VerticaAutoscaler) validateSubclusterTemplate(allErrs field.ErrorList, isCreate bool) field.ErrorList { + pathPrefix := field.NewPath("spec").Child("template") + // We have a defaulter that sets the service name in template to match + // spec.serviceName. So we only need to check for differences if this is an + // update or a create but we set something. + if (!isCreate || v.Spec.Template.ServiceName != "") && + v.Spec.Template.ServiceName != v.Spec.ServiceName { + err := field.Invalid(pathPrefix.Child("serviceName"), + v.Spec.Template.ServiceName, + "The serviceName in the subcluster template must match spec.serviceName") + allErrs = append(allErrs, err) + } + + return allErrs +} diff --git a/api/v1beta1/verticaautoscaler_webhook_test.go b/api/v1beta1/verticaautoscaler_webhook_test.go new file mode 100644 index 000000000..185eab7e8 --- /dev/null +++ b/api/v1beta1/verticaautoscaler_webhook_test.go @@ -0,0 +1,52 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package v1beta1 + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("verticaautoscaler_webhook", func() { + It("should succeed with all valid fields", func() { + vas := MakeVAS() + Expect(vas.ValidateCreate()).Should(Succeed()) + }) + + It("should fail if granularity isn't set properly", func() { + vas := MakeVAS() + vas.Spec.ScalingGranularity = "BadValue" + Expect(vas.ValidateCreate()).ShouldNot(Succeed()) + }) + + It("should set a default value for the service name in the template", func() { + vas := MakeVAS() + vas.Spec.Template.ServiceName = "" + vas.Default() + Expect(vas.Spec.Template.ServiceName).Should(Equal(vas.Spec.ServiceName)) + }) + + It("should fail if the service name differs", func() { + vas := MakeVAS() + vas.Spec.Template.ServiceName = "SomethingElse" + Expect(vas.ValidateCreate()).ShouldNot(Succeed()) + vas.Spec.Template.ServiceName = "" + Expect(vas.ValidateCreate()).Should(Succeed()) + Expect(vas.ValidateUpdate(MakeVAS())).ShouldNot(Succeed()) + vas.Spec.Template.ServiceName = vas.Spec.ServiceName + Expect(vas.ValidateUpdate(MakeVAS())).Should(Succeed()) + }) +}) diff --git a/api/v1beta1/verticabackup_types.go b/api/v1beta1/verticabackup_types.go new file mode 100644 index 000000000..059f351b5 --- /dev/null +++ b/api/v1beta1/verticabackup_types.go @@ -0,0 +1,140 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// VerticaBackupSpec defines the desired state of VerticaBackup +type VerticaBackupSpec struct { + // Important: Run "make" to regenerate code after modifying this file + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:text" + // The name of the VerticaDB that has the database we will backup. + // This parameter is required. + // The name must be an existing VerticaDB in the same namespace. + VerticaDBName string `json:"verticaDBName,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:text" + // The name of the VerticaArchive to use for this backup. This parameter is required. + // The archive must already exist in the same namespace. + Archive string `json:"archive,omitempty"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default:=true + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:booleanSwitch" + // When set to true, the data sent to the backup path will be encrypted. + // This is required for certain backup locations. + EncryptTransport bool `json:"encryptTransport,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // The path to a SSL certificate bundle. This path is relative inside a VerticaDB pod. + // These are typically one of the certs that are mounted at /certs// + CaFile string `json:"caFile,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // List of objects to include in the backup. This is a wildcard. + IncludeObjects string `json:"includeObjects,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // List of objects to exclude in the backup. This can only be used if includeObjects is used, + // as it remove objects from that were included in that wildcard. + ExcludeObjects string `json:"excludeObjects,omitempty"` +} + +type VerticaBackupPhase string + +const ( + // BackupInitialized means that all required resources have been initialized + BackupInitialized VerticaBackupPhase = "Initialized" + // BackupRunning means that the backup process has initiated. + BackupRunning VerticaBackupPhase = "Running" + // BackupSucceeded means that the backup process has completed. + BackupSucceeded VerticaBackupPhase = "Succeeded" + // BackupFailed means that the backup failed. + BackupFailed VerticaBackupPhase = "Failed" +) + +// VerticaBackupCondition describes the observed state of a VerticaBackup at a certain point. +type VerticaBackupCondition struct { + // +operator-sdk:csv:customresourcedefinitions:type=status + // Type is the type of the condition + Type VerticaBackupPhase `json:"type"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Status is the status of the condition + // can be True, False or Unknown + Status corev1.ConditionStatus `json:"status"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` +} + +// VerticaBackupStatus defines the observed state of VerticaBackup +type VerticaBackupStatus struct { + // +operator-sdk:csv:customresourcedefinitions:type=status + // Reason indicates the reason for any backup related failures. + Reason string `json:"reason,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Current phase of the backup operation + Phase VerticaBackupPhase `json:"phase,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // The name of the VerticaArchive used for this backup + Archive string `json:"archive,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Conditions for VerticaBackup + Conditions []VerticaBackupCondition `json:"conditions,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:resource:categories=all;vertica,shortName=vb +//+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +//+kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase" +//+kubebuilder:printcolumn:name="Archive",type="string",JSONPath=".status.archive" +//+operator-sdk:csv:customresourcedefinitions:resources={{VerticaDB,vertica.com/v1beta1,""},{VerticaArchive,vertica.com/v1beta1,""}} + +// VerticaBackup is the schema for verticabackups API +type VerticaBackup struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VerticaBackupSpec `json:"spec,omitempty"` + Status VerticaBackupStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// VerticaBackupList contains a list of VerticaBackup +type VerticaBackupList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VerticaBackup `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VerticaBackup{}, &VerticaBackupList{}) +} diff --git a/api/v1beta1/verticadb_types.go b/api/v1beta1/verticadb_types.go index b8ccb8341..3b55def11 100644 --- a/api/v1beta1/verticadb_types.go +++ b/api/v1beta1/verticadb_types.go @@ -34,9 +34,6 @@ import ( // Important: Run "make" to regenerate code after modifying this file -const VerticaDBKind = "VerticaDB" -const VerticaDBAPIVersion = "vertica.com/v1beta1" - // Set constant Upgrade Requeue Time const URTime = 30 @@ -797,7 +794,7 @@ type VerticaDBPodStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status -//+kubebuilder:resource:categories=all;verticadbs,shortName=vdb +//+kubebuilder:resource:categories=all;vertica,shortName=vdb //+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" //+kubebuilder:printcolumn:name="Subclusters",type="integer",JSONPath=".status.subclusterCount" //+kubebuilder:printcolumn:name="Installed",type="integer",JSONPath=".status.installCount" @@ -867,8 +864,8 @@ func MakeVDB() *VerticaDB { nm := MakeVDBName() return &VerticaDB{ TypeMeta: metav1.TypeMeta{ - APIVersion: "vertica.com/v1beta1", - Kind: "VerticaDB", + APIVersion: GroupVersion.String(), + Kind: VerticaDBKind, }, ObjectMeta: metav1.ObjectMeta{ Name: nm.Name, @@ -979,6 +976,19 @@ func (s *Subcluster) GetServiceName() string { return s.ServiceName } +// FindSubclusterForServiceName will find any subclusters that match the given service name +func (v *VerticaDB) FindSubclusterForServiceName(svcName string) (scs []*Subcluster, totalSize int32) { + totalSize = int32(0) + scs = []*Subcluster{} + for i := range v.Spec.Subclusters { + if v.Spec.Subclusters[i].GetServiceName() == svcName { + scs = append(scs, &v.Spec.Subclusters[i]) + totalSize += v.Spec.Subclusters[i].Size + } + } + return scs, totalSize +} + // RequiresTransientSubcluster checks if an online upgrade requires a // transient subcluster. A transient subcluster exists if the template is // filled out. diff --git a/api/v1beta1/verticadb_webhook.go b/api/v1beta1/verticadb_webhook.go index 39f6f0878..f56180a6e 100644 --- a/api/v1beta1/verticadb_webhook.go +++ b/api/v1beta1/verticadb_webhook.go @@ -120,6 +120,7 @@ func (v *VerticaDB) Default() { v.Spec.Communal.Endpoint = DefaultGCloudEndpoint } v.Spec.TemporarySubclusterRouting.Template.IsPrimary = false + v.setDefaultServiceName() } //+kubebuilder:webhook:path=/validate-vertica-com-v1beta1-verticadb,mutating=false,failurePolicy=fail,sideEffects=None,groups=vertica.com,resources=verticadbs,verbs=create;update,versions=v1beta1,name=vverticadb.kb.io,admissionReviewVersions=v1 @@ -134,7 +135,7 @@ func (v *VerticaDB) ValidateCreate() error { if allErrs == nil { return nil } - return apierrors.NewInvalid(schema.GroupKind{Group: "vertica.com", Kind: "VerticaDB"}, v.Name, allErrs) + return apierrors.NewInvalid(schema.GroupKind{Group: Group, Kind: VerticaDBKind}, v.Name, allErrs) } // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type @@ -145,7 +146,7 @@ func (v *VerticaDB) ValidateUpdate(old runtime.Object) error { if allErrs == nil { return nil } - return apierrors.NewInvalid(schema.GroupKind{Group: "vertica.com", Kind: "VerticaDB"}, v.Name, allErrs) + return apierrors.NewInvalid(schema.GroupKind{Group: Group, Kind: VerticaDBKind}, v.Name, allErrs) } // ValidateDelete implements webhook.Validator so a webhook will be registered for the type @@ -776,3 +777,14 @@ func (v *VerticaDB) checkImmutableTemporarySubclusterRouting(oldObj *VerticaDB, } return allErrs } + +// setDefaultServiceName will explicitly set the serviceName in any subcluster +// that omitted it +func (v *VerticaDB) setDefaultServiceName() { + for i := range v.Spec.Subclusters { + sc := &v.Spec.Subclusters[i] + if sc.ServiceName == "" { + sc.ServiceName = sc.GetServiceName() + } + } +} diff --git a/api/v1beta1/verticadb_webhook_test.go b/api/v1beta1/verticadb_webhook_test.go index 006e69f21..768053703 100644 --- a/api/v1beta1/verticadb_webhook_test.go +++ b/api/v1beta1/verticadb_webhook_test.go @@ -476,6 +476,13 @@ var _ = Describe("verticadb_webhook", func() { } validateSpecValuesHaveErr(vdb, true) }) + + It("should fill in the default serviceName if omitted", func() { + vdb := MakeVDB() + Expect(vdb.Spec.Subclusters[0].ServiceName).Should(Equal("")) + vdb.Default() + Expect(vdb.Spec.Subclusters[0].ServiceName).Should(Equal(vdb.Spec.Subclusters[0].Name)) + }) }) func createVDBHelper() *VerticaDB { diff --git a/api/v1beta1/verticarestore_types.go b/api/v1beta1/verticarestore_types.go new file mode 100644 index 000000000..29e2bdcf8 --- /dev/null +++ b/api/v1beta1/verticarestore_types.go @@ -0,0 +1,160 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// VerticaRestoreSpec defines the desired state of VerticaRestore +type VerticaRestoreSpec struct { + // Important: Run "make" to regenerate code after modifying this file + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:text" + // The name of the VerticaDB we are going to restore to. + // This parameter is required. + // The name must be an existing VerticaDB in the same namespace. + VerticaDBName string `json:"verticaDBName,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:text" + // The name of the VerticaArchive to restore from. It must reference an existing VerticaArchive, + // and at least one backup must exist there. + Archive string `json:"archive,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // The timestamp of the image to restore from. This must be one of the retained backup images. + // If this is omitted, the last backup is used. + Timestamp metav1.Timestamp `json:"timestamp,omitempty"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default:=false + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:booleanSwitch" + // When set to true, all foreign key constraints are unconditionally dropped during object-level restore. + // This allows you to restore database objects independent of their foreign key dependencies. + // You must set objectRestoreMode to coexist, otherwise this setting is ignored. + DropForeignConstraints bool `json:"dropForeignConstraints,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // List of objects to restore from the backup. This is a wildcard. + IncludeObjects string `json:"includeObjects,omitempty"` + + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + // List of objects to exclude from the backup. This can only be used if includeObjects is used, + // as it remove objects from that were included in that wildcard. + ExcludeObjects string `json:"excludeObjects,omitempty"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default:=createOrReplace + // +operator-sdk:csv:customresourcedefinitions:type=spec + // Specifies how to handle objects of the same name when restoring schema or table backups. + // Valid values are one of the following: + // - createOrReplace: creates any objects that do not exist. If an object does exist, + // restore overwrites it with the version from the archive. + // - create: creates any objects that do not exist and does not replace existing objects. + // If an object being restored does exist, the restore fails. + // - coexist: vbr creates the restored version of each object with a name formatted as follows: + // backup_timestamp_objectname + + // This approach allows existing and restored objects to exist simultaneously. + // If the appended information pushes the schema name past the maximum length of 128 characters, + // Vertica truncates the name. You can perform a reverse lookup of the original schema name + // by querying the system table TRUNCATED_SCHEMATA. + ObjectRestoreMode string `json:"objectRestoreMode,omitempty"` +} + +type VerticaRestorePhase string + +const ( + // RestoreInitialized means that all required resources have been initialized. + RestoreInitialized VerticaRestorePhase = "Initialized" + // RestoreRunning means that the Restore process has initiated . + RestoreRunning VerticaRestorePhase = "Running" + // RestoreSucceeded means that the Restore process has completed. + RestoreSucceeded VerticaRestorePhase = "Succeeded" + // RestoreFailed means that the Restore failed. + RestoreFailed VerticaRestorePhase = "Failed" +) + +// VerticaRestoreCondition describes the observed state of a VerticaRestore at a certain point. +type VerticaRestoreCondition struct { + // +operator-sdk:csv:customresourcedefinitions:type=status + // Type is the type of the condition + Type VerticaRestorePhase `json:"type"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Status is the status of the condition + // can be True, False or Unknown + Status corev1.ConditionStatus `json:"status"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` +} + +// VerticaRestoreStatus defines the observed state of VerticaRestore +type VerticaRestoreStatus struct { + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Current phase of the restore operation + Phase VerticaRestorePhase `json:"phase"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Reason indicates the reason for any restore related failures. + Reason string `json:"reason,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // The name of the VerticaArchive used for this restore + Archive string `json:"archive,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // Conditions for VerticaRestore + Conditions []VerticaRestoreCondition `json:"conditions,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:resource:categories=all;vertica,shortName=vr +//+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +//+kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase" +//+kubebuilder:printcolumn:name="Archive",type="string",JSONPath=".status.archive" +//+operator-sdk:csv:customresourcedefinitions:resources={{VerticaDB,vertica.com/v1beta1,""},{VerticaArchive,vertica.com/v1beta1,""}} + +// VerticaRestore is the schema for verticarestores API +type VerticaRestore struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VerticaRestoreSpec `json:"spec,omitempty"` + Status VerticaRestoreStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// VerticaRestoreList contains a list of VerticaRestore +type VerticaRestoreList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VerticaRestore `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VerticaRestore{}, &VerticaRestoreList{}) +} diff --git a/api/v1beta1/webhook_suite_test.go b/api/v1beta1/webhook_suite_test.go index 7d9609a8d..3e939cd3d 100644 --- a/api/v1beta1/webhook_suite_test.go +++ b/api/v1beta1/webhook_suite_test.go @@ -103,6 +103,9 @@ var _ = BeforeSuite(func() { err = (&VerticaDB{}).SetupWebhookWithManager(mgr) Expect(err).NotTo(HaveOccurred()) + err = (&VerticaAutoscaler{}).SetupWebhookWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + //+kubebuilder:scaffold:webhook go func() { diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 72212c950..1b1f9e96d 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -36,12 +36,18 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/client-go/rest" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/healthz" + "sigs.k8s.io/controller-runtime/pkg/manager" verticacomv1beta1 "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" - "github.com/vertica/vertica-kubernetes/pkg/controllers" + "github.com/vertica/vertica-kubernetes/pkg/controllers/va" + "github.com/vertica/vertica-kubernetes/pkg/controllers/vas" + "github.com/vertica/vertica-kubernetes/pkg/controllers/vb" + "github.com/vertica/vertica-kubernetes/pkg/controllers/vdb" + "github.com/vertica/vertica-kubernetes/pkg/controllers/vr" //+kubebuilder:scaffold:imports ) @@ -221,26 +227,98 @@ func getLogger(logArgs Logging) *zap.Logger { return zap.New(core, opts...) } +// addReconcilersToManager will add a controller for each CR that this operator +// handles. If any failure occurs, if will exit the program. +func addReconcilersToManager(mgr manager.Manager, restCfg *rest.Config, flagArgs *FlagConfig) { + if err := (&vdb.VerticaDBReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("VerticaDB"), + Scheme: mgr.GetScheme(), + Cfg: restCfg, + EVRec: mgr.GetEventRecorderFor(builder.OperatorName), + ServiceAccountName: flagArgs.ServiceAccountName, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VerticaDB") + os.Exit(1) + } + + if err := (&vas.VerticaAutoscalerReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + EVRec: mgr.GetEventRecorderFor(builder.OperatorName), + Log: ctrl.Log.WithName("controllers").WithName("VerticaAutoscaler"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VerticaAutoscaler") + os.Exit(1) + } + + if err := (&va.VerticaArchiveReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + EVRec: mgr.GetEventRecorderFor(builder.OperatorName), + Log: ctrl.Log.WithName("controllers").WithName("VerticaArchive"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VerticaArchive") + os.Exit(1) + } + + if err := (&vb.VerticaBackupReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + EVRec: mgr.GetEventRecorderFor(builder.OperatorName), + Log: ctrl.Log.WithName("controllers").WithName("VerticaBackup"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VerticaBackup") + os.Exit(1) + } + + if err := (&vr.VerticaRestoreReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + EVRec: mgr.GetEventRecorderFor(builder.OperatorName), + Log: ctrl.Log.WithName("controllers").WithName("VerticaRestore"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VerticaRestore") + os.Exit(1) + } + //+kubebuilder:scaffold:builder +} + +// addWebhooksToManager will add any webhooks to the manager. If any failure +// occurs, it will exit the program. +func addWebhooksToManager(mgr manager.Manager) { + // Set the minimum TLS version for the webhook. By default it will use + // TLS 1.0, which has a lot of security flaws. This is a hacky way to + // set this and should be removed once there is a supported way. + // There are numerous proposals to allow this to be configured from + // Manager -- based on most recent activity this one looks promising: + // https://github.com/kubernetes-sigs/controller-runtime/issues/852 + webhookServer := mgr.GetWebhookServer() + webhookServer.TLSMinVersion = "1.3" + + if err := (&verticacomv1beta1.VerticaDB{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "VerticaDB") + os.Exit(1) + } + if err := (&verticacomv1beta1.VerticaAutoscaler{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "VerticaAutoscaler") + os.Exit(1) + } +} + func main() { flagArgs := &FlagConfig{} flagArgs.setFlagArgs() flag.Parse() - metricsAddr := flagArgs.MetricsAddr - enableLeaderElection := flagArgs.EnableLeaderElection - probeAddr := flagArgs.ProbeAddr - enableProfiler := flagArgs.EnableProfiler - saName := flagArgs.ServiceAccountName - logArgs := flagArgs.LogArgs - - logger := getLogger(*logArgs) - if logArgs.FilePath != "" { - log.Println(fmt.Sprintf("Now logging in file %s", logArgs.FilePath)) + logger := getLogger(*flagArgs.LogArgs) + if flagArgs.LogArgs.FilePath != "" { + log.Println(fmt.Sprintf("Now logging in file %s", flagArgs.LogArgs.FilePath)) } ctrl.SetLogger(zapr.NewLogger(logger)) - if enableProfiler { + if flagArgs.EnableProfiler { go func() { addr := "localhost:6060" setupLog.Info("Opening profiling port", "addr", addr) @@ -260,10 +338,10 @@ func main() { mgr, err := ctrl.NewManager(restCfg, ctrl.Options{ Scheme: scheme, - MetricsBindAddress: metricsAddr, + MetricsBindAddress: flagArgs.MetricsAddr, Port: 9443, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, + HealthProbeBindAddress: flagArgs.ProbeAddr, + LeaderElection: flagArgs.EnableLeaderElection, LeaderElectionID: "5c1e6227.vertica.com", Namespace: watchNamespace, }) @@ -272,33 +350,9 @@ func main() { os.Exit(1) } - if err = (&controllers.VerticaDBReconciler{ - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controllers").WithName("VerticaDB"), - Scheme: mgr.GetScheme(), - Cfg: restCfg, - EVRec: mgr.GetEventRecorderFor(builder.OperatorName), - ServiceAccountName: saName, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "VerticaDB") - os.Exit(1) - } - + addReconcilersToManager(mgr, restCfg, flagArgs) if getIsWebhookEnabled() { - // Set the minimum TLS version for the webhook. By default it will use - // TLS 1.0, which has a lot of security flaws. This is a hacky way to - // set this and should be removed once there is a supported way. - // There are numerous proposals to allow this to be configured from - // Manager -- based on most recent activity this one looks promising: - // https://github.com/kubernetes-sigs/controller-runtime/issues/852 - webhookServer := mgr.GetWebhookServer() - webhookServer.TLSMinVersion = "1.3" - - if err = (&verticacomv1beta1.VerticaDB{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "VerticaDB") - os.Exit(1) - } - //+kubebuilder:scaffold:builder + addWebhooksToManager(mgr) } if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 4b89cc615..ac5a6e060 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -3,17 +3,26 @@ # It should be run by config/default resources: - bases/vertica.com_verticadbs.yaml + - bases/vertica.com_verticaarchives.yaml + - bases/vertica.com_verticabackups.yaml + - bases/vertica.com_verticarestores.yaml + - bases/vertica.com_verticaautoscalers.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. # patches here are for enabling the conversion webhook for each CRD - patches/webhook_in_verticadbs.yaml + - patches/webhook_in_verticaautoscalers.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD - patches/cainjection_in_verticadbs.yaml + - patches/cainjection_in_verticaarchives.yaml + - patches/cainjection_in_verticabackups.yaml + - patches/cainjection_in_verticarestores.yaml + - patches/cainjection_in_verticaautoscalers.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_verticaarchives.yaml b/config/crd/patches/cainjection_in_verticaarchives.yaml new file mode 100644 index 000000000..12ff4731a --- /dev/null +++ b/config/crd/patches/cainjection_in_verticaarchives.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: verticaarchives.vertica.com \ No newline at end of file diff --git a/config/crd/patches/cainjection_in_verticaautoscalers.yaml b/config/crd/patches/cainjection_in_verticaautoscalers.yaml new file mode 100644 index 000000000..14fd9525d --- /dev/null +++ b/config/crd/patches/cainjection_in_verticaautoscalers.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: verticaautoscalers.vertica.com diff --git a/config/crd/patches/cainjection_in_verticabackups.yaml b/config/crd/patches/cainjection_in_verticabackups.yaml new file mode 100644 index 000000000..9360b8f0f --- /dev/null +++ b/config/crd/patches/cainjection_in_verticabackups.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: verticabackups.vertica.com \ No newline at end of file diff --git a/config/crd/patches/cainjection_in_verticarestores.yaml b/config/crd/patches/cainjection_in_verticarestores.yaml new file mode 100644 index 000000000..0fafa806a --- /dev/null +++ b/config/crd/patches/cainjection_in_verticarestores.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: verticarestores.vertica.com \ No newline at end of file diff --git a/config/crd/patches/webhook_in_verticaautoscalers.yaml b/config/crd/patches/webhook_in_verticaautoscalers.yaml new file mode 100644 index 000000000..0f463c965 --- /dev/null +++ b/config/crd/patches/webhook_in_verticaautoscalers.yaml @@ -0,0 +1,8 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: verticaautoscalers.vertica.com +spec: + conversion: + strategy: None diff --git a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml index 25dd403c2..74e1677ff 100644 --- a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml @@ -16,6 +16,212 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: + - description: VerticaAutoscaler is the Schema for the verticaautoscalers API + displayName: Vertica Autoscaler + kind: VerticaAutoscaler + name: verticaautoscalers.vertica.com + resources: + - kind: VerticaDB + name: "" + version: vertica.com/v1beta1 + specDescriptors: + - description: If true, this will cause the operator to scale down to zero pods + if the targetSize is zero. If scaling by subcluster this will remove all + subclusters that match the service name. If false, the operator will ignore + a targetSize of zero. + displayName: Allow Scale To Zero + path: allowScaleToZero + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:hidden + - description: 'This defines how the scaling will happen. This can be one of + the following: - Subcluster: Scaling will be achieved by creating or deleting + entire subclusters. The template for new subclusters are either the template + if filled out or an existing subcluster that matches the service name. + - Pod: Only increase or decrease the size of an existing subcluster. If + multiple subclusters are selected by the serviceName, this will grow the + last subcluster only.' + displayName: Scaling Granularity + path: scalingGranularity + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:select:Pod + - urn:alm:descriptor:com.tectonic.ui:select:Subcluster + - description: This acts as a selector for the subclusters that are being scaled + together. Each subcluster has a service name field, which if omitted is + the same name as the subcluster name. Multiple subclusters that have the + same service name use the same service object. + displayName: Service Name + path: serviceName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:text + - description: This is the total pod count for all subclusters that match the + serviceName. Changing this value may trigger a change in the VerticaDB + that is associated with this object. This value is generally left as zero. It + will get initialized in the operator and then modified via the /scale subresource. + displayName: Target Size + path: targetSize + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:podCount + - description: When the scaling granularity is Subcluster, this field defines + a template to use for when a new subcluster needs to be created. If size + is 0, then the operator will use an existing subcluster to use as the template. If + size is > 0, the service name must match the serviceName parameter. The + name of the new subcluster is always auto generated. If the name is set + here it will be used as a prefix for the new subcluster. Otherwise, we + use the name of this VerticaAutoscaler object as a prefix for all subclusters. + displayName: Template + path: template + - description: 'Like nodeSelector this allows you to constrain the pod only + to certain pods. It is more expressive than just using node selectors. More + info: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity' + displayName: Affinity + path: template.affinity + - description: Describes node affinity scheduling rules for the pod. + displayName: Node Affinity + path: template.affinity.nodeAffinity + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:nodeAffinity + - description: Describes pod affinity scheduling rules (e.g. co-locate this + pod in the same node, zone, etc. as some other pod(s)). + displayName: Pod Affinity + path: template.affinity.podAffinity + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:podAffinity + - description: Describes pod anti-affinity scheduling rules (e.g. avoid putting + this pod in the same node, zone, etc. as some other pod(s)). + displayName: Pod Anti Affinity + path: template.affinity.podAntiAffinity + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:podAntiAffinity + - description: 'Allows the service object to be attached to a list of external + IPs that you specify. If not set, the external IP list is left empty in + the service object. More info: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips' + displayName: External IPs + path: template.externalIPs + - description: This allows a different image to be used for the subcluster than + the one in VerticaDB. This is intended to be used internally by the online + image change process. + displayName: Image Override + path: template.imageOverride + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:hidden + - description: Indicates whether the subcluster is a primary or secondary. You + must have at least one primary subcluster in the database. + displayName: Is Primary + path: template.isPrimary + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:booleanSwitch + - description: Internal state that indicates whether this is a transient read-only + subcluster used for online upgrade. A subcluster that exists temporarily + to serve traffic for subclusters that are restarting with the new image. + displayName: Is Transient + path: template.isTransient + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:hidden + - description: 'Specify IP address of LoadBalancer service for this subcluster. + This field is ignored when serviceType != "LoadBalancer". More info: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer' + displayName: Load Balancer IP + path: template.loadBalancerIP + - description: The name of the subcluster. This is a required parameter. This + cannot change after CRD creation. + displayName: Name + path: template.name + - description: When setting serviceType to NodePort, this parameter allows you + to define the port that is opened at each node. If using NodePort and this + is omitted, Kubernetes will choose the port automatically. This port must + be from within the defined range allocated by the control plane (default + is 30000-32767). + displayName: Node Port + path: template.nodePort + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: 'A map of label keys and values to restrict Vertica node scheduling + to workers with matching labels. More info: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector' + displayName: Node Selector + path: template.nodeSelector + - description: 'The priority class name given to pods in this subcluster. This + affects where the pod gets scheduled. More info: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass' + displayName: Priority Class Name + path: template.priorityClassName + - description: 'This defines the resource requests and limits for pods in the + subcluster. It is advisable that the request and limits match as this ensures + the pods are assigned to the guaranteed QoS class. This will reduces the + chance that pods are chosen by the OOM killer. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + displayName: Resources + path: template.resources + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:resourceRequirements + - description: A map of key/value pairs appended to service metadata.annotations. + displayName: Service Annotations + path: template.serviceAnnotations + - description: Identifies the name of the service object that will serve this + subcluster. If multiple subclusters share the same service name then they + all share the same service object. This allows for a single service object + to round robin between multiple subclusters. If this is left blank, a service + object matching the subcluster name is used. The actual name of the service + object is always prefixed with the name of the owning VerticaDB. + displayName: Service Name + path: template.serviceName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:advanced + - description: 'Identifies the type of Kubernetes service to use for external + client connectivity. The default is to use a ClusterIP, which sets a stable + IP and port to use that is accessible only from within Kubernetes itself. + Depending on the service type chosen the user may need to set other config + knobs to further config it. These other knobs follow this one. More info: + https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types' + displayName: Service Type + path: template.serviceType + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:select:ClusterIP + - urn:alm:descriptor:com.tectonic.ui:select:NodePort + - urn:alm:descriptor:com.tectonic.ui:select:LoadBalancer + - description: "The number of pods that the subcluster will have. This determines + the number of Vertica nodes that it will have. Changing this number will + either delete or schedule new pods. \n The database has a k-safety of 1. + So, if this is a primary subcluster, the minimum value is 3. If this is + a secondary subcluster, the minimum is 0. \n Note, you must have a valid + license to pick a value larger than 3. The default license that comes in + the vertica container is for the community edition, which can only have + 3 nodes. The license can be set with the db.licenseSecret parameter." + displayName: Size + path: template.size + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:podCount + - description: 'Any tolerations and taints to use to aid in where to schedule + a pod. More info: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/' + displayName: Tolerations + path: template.tolerations + - description: The name of the VerticaDB CR that this autoscaler is defined + for. The VerticaDB object must exist in the same namespace as this object. + displayName: Vertica DBName + path: verticaDBName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:text + statusDescriptors: + - description: Conditions for VerticaAutoscaler + displayName: Conditions + path: conditions + - description: Last time the condition transitioned from one status to another. + displayName: Last Transition Time + path: conditions[0].lastTransitionTime + - description: Status is the status of the condition can be True, False or Unknown + displayName: Status + path: conditions[0].status + - description: Type is the type of the condition + displayName: Type + path: conditions[0].type + - description: The observed size of all pods that are routed through the service + name. + displayName: Current Size + path: currentSize + - description: The total number of times the operator has scaled up/down the + VerticaDB. + displayName: Scaling Count + path: scalingCount + - description: The selector used to find all of the pods for this autoscaler. + displayName: Selector + path: selector + version: v1beta1 - description: VerticaDB is the CR that defines a Vertica Eon mode cluster that is managed by the verticadb-operator. displayName: Vertica DB @@ -359,6 +565,10 @@ spec: path: subclusters[0].isTransient x-descriptors: - urn:alm:descriptor:com.tectonic.ui:hidden + - description: 'Specify IP address of LoadBalancer service for this subcluster. + This field is ignored when serviceType != "LoadBalancer". More info: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer' + displayName: Load Balancer IP + path: subclusters[0].loadBalancerIP - description: The name of the subcluster. This is a required parameter. This cannot change after CRD creation. displayName: Name @@ -388,6 +598,9 @@ spec: path: subclusters[0].resources x-descriptors: - urn:alm:descriptor:com.tectonic.ui:resourceRequirements + - description: A map of key/value pairs appended to service metadata.annotations. + displayName: Service Annotations + path: subclusters[0].serviceAnnotations - description: Identifies the name of the service object that will serve this subcluster. If multiple subclusters share the same service name then they all share the same service object. This allows for a single service object @@ -500,6 +713,10 @@ spec: path: temporarySubclusterRouting.template.isTransient x-descriptors: - urn:alm:descriptor:com.tectonic.ui:hidden + - description: 'Specify IP address of LoadBalancer service for this subcluster. + This field is ignored when serviceType != "LoadBalancer". More info: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer' + displayName: Load Balancer IP + path: temporarySubclusterRouting.template.loadBalancerIP - description: The name of the subcluster. This is a required parameter. This cannot change after CRD creation. displayName: Name @@ -529,6 +746,9 @@ spec: path: temporarySubclusterRouting.template.resources x-descriptors: - urn:alm:descriptor:com.tectonic.ui:resourceRequirements + - description: A map of key/value pairs appended to service metadata.annotations. + displayName: Service Annotations + path: temporarySubclusterRouting.template.serviceAnnotations - description: Identifies the name of the service object that will serve this subcluster. If multiple subclusters share the same service name then they all share the same service object. This allows for a single service object diff --git a/config/rbac/verticaautoscaler_editor_role.yaml b/config/rbac/verticaautoscaler_editor_role.yaml new file mode 100644 index 000000000..2dbcdf108 --- /dev/null +++ b/config/rbac/verticaautoscaler_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit verticaautoscalers. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: verticaautoscaler-editor-role +rules: +- apiGroups: + - vertica.com + resources: + - verticaautoscalers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - vertica.com + resources: + - verticaautoscalers/status + verbs: + - get diff --git a/config/rbac/verticaautoscaler_viewer_role.yaml b/config/rbac/verticaautoscaler_viewer_role.yaml new file mode 100644 index 000000000..4d07f95cd --- /dev/null +++ b/config/rbac/verticaautoscaler_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view verticaautoscalers. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: verticaautoscaler-viewer-role +rules: +- apiGroups: + - vertica.com + resources: + - verticaautoscalers + verbs: + - get + - list + - watch +- apiGroups: + - vertica.com + resources: + - verticaautoscalers/status + verbs: + - get diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 4e3f935fc..6a17b42e9 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -1,4 +1,7 @@ ## Append samples you want in your CSV to this file as resources ## resources: - v1beta1_verticadb.yaml +- v1beta1_verticaarchive.yaml +- v1beta1_verticabackup.yaml +- v1beta1_verticaautoscaler.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/v1beta1_verticaarchive.yaml b/config/samples/v1beta1_verticaarchive.yaml new file mode 100644 index 000000000..00560f449 --- /dev/null +++ b/config/samples/v1beta1_verticaarchive.yaml @@ -0,0 +1,7 @@ +apiVersion: vertica.com/v1beta1 +kind: VerticaArchive +metadata: + name: my-backup +spec: + path: s3://nimbusdb/backup + restorePointLimit: 1 \ No newline at end of file diff --git a/config/samples/v1beta1_verticaautoscaler.yaml b/config/samples/v1beta1_verticaautoscaler.yaml new file mode 100644 index 000000000..429ed4280 --- /dev/null +++ b/config/samples/v1beta1_verticaautoscaler.yaml @@ -0,0 +1,7 @@ +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: verticaautoscaler-sample +spec: + verticaDBName: verticadb-sample + serviceName: defaultsubcluster diff --git a/config/samples/v1beta1_verticabackup.yaml b/config/samples/v1beta1_verticabackup.yaml new file mode 100644 index 000000000..6b6504252 --- /dev/null +++ b/config/samples/v1beta1_verticabackup.yaml @@ -0,0 +1,7 @@ +apiVersion: vertica.com/v1beta1 +kind: VerticaBackup +metadata: + name: backup-sample +spec: + verticaDBName: sample + archive: my-backup \ No newline at end of file diff --git a/config/samples/v1beta1_verticadb.yaml b/config/samples/v1beta1_verticadb.yaml index 2e51ddd1a..014775b8b 100644 --- a/config/samples/v1beta1_verticadb.yaml +++ b/config/samples/v1beta1_verticadb.yaml @@ -23,3 +23,10 @@ spec: credentialSecret: s3-auth subclusters: - name: defaultsubcluster + # The CPU resource setting is here is a sample. We set it so that this + # will work with the sample VerticaAutoscaler resource. The actual amount + # should be sized according to: + # https://www.vertica.com/kb/Recommendations-for-Sizing-Vertica-Nodes-and-Clusters/Content/Hardware/Recommendations-for-Sizing-Vertica-Nodes-and-Clusters.htm + resources: + requests: + cpu: 500m diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index b8c993145..512543874 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -32,6 +32,31 @@ webhooks: resources: - verticadbs sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-vertica-com-v1beta1-verticaautoscaler + failurePolicy: Fail + name: mverticaautoscaler.kb.io + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: "In" + values: [verticadb-operator-system] + rules: + - apiGroups: + - vertica.com + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - verticaautoscalers + sideEffects: None --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration @@ -39,6 +64,31 @@ metadata: creationTimestamp: null name: validating-webhook-configuration webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-vertica-com-v1beta1-verticaautoscaler + failurePolicy: Fail + name: vverticaautoscaler.kb.io + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: "In" + values: [verticadb-operator-system] + rules: + - apiGroups: + - vertica.com + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - verticaautoscalers + sideEffects: None - admissionReviewVersions: - v1 clientConfig: diff --git a/pkg/builder/labels_annotations.go b/pkg/builder/labels_annotations.go index 4d2e0f383..553b4b28a 100644 --- a/pkg/builder/labels_annotations.go +++ b/pkg/builder/labels_annotations.go @@ -43,6 +43,7 @@ const ( VDBInstanceLabel = "app.kubernetes.io/instance" OperatorVersionLabel = "app.kubernetes.io/version" + ManagedByLabel = "app.kubernetes.io/managed-by" OperatorName = "verticadb-operator" // The name of the operator CurOperatorVersion = "1.4.0" // The version number of the operator @@ -72,11 +73,11 @@ func MakeSubclusterLabels(sc *vapi.Subcluster) map[string]string { // MakeOperatorLabels returns the labels that all objects created by this operator will have func MakeOperatorLabels(vdb *vapi.VerticaDB) map[string]string { return map[string]string{ - "app.kubernetes.io/managed-by": OperatorName, - "app.kubernetes.io/name": "vertica", - VDBInstanceLabel: vdb.Name, - "app.kubernetes.io/component": "database", - "vertica.com/database": vdb.Spec.DBName, + ManagedByLabel: OperatorName, + "app.kubernetes.io/name": "vertica", + VDBInstanceLabel: vdb.Name, + "app.kubernetes.io/component": "database", + "vertica.com/database": vdb.Spec.DBName, } } diff --git a/pkg/controllers/actor.go b/pkg/controllers/actor.go index 017e8cc5a..091f22184 100644 --- a/pkg/controllers/actor.go +++ b/pkg/controllers/actor.go @@ -17,15 +17,8 @@ package controllers import ( "context" - "fmt" - vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" - verrors "github.com/vertica/vertica-kubernetes/pkg/errors" - "github.com/vertica/vertica-kubernetes/pkg/names" - appsv1 "k8s.io/api/apps/v1" - "k8s.io/apimachinery/pkg/api/errors" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" ) // ReconcileActor is an interface that handles one part of the entire @@ -33,46 +26,3 @@ import ( type ReconcileActor interface { Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) } - -// ScaledownActor is an interface that handles a part of scale down, either -// db_remove_node or uninstall. -type ScaledownActor interface { - GetClient() client.Client - GetVDB() *vapi.VerticaDB - CollectPFacts(ctx context.Context) error -} - -// scaledownSubcluster is called to either remove nodes or call uninstall. -// This is a common function that is used by the DBRemoveNodeReconciler and -// UninstallReconciler. It will call a func (scaleDownFunc) for a range of pods -// that are to be scaled down. -func scaledownSubcluster(ctx context.Context, act ScaledownActor, sc *vapi.Subcluster, - scaleDownFunc func(context.Context, *vapi.Subcluster, int32, int32) (ctrl.Result, error)) (ctrl.Result, error) { - if sc == nil { - return ctrl.Result{}, nil - } - sts := &appsv1.StatefulSet{} - if err := act.GetClient().Get(ctx, names.GenStsName(act.GetVDB(), sc), sts); err != nil { - // A non-existent statefulset is okay, as it might not have been created yet. - if errors.IsNotFound(err) { - return ctrl.Result{}, nil - } - return ctrl.Result{}, err - } - - if sts.Status.Replicas > sc.Size { - if err := act.CollectPFacts(ctx); err != nil { - return ctrl.Result{}, err - } - - res, err := scaleDownFunc(ctx, sc, sc.Size, sts.Status.Replicas-1) - if err != nil { - return res, fmt.Errorf("failed to scale down nodes in subcluster %s: %w", sc.Name, err) - } - if verrors.IsReconcileAborted(res, err) { - return res, nil - } - } - - return ctrl.Result{}, nil -} diff --git a/pkg/controllers/k8s.go b/pkg/controllers/k8s.go index 6c015ba9b..b45d321b9 100644 --- a/pkg/controllers/k8s.go +++ b/pkg/controllers/k8s.go @@ -16,59 +16,12 @@ package controllers import ( - "context" - "fmt" - - vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" - "github.com/vertica/vertica-kubernetes/pkg/events" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" ) -// getSecret is a generic function to get a secret and return its contents. If -// the secret is not found, an event is logged and the reconciliation is -// requeued. -func getSecret(ctx context.Context, vrec *VerticaDBReconciler, vdb *vapi.VerticaDB, - nm types.NamespacedName) (*corev1.Secret, ctrl.Result, error) { - secret := &corev1.Secret{} - res, err := getConfigMapOrSecret(ctx, vrec, vdb, nm, secret) - return secret, res, err -} - -// getConfigMap is like getSecret except that it works for configMap's. It the -// configMap is not found, then the ctrl.Result returned will indicate a requeue -// is needed. -func getConfigMap(ctx context.Context, vrec *VerticaDBReconciler, vdb *vapi.VerticaDB, - nm types.NamespacedName) (*corev1.ConfigMap, ctrl.Result, error) { - cm := &corev1.ConfigMap{} - res, err := getConfigMapOrSecret(ctx, vrec, vdb, nm, cm) - return cm, res, err -} - -// getConfigMapOrSecret is a generic function to fetch a ConfigMap or a Secret. -// It will handle logging an event if the configMap or secret is missing. -func getConfigMapOrSecret(ctx context.Context, vrec *VerticaDBReconciler, vdb *vapi.VerticaDB, - nm types.NamespacedName, obj client.Object) (ctrl.Result, error) { - if err := vrec.Client.Get(ctx, nm, obj); err != nil { - if errors.IsNotFound(err) { - objType := "" - switch v := obj.(type) { - default: - objType = fmt.Sprintf("%T", v) - case *corev1.Secret: - objType = "Secret" - case *corev1.ConfigMap: - objType = "ConfigMap" - } - vrec.EVRec.Eventf(vdb, corev1.EventTypeWarning, events.ObjectNotFound, - "Could not find the %s '%s'", objType, nm) - return ctrl.Result{Requeue: true}, nil - } - return ctrl.Result{}, - fmt.Errorf("could not read the secret %s: %w", nm, err) +func GetNamespacedName(namespace, name string) types.NamespacedName { + return types.NamespacedName{ + Namespace: namespace, + Name: name, } - return ctrl.Result{}, nil } diff --git a/pkg/controllers/va/verticaarchive_controller.go b/pkg/controllers/va/verticaarchive_controller.go new file mode 100644 index 000000000..eed2f7c84 --- /dev/null +++ b/pkg/controllers/va/verticaarchive_controller.go @@ -0,0 +1,87 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package va + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// VerticaArchiveReconciler reconciles a VerticaArchive object +type VerticaArchiveReconciler struct { + client.Client + Scheme *runtime.Scheme + Log logr.Logger + EVRec record.EventRecorder +} + +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticaarchives,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticaarhives/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticaarchives/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.0/pkg/reconcile +func (r *VerticaArchiveReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := r.Log.WithValues("verticaarchive", req.NamespacedName) + log.Info("starting reconcile of VerticaArchive") + + var res ctrl.Result + va := &vapi.VerticaArchive{} + err := r.Get(ctx, req.NamespacedName, va) + if err != nil { + if errors.IsNotFound(err) { + log.Info("VerticaArchive resource not found. Ignoring since object must be deleted") + return ctrl.Result{}, nil + } + log.Error(err, "failed to get VerticaArchive") + return ctrl.Result{}, err + } + + // The actors that will be applied, in sequence, to reconcile a varc. + actors := []controllers.ReconcileActor{} + + // Iterate over each actor + for _, act := range actors { + log.Info("starting actor", "name", fmt.Sprintf("%T", act)) + res, err = act.Reconcile(ctx, &req) + // Error or a request to requeue will stop the reconciliation. + if verrors.IsReconcileAborted(res, err) { + log.Info("aborting reconcile of VerticaArchive", "result", res, "err", err) + return res, err + } + } + + log.Info("ending reconcile of VerticaArchive", "result", res, "err", err) + return res, err +} + +// SetupWithManager sets up the controller with the Manager. +func (r *VerticaArchiveReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&vapi.VerticaArchive{}). + Complete(r) +} diff --git a/pkg/controllers/vas/k8s.go b/pkg/controllers/vas/k8s.go new file mode 100644 index 000000000..d81e76da2 --- /dev/null +++ b/pkg/controllers/vas/k8s.go @@ -0,0 +1,44 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/events" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" +) + +// fetchVDB will fetch the VerticaDB that is referenced in a VerticaAutoscaler. +// This will log an event if the VerticaDB is not found. +func fetchVDB(ctx context.Context, vrec *VerticaAutoscalerReconciler, + vas *vapi.VerticaAutoscaler, vdb *vapi.VerticaDB) (ctrl.Result, error) { + nm := types.NamespacedName{ + Namespace: vas.Namespace, + Name: vas.Spec.VerticaDBName, + } + err := vrec.Client.Get(ctx, nm, vdb) + if err != nil && errors.IsNotFound(err) { + vrec.EVRec.Eventf(vas, corev1.EventTypeWarning, events.VerticaDBNotFound, + "The VerticaDB named '%s' was not found", vas.Spec.VerticaDBName) + return ctrl.Result{Requeue: true}, nil + } + return ctrl.Result{}, err +} diff --git a/pkg/controllers/vas/refreshcurrentsize_reconcile.go b/pkg/controllers/vas/refreshcurrentsize_reconcile.go new file mode 100644 index 000000000..475f07d90 --- /dev/null +++ b/pkg/controllers/vas/refreshcurrentsize_reconcile.go @@ -0,0 +1,46 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/vasstatus" + ctrl "sigs.k8s.io/controller-runtime" +) + +// RefreshCurrentSizeReconciler will refresh the currentSize status field in the CR. +type RefreshCurrentSizeReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler +} + +func MakeRefreshCurrentSizeReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { + return &RefreshCurrentSizeReconciler{VRec: v, Vas: vas} +} + +// Reconcile will handle updating the currentSize in the status field +func (v *RefreshCurrentSizeReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + vdb := &vapi.VerticaDB{} + if res, err := fetchVDB(ctx, v.VRec, v.Vas, vdb); verrors.IsReconcileAborted(res, err) { + return res, err + } + _, totSize := vdb.FindSubclusterForServiceName(v.Vas.Spec.ServiceName) + return ctrl.Result{}, vasstatus.RefreshCurrentSize(ctx, v.VRec.Client, v.VRec.Log, req, totSize) +} diff --git a/pkg/controllers/vas/refreshselector_reconcile.go b/pkg/controllers/vas/refreshselector_reconcile.go new file mode 100644 index 000000000..0b663e1ed --- /dev/null +++ b/pkg/controllers/vas/refreshselector_reconcile.go @@ -0,0 +1,41 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + "github.com/vertica/vertica-kubernetes/pkg/vasstatus" + ctrl "sigs.k8s.io/controller-runtime" +) + +// RefreshSelectorReconciler is a reconciler to update the pod selector in the +// status field +type RefreshSelectorReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler +} + +func MakeRefreshSelectorReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { + return &RefreshSelectorReconciler{VRec: v, Vas: vas} +} + +// Reconcile will handle updating the selector in the status portion of a VerticaAutoscaler +func (v *RefreshSelectorReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + return ctrl.Result{}, vasstatus.SetSelector(ctx, v.VRec.Client, v.VRec.Log, req) +} diff --git a/pkg/controllers/vas/subclusterresize_reconcile.go b/pkg/controllers/vas/subclusterresize_reconcile.go new file mode 100644 index 000000000..c6a0ee066 --- /dev/null +++ b/pkg/controllers/vas/subclusterresize_reconcile.go @@ -0,0 +1,113 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/events" + "github.com/vertica/vertica-kubernetes/pkg/vasstatus" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" +) + +// SubclusterResizeReconciler will grow/shrink existing subclusters based on the +// target pod count in the CR. +type SubclusterResizeReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler + Vdb *vapi.VerticaDB +} + +func MakeSubclusterResizeReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { + return &SubclusterResizeReconciler{VRec: r, Vas: vas, Vdb: &vapi.VerticaDB{}} +} + +// Reconcile will grow/shrink an existing subcluste based on the target pod count +func (s *SubclusterResizeReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + if s.Vas.Spec.ScalingGranularity != vapi.PodScalingGranularity { + return ctrl.Result{}, nil + } + + return s.resizeSubcluster(ctx, req) +} + +// resizeSubcluster will change the size of a subcluster given the target pod count +func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + var res ctrl.Result + scalingDone := false + // Update the VerticaDB with a retry mechanism for any conflict updates + // (i.e. if someone updated the vdb since we last fetched it) + err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + if r, e := fetchVDB(ctx, s.VRec, s.Vas, s.Vdb); verrors.IsReconcileAborted(r, e) { + res = r + return e + } + + subclusters, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) + if len(subclusters) == 0 { + s.VRec.EVRec.Eventf(s.Vas, corev1.EventTypeWarning, events.SubclusterServiceNameNotFound, + "Could not find any subclusters with service name '%s'", s.Vas.Spec.ServiceName) + res.Requeue = true + return nil + } + + delta := s.Vas.Spec.TargetSize - totSize + if delta == 0 { + return nil + } + + for i := len(subclusters) - 1; i >= 0; i-- { + targetSc := subclusters[i] + if delta > 0 { // Growing subclusters + targetSc.Size += delta + delta = 0 + } else { // Shrinking subclusters + if -1*delta > targetSc.Size { + delta += targetSc.Size + targetSc.Size = 0 + } else { + targetSc.Size += delta + delta = 0 + } + } + if delta == 0 { + break + } + } + + err := s.VRec.Client.Update(ctx, s.Vdb) + if err == nil { + scalingDone = true + } + return err + }) + + if verrors.IsReconcileAborted(res, err) { + return res, err + } + + if scalingDone { + _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) + err = vasstatus.ReportScalingOperation(ctx, s.VRec.Client, s.VRec.Log, req, totSize) + } + + return res, err +} diff --git a/pkg/controllers/vas/subclusterresize_reconcile_test.go b/pkg/controllers/vas/subclusterresize_reconcile_test.go new file mode 100644 index 000000000..a02e61024 --- /dev/null +++ b/pkg/controllers/vas/subclusterresize_reconcile_test.go @@ -0,0 +1,177 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/test" + ctrl "sigs.k8s.io/controller-runtime" +) + +var _ = Describe("subclusterresize_reconcile", func() { + ctx := context.Background() + + It("should requeue if VerticaDB doesn't exist", func() { + vas := vapi.MakeVAS() + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{Requeue: true})) + }) + + It("should requeue if no subcluster exists with service name", func() { + vdb := vapi.MakeVDB() + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.ServiceName = "not-there" + vas.Spec.TargetSize = 5 + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{Requeue: true})) + }) + + It("should resize subcluster if targetSize is set in vas", func() { + const ScName = "sc1" + var TargetSize int32 = 20 + vdb := vapi.MakeVDB() + vdb.Spec.Subclusters = []vapi.Subcluster{ + {Name: ScName, Size: 1}, + } + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.TargetSize = TargetSize + vas.Spec.ServiceName = ScName + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + nm := vapi.MakeVDBName() + Expect(k8sClient.Get(ctx, nm, fetchVdb)).Should(Succeed()) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(TargetSize)) + }) + + It("should be a no-op if the targetSize isn't set", func() { + vdb := vapi.MakeVDB() + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.TargetSize = 0 + vas.Spec.ServiceName = vdb.Spec.Subclusters[0].GetServiceName() + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + nm := vapi.MakeVDBName() + Expect(k8sClient.Get(ctx, nm, fetchVdb)).Should(Succeed()) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[0].Size)) + }) + + It("should be a no-op if the targetSize matches actual", func() { + vdb := vapi.MakeVDB() + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.TargetSize = vdb.Spec.Subclusters[0].Size + vas.Spec.ServiceName = vdb.Spec.Subclusters[0].GetServiceName() + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + nm := vapi.MakeVDBName() + Expect(k8sClient.Get(ctx, nm, fetchVdb)).Should(Succeed()) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[0].Size)) + }) + + It("should only grow the last subcluster defined", func() { + const TargetSvcName = "conn" + vdb := vapi.MakeVDB() + vdb.Spec.Subclusters = []vapi.Subcluster{ + {Name: "sc1", Size: 5, ServiceName: TargetSvcName}, + {Name: "sc2", Size: 1, ServiceName: TargetSvcName}, + {Name: "sc3", Size: 10, ServiceName: "other"}, + } + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + const NumPodsToAdd = 5 + vas.Spec.TargetSize = vdb.Spec.Subclusters[0].Size + vdb.Spec.Subclusters[1].Size + NumPodsToAdd + vas.Spec.ServiceName = TargetSvcName + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + nm := vapi.MakeVDBName() + Expect(k8sClient.Get(ctx, nm, fetchVdb)).Should(Succeed()) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[0].Size)) + Expect(fetchVdb.Spec.Subclusters[1].Size).Should(Equal(vas.Spec.TargetSize - vdb.Spec.Subclusters[0].Size)) + Expect(fetchVdb.Spec.Subclusters[2].Size).Should(Equal(vdb.Spec.Subclusters[2].Size)) + }) + + It("should shrink the subcluster size", func() { + const TargetSvcName = "conn" + vdb := vapi.MakeVDB() + vdb.Spec.Subclusters = []vapi.Subcluster{ + {Name: "sc1", Size: 5, ServiceName: TargetSvcName}, + {Name: "sc2", Size: 10, ServiceName: "other"}, + {Name: "sc3", Size: 1, ServiceName: TargetSvcName}, + } + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + const NumPodsToRemove = 3 + vas.Spec.TargetSize = vdb.Spec.Subclusters[0].Size + vdb.Spec.Subclusters[2].Size - NumPodsToRemove + vas.Spec.ServiceName = TargetSvcName + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + nm := vapi.MakeVDBName() + Expect(k8sClient.Get(ctx, nm, fetchVdb)).Should(Succeed()) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[0].Size + vdb.Spec.Subclusters[2].Size - NumPodsToRemove)) + Expect(fetchVdb.Spec.Subclusters[1].Size).Should(Equal(vdb.Spec.Subclusters[1].Size)) + Expect(fetchVdb.Spec.Subclusters[2].Size).Should(Equal(int32(0))) + }) +}) diff --git a/pkg/controllers/vas/subclusterscale_reconcile.go b/pkg/controllers/vas/subclusterscale_reconcile.go new file mode 100644 index 000000000..22cf9e7ae --- /dev/null +++ b/pkg/controllers/vas/subclusterscale_reconcile.go @@ -0,0 +1,186 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + "fmt" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/events" + "github.com/vertica/vertica-kubernetes/pkg/vasstatus" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" +) + +// SubclusterScaleReconciler will scale a VerticaDB by adding or removing subclusters. +type SubclusterScaleReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler + Vdb *vapi.VerticaDB +} + +func MakeSubclusterScaleReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { + return &SubclusterScaleReconciler{VRec: r, Vas: vas, Vdb: &vapi.VerticaDB{}} +} + +// Reconcile will grow/shrink the VerticaDB passed on the target pod count. +func (s *SubclusterScaleReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + if s.Vas.Spec.ScalingGranularity != vapi.SubclusterScalingGranularity { + return ctrl.Result{}, nil + } + + return s.scaleSubcluster(ctx, req) +} + +// scaleSubcluster will decide to add or remove whole subclusters to reach the +// target size +func (s *SubclusterScaleReconciler) scaleSubcluster(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + var res ctrl.Result + scalingDone := false + // Update the VerticaDB with a retry mechanism for any conflict updates + // (i.e. if someone updated the vdb since we last fetched it) + err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + if r, e := fetchVDB(ctx, s.VRec, s.Vas, s.Vdb); verrors.IsReconcileAborted(r, e) { + res = r + return e + } + + _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) + delta := s.Vas.Spec.TargetSize - totSize + switch { + case delta < 0: + if changed := s.considerRemovingSubclusters(delta * -1); !changed { + return nil + } + case delta > 0: + if changed := s.considerAddingSubclusters(delta); !changed { + return nil + } + default: + return nil // No change + } + + err := s.VRec.Client.Update(ctx, s.Vdb) + if err == nil { + scalingDone = true + } + return err + }) + + if verrors.IsReconcileAborted(res, err) { + return res, err + } + + if scalingDone { + _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) + err = vasstatus.ReportScalingOperation(ctx, s.VRec.Client, s.VRec.Log, req, totSize) + } + return res, err +} + +// considerRemovingSubclusters will shrink the Vdb by removing subclusters -- +// picking the last one first. Changes are made in-place in s.Vdb +func (s *SubclusterScaleReconciler) considerRemovingSubclusters(podsToRemove int32) bool { + origNumSubclusters := len(s.Vdb.Spec.Subclusters) + for j := len(s.Vdb.Spec.Subclusters) - 1; j >= 0; j-- { + sc := &s.Vdb.Spec.Subclusters[j] + if sc.GetServiceName() == s.Vas.Spec.ServiceName { + if podsToRemove > 0 && sc.Size <= podsToRemove { + podsToRemove -= sc.Size + s.VRec.Log.Info("Removing subcluster in VerticaDB", "VerticaDB", s.Vdb.Name, "Subcluster", sc.Name) + s.Vdb.Spec.Subclusters = append(s.Vdb.Spec.Subclusters[:j], s.Vdb.Spec.Subclusters[j+1:]...) + continue + } else { + return origNumSubclusters != len(s.Vdb.Spec.Subclusters) + } + } + } + return origNumSubclusters != len(s.Vdb.Spec.Subclusters) +} + +// considerAddingSubclusters will grow the Vdb by adding new subclusters. +// Changes are made in-place in s.Vdb +func (s *SubclusterScaleReconciler) considerAddingSubclusters(newPodsNeeded int32) bool { + origNumSubclusters := len(s.Vdb.Spec.Subclusters) + scMap := s.Vdb.GenSubclusterMap() + newScSize, ok := s.calcNextSubclusterSize(scMap) + if !ok { + return false + } + for newPodsNeeded >= newScSize { + newSc, _ := s.calcNextSubcluster(scMap) + s.Vdb.Spec.Subclusters = append(s.Vdb.Spec.Subclusters, *newSc) + scMap[newSc.Name] = &s.Vdb.Spec.Subclusters[len(s.Vdb.Spec.Subclusters)-1] + newPodsNeeded -= newSc.Size + s.VRec.Log.Info("Adding subcluster to VerticaDB", "VerticaDB", s.Vdb.Name, "Subcluster", newSc.Name, "Size", newSc.Size) + } + return origNumSubclusters != len(s.Vdb.Spec.Subclusters) +} + +// genNextSubclusterName will come up with a unique name to give a new subcluster +func (s *SubclusterScaleReconciler) genNextSubclusterName(scMap map[string]*vapi.Subcluster) string { + baseName := s.Vas.Spec.Template.Name + if baseName == "" { + baseName = s.Vas.Name + } + i := 0 + for { + name := fmt.Sprintf("%s-%d", baseName, i) + _, ok := scMap[name] + if !ok { + return name + } + i++ + } +} + +// calcNextSubclusterSize returns the size of the next subcluster +func (s *SubclusterScaleReconciler) calcNextSubclusterSize(scMap map[string]*vapi.Subcluster) (int32, bool) { + newSc, ok := s.calcNextSubcluster(scMap) + if !ok { + return 0, false + } + return newSc.Size, true +} + +// calcNextSubcluster build the next subcluster that we want to add to the vdb. +// Returns false for second parameter if unable to construct one. An event will +// be logged if this happens. +func (s *SubclusterScaleReconciler) calcNextSubcluster(scMap map[string]*vapi.Subcluster) (*vapi.Subcluster, bool) { + // If the template is set, we will use that. Otherwise, we try to use an + // existing subcluster (last one added) as a base. + if s.Vas.CanUseTemplate() { + sc := s.Vas.Spec.Template.DeepCopy() + sc.Name = s.genNextSubclusterName(scMap) + return sc, true + } + scs, _ := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) + if len(scs) == 0 { + msg := "Could not determine size of the next subcluster. Template in VerticaAutoscaler " + msg += "is empty and no existing subcluster can be used as a base" + s.VRec.Log.Info(msg) + s.VRec.EVRec.Event(s.Vas, corev1.EventTypeWarning, events.NoSubclusterTemplate, msg) + return nil, false + } + newSc := scs[len(scs)-1].DeepCopy() + newSc.ServiceName = s.Vas.Spec.ServiceName + newSc.Name = s.genNextSubclusterName(scMap) + return newSc, true +} diff --git a/pkg/controllers/vas/subclusterscale_reconcile_test.go b/pkg/controllers/vas/subclusterscale_reconcile_test.go new file mode 100644 index 000000000..c20f5c17c --- /dev/null +++ b/pkg/controllers/vas/subclusterscale_reconcile_test.go @@ -0,0 +1,221 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + "fmt" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/test" + ctrl "sigs.k8s.io/controller-runtime" +) + +var _ = Describe("subclusterscale_reconcile", func() { + ctx := context.Background() + + It("should grow by adding new subclusters", func() { + vdb := vapi.MakeVDB() + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity + vas.Spec.Template = vapi.Subcluster{ + Name: "blah", + ServiceName: "my-ut", + Size: 8, + } + vas.Spec.TargetSize = vas.Spec.Template.Size * 2 + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + nm := vapi.MakeVDBName() + Expect(k8sClient.Get(ctx, nm, fetchVdb)).Should(Succeed()) + Expect(len(fetchVdb.Spec.Subclusters)).Should(Equal(3)) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[0].Size)) + Expect(fetchVdb.Spec.Subclusters[1].Size).Should(Equal(vas.Spec.Template.Size)) + Expect(fetchVdb.Spec.Subclusters[1].Name).Should(Equal("blah-0")) + Expect(fetchVdb.Spec.Subclusters[2].Size).Should(Equal(vas.Spec.Template.Size)) + Expect(fetchVdb.Spec.Subclusters[2].Name).Should(Equal("blah-1")) + }) + + It("should shrink only when delta from targetPod is an entire subcluster", func() { + vdb := vapi.MakeVDB() + const ServiceName = "as" + vdb.Spec.Subclusters = []vapi.Subcluster{ + {Name: "sc1", Size: 5, ServiceName: ServiceName}, + {Name: "sc2", Size: 20, ServiceName: "pri"}, + {Name: "sc3a", Size: 1, ServiceName: ServiceName}, + {Name: "sc3b", Size: 9, ServiceName: ServiceName}, + {Name: "sc4", Size: 7, ServiceName: "other-svc"}, + {Name: "sc5", Size: 2, ServiceName: ServiceName}, + } + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity + vas.Spec.ServiceName = ServiceName + vas.Spec.Template = vapi.Subcluster{ + Name: "blah", + ServiceName: ServiceName, + Size: 5, + } + vas.Spec.TargetSize = 8 + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + vdbName := vdb.ExtractNamespacedName() + Expect(k8sClient.Get(ctx, vdbName, fetchVdb)).Should(Succeed()) + Expect(len(fetchVdb.Spec.Subclusters)).Should(Equal(5)) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[0].Size)) + Expect(fetchVdb.Spec.Subclusters[1].Size).Should(Equal(vdb.Spec.Subclusters[1].Size)) + Expect(fetchVdb.Spec.Subclusters[2].Size).Should(Equal(vdb.Spec.Subclusters[2].Size)) + Expect(fetchVdb.Spec.Subclusters[3].Size).Should(Equal(vdb.Spec.Subclusters[3].Size)) + Expect(fetchVdb.Spec.Subclusters[4].Size).Should(Equal(vdb.Spec.Subclusters[4].Size)) + + vasName := vapi.MakeVASName() + Expect(k8sClient.Get(ctx, vasName, vas)).Should(Succeed()) + vas.Spec.TargetSize = 3 + Expect(k8sClient.Update(ctx, vas)).Should(Succeed()) + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + Expect(k8sClient.Get(ctx, vdbName, fetchVdb)).Should(Succeed()) + Expect(len(fetchVdb.Spec.Subclusters)).Should(Equal(3)) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[0].Size)) + Expect(fetchVdb.Spec.Subclusters[1].Size).Should(Equal(vdb.Spec.Subclusters[1].Size)) + Expect(fetchVdb.Spec.Subclusters[2].Size).Should(Equal(vdb.Spec.Subclusters[4].Size)) + }) + + It("should get rid of all subclusters if shrinking to zero is allowed", func() { + vdb := vapi.MakeVDB() + const ServiceName = "as" + vdb.Spec.Subclusters = []vapi.Subcluster{ + {Name: "sc1", Size: 5, ServiceName: ServiceName}, + {Name: "sc2", Size: 20, ServiceName: "pri"}, + {Name: "sc3", Size: 9, ServiceName: ServiceName}, + {Name: "sc4", Size: 7, ServiceName: "pri"}, + {Name: "sc5", Size: 3, ServiceName: ServiceName}, + } + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity + vas.Spec.ServiceName = ServiceName + vas.Spec.Template = vapi.Subcluster{ + Name: "blah", + ServiceName: ServiceName, + Size: 5, + } + vas.Spec.TargetSize = 0 + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + vdbName := vdb.ExtractNamespacedName() + Expect(k8sClient.Get(ctx, vdbName, fetchVdb)).Should(Succeed()) + // Expect no change since targetSize is zero without allowScaleToZero + Expect(len(fetchVdb.Spec.Subclusters)).Should(Equal(5)) + + vasName := vapi.MakeVASName() + Expect(k8sClient.Get(ctx, vasName, vas)).Should(Succeed()) + vas.Spec.TargetSize = 0 + Expect(k8sClient.Update(ctx, vas)).Should(Succeed()) + + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + Expect(k8sClient.Get(ctx, vdbName, fetchVdb)).Should(Succeed()) + Expect(len(fetchVdb.Spec.Subclusters)).Should(Equal(2)) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[1].Size)) + Expect(fetchVdb.Spec.Subclusters[1].Size).Should(Equal(vdb.Spec.Subclusters[3].Size)) + }) + + It("should use an existing subcluster as base if scaling out", func() { + vdb := vapi.MakeVDB() + const ServiceName = "as" + vdb.Spec.Subclusters = []vapi.Subcluster{ + {Name: "base", Size: 5, ServiceName: ServiceName}, + } + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity + vas.Spec.ServiceName = ServiceName + vas.Spec.Template.Size = 0 + vas.Spec.TargetSize = 8 + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + vdbName := vdb.ExtractNamespacedName() + Expect(k8sClient.Get(ctx, vdbName, fetchVdb)).Should(Succeed()) + Expect(len(fetchVdb.Spec.Subclusters)).Should(Equal(1)) + + vasName := vapi.MakeVASName() + Expect(k8sClient.Get(ctx, vasName, vas)).Should(Succeed()) + vas.Spec.TargetSize = 13 + Expect(k8sClient.Update(ctx, vas)).Should(Succeed()) + + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + Expect(k8sClient.Get(ctx, vdbName, fetchVdb)).Should(Succeed()) + Expect(len(fetchVdb.Spec.Subclusters)).Should(Equal(2)) + Expect(fetchVdb.Spec.Subclusters[0].Size).Should(Equal(vdb.Spec.Subclusters[0].Size)) + Expect(fetchVdb.Spec.Subclusters[1].Size).Should(Equal(vdb.Spec.Subclusters[0].Size)) + Expect(fetchVdb.Spec.Subclusters[1].Name).Should(Equal(fmt.Sprintf("%s-0", vas.Name))) + Expect(fetchVdb.Spec.Subclusters[1].ServiceName).Should(Equal(ServiceName)) + }) + + It("should not scale out if no template or existing subcluster can be used", func() { + vdb := vapi.MakeVDB() + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity + vas.Spec.ServiceName = "BrandNewServiceName" + vas.Spec.Template.Size = 0 + vas.Spec.TargetSize = 50 + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVdb := &vapi.VerticaDB{} + vdbName := vdb.ExtractNamespacedName() + Expect(k8sClient.Get(ctx, vdbName, fetchVdb)).Should(Succeed()) + Expect(len(fetchVdb.Spec.Subclusters)).Should(Equal(1)) + }) +}) diff --git a/pkg/controllers/vas/suite_test.go b/pkg/controllers/vas/suite_test.go new file mode 100644 index 000000000..727a3147f --- /dev/null +++ b/pkg/controllers/vas/suite_test.go @@ -0,0 +1,90 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "path/filepath" + "testing" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/builder" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +var k8sClient client.Client +var testEnv *envtest.Environment +var logger logr.Logger +var restCfg *rest.Config +var vasRec *VerticaAutoscalerReconciler + +var _ = BeforeSuite(func() { + logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)) + logf.SetLogger(logger) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + cfg, err := testEnv.Start() + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + ExpectWithOffset(1, cfg).NotTo(BeNil()) + restCfg = cfg + + err = vapi.AddToScheme(scheme.Scheme) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + k8sClient, err = client.New(restCfg, client.Options{Scheme: scheme.Scheme}) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + mgr, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme.Scheme, + MetricsBindAddress: "0", // Disable metrics for the test + }) + Expect(err).NotTo(HaveOccurred()) + + vasRec = &VerticaAutoscalerReconciler{ + Client: k8sClient, + Log: logger, + Scheme: scheme.Scheme, + EVRec: mgr.GetEventRecorderFor(builder.OperatorName), + } +}, 60) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + ExpectWithOffset(1, err).NotTo(HaveOccurred()) +}) + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecsWithDefaultAndCustomReporters(t, + "vas Suite", + []Reporter{printer.NewlineReporter{}}) +} diff --git a/pkg/controllers/vas/targetsizeinitializer_reconcile.go b/pkg/controllers/vas/targetsizeinitializer_reconcile.go new file mode 100644 index 000000000..53d2c3592 --- /dev/null +++ b/pkg/controllers/vas/targetsizeinitializer_reconcile.go @@ -0,0 +1,84 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/vasstatus" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" +) + +type TargetSizeInitializerReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler +} + +func MakeTargetSizeInitializerReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { + return &TargetSizeInitializerReconciler{VRec: v, Vas: vas} +} + +// Reconcile will update the targetSize in a Vas if not already initialized +func (v *TargetSizeInitializerReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + if len(v.Vas.Status.Conditions) > vapi.TargetSizeInitializedIndex && + v.Vas.Status.Conditions[vapi.TargetSizeInitializedIndex].Status == corev1.ConditionTrue { + // Already initialized + return ctrl.Result{}, nil + } + + if v.Vas.Spec.TargetSize == 0 { + if res, err := v.initTargetSize(ctx); verrors.IsReconcileAborted(res, err) { + return res, err + } + } + return ctrl.Result{}, v.setTargetSizeInitializedCondition(ctx, req) +} + +// initTargetSize will calculate what the targetSize is based on the current vdb. +func (v *TargetSizeInitializerReconciler) initTargetSize(ctx context.Context) (ctrl.Result, error) { + vdb := &vapi.VerticaDB{} + res := ctrl.Result{} + + err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + var e error + if res, e = fetchVDB(ctx, v.VRec, v.Vas, vdb); verrors.IsReconcileAborted(res, e) { + return e + } + _, totSize := vdb.FindSubclusterForServiceName(v.Vas.Spec.ServiceName) + + if v.Vas.Spec.TargetSize != totSize { + v.VRec.Log.Info("Updating targetSize in vas", "targetSize", totSize) + v.Vas.Spec.TargetSize = totSize + return v.VRec.Client.Update(ctx, v.Vas) + } + return nil + }) + return res, err +} + +// setTargetSizeInitializedCondition will seth the targetSizeInitialized condition to true +func (v *TargetSizeInitializerReconciler) setTargetSizeInitializedCondition(ctx context.Context, req *ctrl.Request) error { + cond := vapi.VerticaAutoscalerCondition{ + Type: vapi.TargetSizeInitialized, + Status: corev1.ConditionTrue, + } + return vasstatus.UpdateCondition(ctx, v.VRec.Client, v.VRec.Log, req, cond) +} diff --git a/pkg/controllers/vas/targetsizeinitializer_reconcile_test.go b/pkg/controllers/vas/targetsizeinitializer_reconcile_test.go new file mode 100644 index 000000000..a37a725bb --- /dev/null +++ b/pkg/controllers/vas/targetsizeinitializer_reconcile_test.go @@ -0,0 +1,58 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/test" + corev1 "k8s.io/api/core/v1" + ctrl "sigs.k8s.io/controller-runtime" +) + +var _ = Describe("targetsizeinitializer_reconcile", func() { + ctx := context.Background() + + It("should init the targetsize for a new vas", func() { + const ServiceName = "as" + vdb := vapi.MakeVDB() + vdb.Spec.Subclusters = []vapi.Subcluster{ + {Name: "sc1", Size: 10, ServiceName: ServiceName}, + {Name: "sc2", Size: 15, ServiceName: ServiceName}, + } + test.CreateVDB(ctx, k8sClient, vdb) + defer test.DeleteVDB(ctx, k8sClient, vdb) + + vas := vapi.MakeVAS() + vas.Spec.ServiceName = ServiceName + vas.Spec.TargetSize = 0 + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + req := ctrl.Request{NamespacedName: vapi.MakeVASName()} + Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) + + fetchVas := &vapi.VerticaAutoscaler{} + nm := vapi.MakeVASName() + Expect(k8sClient.Get(ctx, nm, fetchVas)).Should(Succeed()) + Expect(fetchVas.Spec.TargetSize).Should(Equal(int32(25))) + Expect(len(fetchVas.Status.Conditions)).Should(Equal(1)) + Expect(fetchVas.Status.Conditions[vapi.TargetSizeInitializedIndex].Status).Should(Equal(corev1.ConditionTrue)) + }) +}) diff --git a/pkg/controllers/vas/vdbverify_reconcile.go b/pkg/controllers/vas/vdbverify_reconcile.go new file mode 100644 index 000000000..15d445a83 --- /dev/null +++ b/pkg/controllers/vas/vdbverify_reconcile.go @@ -0,0 +1,43 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vas + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + ctrl "sigs.k8s.io/controller-runtime" +) + +// VDBVerifyReconciler will verify the VerticaDB in the VAS CR exists +type VDBVerifyReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler + Vdb *vapi.VerticaDB +} + +func MakeVDBVerifyReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { + return &VDBVerifyReconciler{VRec: r, Vas: vas, Vdb: &vapi.VerticaDB{}} +} + +// Reconcile will verify the VerticaDB in the VAS CR exists +func (s *VDBVerifyReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + // This reconciler is intended to be the first thing we run. We want early + // feedback if the VerticaDB that is referenced in the vas doesn't exist. + // This will print out an event if the VerticaDB cannot be found. + return fetchVDB(ctx, s.VRec, s.Vas, s.Vdb) +} diff --git a/pkg/controllers/vas/verticaautoscaler_controller.go b/pkg/controllers/vas/verticaautoscaler_controller.go new file mode 100644 index 000000000..414fc5343 --- /dev/null +++ b/pkg/controllers/vas/verticaautoscaler_controller.go @@ -0,0 +1,112 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vas + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/go-logr/logr" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" +) + +// VerticaAutoscalerReconciler reconciles a VerticaAutoscaler object +type VerticaAutoscalerReconciler struct { + client.Client + Scheme *runtime.Scheme + Log logr.Logger + EVRec record.EventRecorder +} + +//nolint:lll +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticaautoscalers,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticaautoscalers/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticaautoscalers/finalizers,verbs=update +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticadbs,verbs=get;list;create;update;patch;delete + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.0/pkg/reconcile +func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := r.Log.WithValues("verticaautoscaler", req.NamespacedName) + log.Info("starting reconcile of VerticaAutoscaler") + + var res ctrl.Result + vas := &vapi.VerticaAutoscaler{} + err := r.Get(ctx, req.NamespacedName, vas) + if err != nil { + if errors.IsNotFound(err) { + log.Info("VerticaAutoscaler resource not found. Ignoring since object must be deleted") + return ctrl.Result{}, nil + } + log.Error(err, "failed to get VerticaAutoscaler") + return ctrl.Result{}, err + } + + // The actors that will be applied, in sequence, to reconcile a vas. + actors := []controllers.ReconcileActor{ + // Sanity check to make sure the VerticaDB referenced in vas actually exists. + MakeVDBVerifyReconciler(r, vas), + // Initialize targetSize in new VerticaAutoscaler objects + MakeTargetSizeInitializerReconciler(r, vas), + // Update the currentSize in the status + MakeRefreshCurrentSizeReconciler(r, vas), + // Update the selector in the status + MakeRefreshSelectorReconciler(r, vas), + // If scaling granularity is Pod, this will resize existing subclusters + // depending on the targetSize. + MakeSubclusterResizeReconciler(r, vas), + // If scaling granularity is Subcluster, this will create or delete + // entire subcluster to match the targetSize. + MakeSubclusterScaleReconciler(r, vas), + } + + // Iterate over each actor + for _, act := range actors { + log.Info("starting actor", "name", fmt.Sprintf("%T", act)) + res, err = act.Reconcile(ctx, &req) + // Error or a request to requeue will stop the reconciliation. + if verrors.IsReconcileAborted(res, err) { + log.Info("aborting reconcile of VerticaAutoscaler", "result", res, "err", err) + return res, err + } + } + + log.Info("ending reconcile of VerticaAutoscaler", "result", res, "err", err) + return res, err +} + +// SetupWithManager sets up the controller with the Manager. +func (r *VerticaAutoscalerReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&vapi.VerticaAutoscaler{}). + // Not a strict ownership, but this is used so that the operator will + // reconcile the VerticaAutoscaler for any change in the VerticaDB. + // This ensures the status fields are kept up to date. + Owns(&vapi.VerticaDB{}). + Complete(r) +} diff --git a/pkg/controllers/vb/k8s.go b/pkg/controllers/vb/k8s.go new file mode 100644 index 000000000..b39579d36 --- /dev/null +++ b/pkg/controllers/vb/k8s.go @@ -0,0 +1,59 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vb + +import ( + "context" + "fmt" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/events" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// fetchVdbOrVa will fetch the VerticaDB/VerticaArchive that is referenced in a VerticaBackup. +// This will log an event if the VerticaDB/VerticaArchive is not found. +func fetchVdbOrVa(ctx context.Context, vburec *VerticaBackupReconciler, + vbu *vapi.VerticaBackup, nm types.NamespacedName, obj client.Object) (ctrl.Result, error) { + err := vburec.Client.Get(ctx, nm, obj) + if err != nil && errors.IsNotFound(err) { + event := "" + objType := "" + ownedObjName := "" + switch v := obj.(type) { + case *vapi.VerticaDB: + event = events.VerticaDBNotFound + objType = vapi.VerticaDBKind + ownedObjName = vbu.Spec.VerticaDBName + case *vapi.VerticaArchive: + event = events.VerticaArchiveNotFound + objType = vapi.VerticaArchiveKind + ownedObjName = vbu.Spec.Archive + default: + event = events.ObjectNotFound + objType = fmt.Sprintf("%T", v) + ownedObjName = "Unknown" + } + vburec.EVRec.Eventf(vbu, corev1.EventTypeWarning, event, + "The '%s' named '%s' was not found", objType, ownedObjName) + return ctrl.Result{Requeue: true}, nil + } + return ctrl.Result{}, err +} diff --git a/pkg/controllers/vb/vaverify_reconcile.go b/pkg/controllers/vb/vaverify_reconcile.go new file mode 100644 index 000000000..2dfdffe22 --- /dev/null +++ b/pkg/controllers/vb/vaverify_reconcile.go @@ -0,0 +1,42 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +//nolint:dupl +package vb + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + ctrl "sigs.k8s.io/controller-runtime" +) + +// VAVerifyReconciler will verify the VerticaArchive in the VBU CR exists +type VAVerifyReconciler struct { + VBURec *VerticaBackupReconciler + Vbu *vapi.VerticaBackup + Varc *vapi.VerticaArchive +} + +func MakeVAVerifyReconciler(r *VerticaBackupReconciler, vbu *vapi.VerticaBackup) controllers.ReconcileActor { + return &VAVerifyReconciler{VBURec: r, Vbu: vbu, Varc: &vapi.VerticaArchive{}} +} + +// Reconcile will verify the VerticaArchive in the VBU CR exists +func (s *VAVerifyReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + varcNm := controllers.GetNamespacedName(s.Vbu.Namespace, s.Vbu.Spec.Archive) + // This reconciler is to get afeedback if the VerticaArchive that is referenced in the vbu doesn't exist. + // This will print out an event if the VerticaArchive cannot be found. + return fetchVdbOrVa(ctx, s.VBURec, s.Vbu, varcNm, s.Varc) +} diff --git a/pkg/controllers/vb/vdbverify_reconcile.go b/pkg/controllers/vb/vdbverify_reconcile.go new file mode 100644 index 000000000..9db2e2ac5 --- /dev/null +++ b/pkg/controllers/vb/vdbverify_reconcile.go @@ -0,0 +1,42 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +//nolint:dupl +package vb + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + ctrl "sigs.k8s.io/controller-runtime" +) + +// VDBVerifyReconciler will verify the VerticaDB in the VBU CR exists +type VDBVerifyReconciler struct { + VBURec *VerticaBackupReconciler + Vbu *vapi.VerticaBackup + Vdb *vapi.VerticaDB +} + +func MakeVDBVerifyReconciler(r *VerticaBackupReconciler, vbu *vapi.VerticaBackup) controllers.ReconcileActor { + return &VDBVerifyReconciler{VBURec: r, Vbu: vbu, Vdb: &vapi.VerticaDB{}} +} + +// Reconcile will verify the VerticaDB in the VBU CR exists +func (s *VDBVerifyReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + vdbNm := controllers.GetNamespacedName(s.Vbu.Namespace, s.Vbu.Spec.VerticaDBName) + // This reconciler is to get a feedback if the VerticaDB that is referenced in the vbu doesn't exist. + // This will print out an event if the VerticaDB cannot be found. + return fetchVdbOrVa(ctx, s.VBURec, s.Vbu, vdbNm, s.Vdb) +} diff --git a/pkg/controllers/vb/verticabackup_controller.go b/pkg/controllers/vb/verticabackup_controller.go new file mode 100644 index 000000000..90536f4cf --- /dev/null +++ b/pkg/controllers/vb/verticabackup_controller.go @@ -0,0 +1,97 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vb + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// VerticaBackupReconciler reconciles a VerticaBackup object +type VerticaBackupReconciler struct { + client.Client + Scheme *runtime.Scheme + Log logr.Logger + EVRec record.EventRecorder +} + +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticabackups,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticabackups/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticabackups/finalizers,verbs=update +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticadbs,verbs=get;list;create;update;patch;delete +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticaarchives,verbs=get;list;create;update;patch;delete + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.0/pkg/reconcile +func (r *VerticaBackupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := r.Log.WithValues("verticabackup", req.NamespacedName) + log.Info("starting reconcile of VerticaBackup") + + var res ctrl.Result + vb := &vapi.VerticaBackup{} + err := r.Get(ctx, req.NamespacedName, vb) + if err != nil { + if errors.IsNotFound(err) { + log.Info("VerticaBackup resource not found. Ignoring since object must be deleted") + return ctrl.Result{}, nil + } + log.Error(err, "failed to get VerticaBackup") + return ctrl.Result{}, err + } + + // The actors that will be applied, in sequence, to reconcile a vbu. + actors := []controllers.ReconcileActor{ + MakeVDBVerifyReconciler(r, vb), + MakeVAVerifyReconciler(r, vb), + } + + // Iterate over each actor + for _, act := range actors { + log.Info("starting actor", "name", fmt.Sprintf("%T", act)) + res, err = act.Reconcile(ctx, &req) + // Error or a request to requeue will stop the reconciliation. + if verrors.IsReconcileAborted(res, err) { + log.Info("aborting reconcile of VerticaBackup", "result", res, "err", err) + return res, err + } + } + + log.Info("ending reconcile of VerticaBackup", "result", res, "err", err) + return res, err +} + +// SetupWithManager sets up the controller with the Manager. +func (r *VerticaBackupReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&vapi.VerticaBackup{}). + // Not a strict ownership, but this is used so that the operator will + // reconcile the VerticaBackup for any change in the VerticaDB. + // This ensures the status fields are kept up to date. + Owns(&vapi.VerticaDB{}). + Owns(&vapi.VerticaArchive{}). + Complete(r) +} diff --git a/pkg/controllers/vdb/actor.go b/pkg/controllers/vdb/actor.go new file mode 100644 index 000000000..677cb7a8c --- /dev/null +++ b/pkg/controllers/vdb/actor.go @@ -0,0 +1,72 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vdb + +import ( + "context" + "fmt" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/names" + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/errors" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ScaledownActor is an interface that handles a part of scale down, either +// db_remove_node or uninstall. +type ScaledownActor interface { + GetClient() client.Client + GetVDB() *vapi.VerticaDB + CollectPFacts(ctx context.Context) error +} + +// scaledownSubcluster is called to either remove nodes or call uninstall. +// This is a common function that is used by the DBRemoveNodeReconciler and +// UninstallReconciler. It will call a func (scaleDownFunc) for a range of pods +// that are to be scaled down. +func scaledownSubcluster(ctx context.Context, act ScaledownActor, sc *vapi.Subcluster, + scaleDownFunc func(context.Context, *vapi.Subcluster, int32, int32) (ctrl.Result, error)) (ctrl.Result, error) { + if sc == nil { + return ctrl.Result{}, nil + } + sts := &appsv1.StatefulSet{} + if err := act.GetClient().Get(ctx, names.GenStsName(act.GetVDB(), sc), sts); err != nil { + // A non-existent statefulset is okay, as it might not have been created yet. + if errors.IsNotFound(err) { + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + + if sts.Status.Replicas > sc.Size { + if err := act.CollectPFacts(ctx); err != nil { + return ctrl.Result{}, err + } + + res, err := scaleDownFunc(ctx, sc, sc.Size, sts.Status.Replicas-1) + if err != nil { + return res, fmt.Errorf("failed to scale down nodes in subcluster %s: %w", sc.Name, err) + } + if verrors.IsReconcileAborted(res, err) { + return res, nil + } + } + + return ctrl.Result{}, nil +} diff --git a/pkg/controllers/at.go b/pkg/controllers/vdb/at.go similarity index 99% rename from pkg/controllers/at.go rename to pkg/controllers/vdb/at.go index 9305d5a70..b3efdea33 100644 --- a/pkg/controllers/at.go +++ b/pkg/controllers/vdb/at.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/at_test.go b/pkg/controllers/vdb/at_test.go similarity index 98% rename from pkg/controllers/at_test.go rename to pkg/controllers/vdb/at_test.go index 1e29c4165..5612fccdc 100644 --- a/pkg/controllers/at_test.go +++ b/pkg/controllers/vdb/at_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/clientroutinglabel_reconcile.go b/pkg/controllers/vdb/clientroutinglabel_reconcile.go similarity index 97% rename from pkg/controllers/clientroutinglabel_reconcile.go rename to pkg/controllers/vdb/clientroutinglabel_reconcile.go index 04a8fd9b7..6bd1c4425 100644 --- a/pkg/controllers/clientroutinglabel_reconcile.go +++ b/pkg/controllers/vdb/clientroutinglabel_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -21,6 +21,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -47,7 +48,7 @@ type ClientRoutingLabelReconciler struct { } func MakeClientRoutingLabelReconciler(vdbrecon *VerticaDBReconciler, - vdb *vapi.VerticaDB, pfacts *PodFacts, applyMethod ApplyMethodType, scName string) ReconcileActor { + vdb *vapi.VerticaDB, pfacts *PodFacts, applyMethod ApplyMethodType, scName string) controllers.ReconcileActor { return &ClientRoutingLabelReconciler{ VRec: vdbrecon, Vdb: vdb, diff --git a/pkg/controllers/clientroutinglabel_reconcile_test.go b/pkg/controllers/vdb/clientroutinglabel_reconcile_test.go similarity index 99% rename from pkg/controllers/clientroutinglabel_reconcile_test.go rename to pkg/controllers/vdb/clientroutinglabel_reconcile_test.go index 46d0e8dfc..4c6fa6314 100644 --- a/pkg/controllers/clientroutinglabel_reconcile_test.go +++ b/pkg/controllers/vdb/clientroutinglabel_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/createdb_reconcile.go b/pkg/controllers/vdb/createdb_reconcile.go similarity index 98% rename from pkg/controllers/createdb_reconcile.go rename to pkg/controllers/vdb/createdb_reconcile.go index 5ec9899d4..71008d580 100644 --- a/pkg/controllers/createdb_reconcile.go +++ b/pkg/controllers/vdb/createdb_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -27,6 +27,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cloud" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/license" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -53,7 +54,7 @@ type CreateDBReconciler struct { // MakeCreateDBReconciler will build a CreateDBReconciler object func MakeCreateDBReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &CreateDBReconciler{VRec: vdbrecon, Log: log, Vdb: vdb, PRunner: prunner, PFacts: pfacts} } diff --git a/pkg/controllers/createdb_reconcile_test.go b/pkg/controllers/vdb/createdb_reconcile_test.go similarity index 99% rename from pkg/controllers/createdb_reconcile_test.go rename to pkg/controllers/vdb/createdb_reconcile_test.go index 00ed1b178..42666feb7 100644 --- a/pkg/controllers/createdb_reconcile_test.go +++ b/pkg/controllers/vdb/createdb_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/dbaddnode_reconcile.go b/pkg/controllers/vdb/dbaddnode_reconcile.go similarity index 98% rename from pkg/controllers/dbaddnode_reconcile.go rename to pkg/controllers/vdb/dbaddnode_reconcile.go index 6e0e86582..3693d86ef 100644 --- a/pkg/controllers/dbaddnode_reconcile.go +++ b/pkg/controllers/vdb/dbaddnode_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -23,6 +23,7 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -42,7 +43,7 @@ type DBAddNodeReconciler struct { // MakeDBAddNodeReconciler will build a DBAddNodeReconciler object func MakeDBAddNodeReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &DBAddNodeReconciler{VRec: vdbrecon, Log: log, Vdb: vdb, PRunner: prunner, PFacts: pfacts} } diff --git a/pkg/controllers/dbaddnode_reconcile_test.go b/pkg/controllers/vdb/dbaddnode_reconcile_test.go similarity index 99% rename from pkg/controllers/dbaddnode_reconcile_test.go rename to pkg/controllers/vdb/dbaddnode_reconcile_test.go index a99a17f1c..28a5d60cd 100644 --- a/pkg/controllers/dbaddnode_reconcile_test.go +++ b/pkg/controllers/vdb/dbaddnode_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/dbaddsubcluster_reconcile.go b/pkg/controllers/vdb/dbaddsubcluster_reconcile.go similarity index 98% rename from pkg/controllers/dbaddsubcluster_reconcile.go rename to pkg/controllers/vdb/dbaddsubcluster_reconcile.go index 35c0bfe93..3ac40ff7d 100644 --- a/pkg/controllers/dbaddsubcluster_reconcile.go +++ b/pkg/controllers/vdb/dbaddsubcluster_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -22,6 +22,7 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -44,7 +45,7 @@ type SubclustersSet map[string]bool // MakeDBAddSubclusterReconciler will build a DBAddSubclusterReconciler object func MakeDBAddSubclusterReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &DBAddSubclusterReconciler{VRec: vdbrecon, Log: log, Vdb: vdb, PRunner: prunner, PFacts: pfacts} } diff --git a/pkg/controllers/dbaddsubcluster_reconcile_test.go b/pkg/controllers/vdb/dbaddsubcluster_reconcile_test.go similarity index 99% rename from pkg/controllers/dbaddsubcluster_reconcile_test.go rename to pkg/controllers/vdb/dbaddsubcluster_reconcile_test.go index c1bd656a7..56b493d18 100644 --- a/pkg/controllers/dbaddsubcluster_reconcile_test.go +++ b/pkg/controllers/vdb/dbaddsubcluster_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/dbremovenode_reconcile.go b/pkg/controllers/vdb/dbremovenode_reconcile.go similarity index 98% rename from pkg/controllers/dbremovenode_reconcile.go rename to pkg/controllers/vdb/dbremovenode_reconcile.go index 82b5fc7f5..6f38b7783 100644 --- a/pkg/controllers/dbremovenode_reconcile.go +++ b/pkg/controllers/vdb/dbremovenode_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -24,6 +24,7 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/iter" @@ -45,7 +46,7 @@ type DBRemoveNodeReconciler struct { // MakeDBRemoveNodeReconciler will build and return the DBRemoveNodeReconciler object. func MakeDBRemoveNodeReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &DBRemoveNodeReconciler{ VRec: vdbrecon, Log: log, diff --git a/pkg/controllers/dbremovenode_reconcile_test.go b/pkg/controllers/vdb/dbremovenode_reconcile_test.go similarity index 99% rename from pkg/controllers/dbremovenode_reconcile_test.go rename to pkg/controllers/vdb/dbremovenode_reconcile_test.go index a4c655b95..7d0b4e619 100644 --- a/pkg/controllers/dbremovenode_reconcile_test.go +++ b/pkg/controllers/vdb/dbremovenode_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/dbremovesubcluster_reconcile.go b/pkg/controllers/vdb/dbremovesubcluster_reconcile.go similarity index 98% rename from pkg/controllers/dbremovesubcluster_reconcile.go rename to pkg/controllers/vdb/dbremovesubcluster_reconcile.go index bf05eedeb..59a81722e 100644 --- a/pkg/controllers/dbremovesubcluster_reconcile.go +++ b/pkg/controllers/vdb/dbremovesubcluster_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -24,6 +24,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/iter" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -43,7 +44,7 @@ type DBRemoveSubclusterReconciler struct { // MakeDBRemoveSubclusterReconciler will build a DBRemoveSubclusterReconciler object func MakeDBRemoveSubclusterReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &DBRemoveSubclusterReconciler{VRec: vdbrecon, Log: log, Vdb: vdb, PRunner: prunner, PFacts: pfacts} } diff --git a/pkg/controllers/dbremovesubcluster_reconcile_test.go b/pkg/controllers/vdb/dbremovesubcluster_reconcile_test.go similarity index 99% rename from pkg/controllers/dbremovesubcluster_reconcile_test.go rename to pkg/controllers/vdb/dbremovesubcluster_reconcile_test.go index 9f5954b3b..5fe6db532 100644 --- a/pkg/controllers/dbremovesubcluster_reconcile_test.go +++ b/pkg/controllers/vdb/dbremovesubcluster_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/drainnode_reconcile.go b/pkg/controllers/vdb/drainnode_reconcile.go similarity index 96% rename from pkg/controllers/drainnode_reconcile.go rename to pkg/controllers/vdb/drainnode_reconcile.go index 5b172b73b..e187b264d 100644 --- a/pkg/controllers/drainnode_reconcile.go +++ b/pkg/controllers/vdb/drainnode_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -21,6 +21,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -36,7 +37,7 @@ type DrainNodeReconciler struct { } func MakeDrainNodeReconciler(vdbrecon *VerticaDBReconciler, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &DrainNodeReconciler{ VRec: vdbrecon, Vdb: vdb, diff --git a/pkg/controllers/drainnode_reconcile_test.go b/pkg/controllers/vdb/drainnode_reconcile_test.go similarity index 99% rename from pkg/controllers/drainnode_reconcile_test.go rename to pkg/controllers/vdb/drainnode_reconcile_test.go index e70061ff5..10b9e1c4f 100644 --- a/pkg/controllers/drainnode_reconcile_test.go +++ b/pkg/controllers/vdb/drainnode_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/init_db.go b/pkg/controllers/vdb/init_db.go similarity index 99% rename from pkg/controllers/init_db.go rename to pkg/controllers/vdb/init_db.go index 215d0230f..85518c31e 100644 --- a/pkg/controllers/init_db.go +++ b/pkg/controllers/vdb/init_db.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -30,7 +30,7 @@ import ( "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" "github.com/vertica/vertica-kubernetes/pkg/paths" - "github.com/vertica/vertica-kubernetes/pkg/status" + "github.com/vertica/vertica-kubernetes/pkg/vdbstatus" "github.com/vertica/vertica-kubernetes/pkg/version" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -127,7 +127,7 @@ func (g *GenericDatabaseInitializer) runInit(ctx context.Context) (ctrl.Result, debugDumpAdmintoolsConf(ctx, g.PRunner, atPod) cond := vapi.VerticaDBCondition{Type: vapi.DBInitialized, Status: corev1.ConditionTrue} - if err := status.UpdateCondition(ctx, g.VRec.Client, g.Vdb, cond); err != nil { + if err := vdbstatus.UpdateCondition(ctx, g.VRec.Client, g.Vdb, cond); err != nil { return ctrl.Result{}, err } diff --git a/pkg/controllers/init_db_test.go b/pkg/controllers/vdb/init_db_test.go similarity index 99% rename from pkg/controllers/init_db_test.go rename to pkg/controllers/vdb/init_db_test.go index 6067646fd..dd88bb58e 100644 --- a/pkg/controllers/init_db_test.go +++ b/pkg/controllers/vdb/init_db_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/install_reconcile.go b/pkg/controllers/vdb/install_reconcile.go similarity index 99% rename from pkg/controllers/install_reconcile.go rename to pkg/controllers/vdb/install_reconcile.go index a551232ad..2225778fb 100644 --- a/pkg/controllers/install_reconcile.go +++ b/pkg/controllers/vdb/install_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -27,6 +27,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/atconf" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" "github.com/vertica/vertica-kubernetes/pkg/names" "github.com/vertica/vertica-kubernetes/pkg/paths" "k8s.io/apimachinery/pkg/types" @@ -45,7 +46,7 @@ type InstallReconciler struct { // MakeInstallReconciler will build and return the InstallReconciler object. func MakeInstallReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &InstallReconciler{ VRec: vdbrecon, Log: log, diff --git a/pkg/controllers/install_reconcile_test.go b/pkg/controllers/vdb/install_reconcile_test.go similarity index 99% rename from pkg/controllers/install_reconcile_test.go rename to pkg/controllers/vdb/install_reconcile_test.go index ad49e400e..4d64186b0 100644 --- a/pkg/controllers/install_reconcile_test.go +++ b/pkg/controllers/vdb/install_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/vdb/k8s.go b/pkg/controllers/vdb/k8s.go new file mode 100644 index 000000000..d781a7416 --- /dev/null +++ b/pkg/controllers/vdb/k8s.go @@ -0,0 +1,74 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vdb + +import ( + "context" + "fmt" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/events" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// getSecret is a generic function to get a secret and return its contents. If +// the secret is not found, an event is logged and the reconciliation is +// requeued. +func getSecret(ctx context.Context, vrec *VerticaDBReconciler, vdb *vapi.VerticaDB, + nm types.NamespacedName) (*corev1.Secret, ctrl.Result, error) { + secret := &corev1.Secret{} + res, err := getConfigMapOrSecret(ctx, vrec, vdb, nm, secret) + return secret, res, err +} + +// getConfigMap is like getSecret except that it works for configMap's. It the +// configMap is not found, then the ctrl.Result returned will indicate a requeue +// is needed. +func getConfigMap(ctx context.Context, vrec *VerticaDBReconciler, vdb *vapi.VerticaDB, + nm types.NamespacedName) (*corev1.ConfigMap, ctrl.Result, error) { + cm := &corev1.ConfigMap{} + res, err := getConfigMapOrSecret(ctx, vrec, vdb, nm, cm) + return cm, res, err +} + +// getConfigMapOrSecret is a generic function to fetch a ConfigMap or a Secret. +// It will handle logging an event if the configMap or secret is missing. +func getConfigMapOrSecret(ctx context.Context, vrec *VerticaDBReconciler, vdb *vapi.VerticaDB, + nm types.NamespacedName, obj client.Object) (ctrl.Result, error) { + if err := vrec.Client.Get(ctx, nm, obj); err != nil { + if errors.IsNotFound(err) { + objType := "" + switch v := obj.(type) { + default: + objType = fmt.Sprintf("%T", v) + case *corev1.Secret: + objType = "Secret" + case *corev1.ConfigMap: + objType = "ConfigMap" + } + vrec.EVRec.Eventf(vdb, corev1.EventTypeWarning, events.ObjectNotFound, + "Could not find the %s '%s'", objType, nm) + return ctrl.Result{Requeue: true}, nil + } + return ctrl.Result{}, + fmt.Errorf("could not read the secret %s: %w", nm, err) + } + return ctrl.Result{}, nil +} diff --git a/pkg/controllers/k8s_test.go b/pkg/controllers/vdb/k8s_test.go similarity index 99% rename from pkg/controllers/k8s_test.go rename to pkg/controllers/vdb/k8s_test.go index dc8463a46..da283e680 100644 --- a/pkg/controllers/k8s_test.go +++ b/pkg/controllers/vdb/k8s_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/obj_reconcile.go b/pkg/controllers/vdb/obj_reconcile.go similarity index 99% rename from pkg/controllers/obj_reconcile.go rename to pkg/controllers/vdb/obj_reconcile.go index 6d6b81ecd..822cf34c1 100644 --- a/pkg/controllers/obj_reconcile.go +++ b/pkg/controllers/vdb/obj_reconcile.go @@ -14,7 +14,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -25,6 +25,7 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/iter" @@ -65,7 +66,7 @@ type ObjReconciler struct { // MakeObjReconciler will build an ObjReconciler object func MakeObjReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, vdb *vapi.VerticaDB, pfacts *PodFacts, - mode ObjReconcileModeType) ReconcileActor { + mode ObjReconcileModeType) controllers.ReconcileActor { return &ObjReconciler{ VRec: vdbrecon, Log: log, diff --git a/pkg/controllers/obj_reconcile_test.go b/pkg/controllers/vdb/obj_reconcile_test.go similarity index 99% rename from pkg/controllers/obj_reconcile_test.go rename to pkg/controllers/vdb/obj_reconcile_test.go index 3c7decfdb..6d4038dfe 100644 --- a/pkg/controllers/obj_reconcile_test.go +++ b/pkg/controllers/vdb/obj_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/offlineupgrade_reconcile.go b/pkg/controllers/vdb/offlineupgrade_reconcile.go similarity index 99% rename from pkg/controllers/offlineupgrade_reconcile.go rename to pkg/controllers/vdb/offlineupgrade_reconcile.go index 39a058674..b66e5101d 100644 --- a/pkg/controllers/offlineupgrade_reconcile.go +++ b/pkg/controllers/vdb/offlineupgrade_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -23,6 +23,7 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/iter" @@ -58,7 +59,7 @@ var OfflineUpgradeStatusMsgs = []string{ // MakeOfflineUpgradeReconciler will build an OfflineUpgradeReconciler object func MakeOfflineUpgradeReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &OfflineUpgradeReconciler{VRec: vdbrecon, Log: log, Vdb: vdb, PRunner: prunner, PFacts: pfacts, Finder: iter.MakeSubclusterFinder(vdbrecon.Client, vdb), Manager: *MakeUpgradeManager(vdbrecon, log, vdb, vapi.OfflineUpgradeInProgress, offlineUpgradeAllowed), diff --git a/pkg/controllers/offlineupgrade_reconcile_test.go b/pkg/controllers/vdb/offlineupgrade_reconcile_test.go similarity index 99% rename from pkg/controllers/offlineupgrade_reconcile_test.go rename to pkg/controllers/vdb/offlineupgrade_reconcile_test.go index a97880f58..b1589db81 100644 --- a/pkg/controllers/offlineupgrade_reconcile_test.go +++ b/pkg/controllers/vdb/offlineupgrade_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/onlineupgrade_reconcile_test.go b/pkg/controllers/vdb/onlineupgrade_reconcile_test.go similarity index 99% rename from pkg/controllers/onlineupgrade_reconcile_test.go rename to pkg/controllers/vdb/onlineupgrade_reconcile_test.go index ac4907004..3ef174043 100644 --- a/pkg/controllers/onlineupgrade_reconcile_test.go +++ b/pkg/controllers/vdb/onlineupgrade_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/onlineupgrade_reconciler.go b/pkg/controllers/vdb/onlineupgrade_reconciler.go similarity index 99% rename from pkg/controllers/onlineupgrade_reconciler.go rename to pkg/controllers/vdb/onlineupgrade_reconciler.go index 878567395..1cb2510a8 100644 --- a/pkg/controllers/onlineupgrade_reconciler.go +++ b/pkg/controllers/vdb/onlineupgrade_reconciler.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -25,6 +25,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/iter" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -53,7 +54,7 @@ type OnlineUpgradeReconciler struct { // MakeOnlineUpgradeReconciler will build an OnlineUpgradeReconciler object func MakeOnlineUpgradeReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &OnlineUpgradeReconciler{VRec: vdbrecon, Log: log, Vdb: vdb, PRunner: prunner, PFacts: pfacts, Finder: iter.MakeSubclusterFinder(vdbrecon.Client, vdb), Manager: *MakeUpgradeManager(vdbrecon, log, vdb, vapi.OnlineUpgradeInProgress, onlineUpgradeAllowed), @@ -629,7 +630,7 @@ func (o *OnlineUpgradeReconciler) skipTransientSetup() bool { return !found } -func (o *OnlineUpgradeReconciler) traceActorReconcile(actor ReconcileActor) { +func (o *OnlineUpgradeReconciler) traceActorReconcile(actor controllers.ReconcileActor) { o.Log.Info("starting actor for online upgrade", "name", fmt.Sprintf("%T", actor)) } diff --git a/pkg/controllers/paths.go b/pkg/controllers/vdb/paths.go similarity index 99% rename from pkg/controllers/paths.go rename to pkg/controllers/vdb/paths.go index b5fd056da..85132d096 100644 --- a/pkg/controllers/paths.go +++ b/pkg/controllers/vdb/paths.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/podfacts.go b/pkg/controllers/vdb/podfacts.go similarity index 99% rename from pkg/controllers/podfacts.go rename to pkg/controllers/vdb/podfacts.go index 45d895678..8a2009f47 100644 --- a/pkg/controllers/podfacts.go +++ b/pkg/controllers/vdb/podfacts.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/podfacts_test.go b/pkg/controllers/vdb/podfacts_test.go similarity index 99% rename from pkg/controllers/podfacts_test.go rename to pkg/controllers/vdb/podfacts_test.go index 3295ab0ae..b5c9ec244 100644 --- a/pkg/controllers/podfacts_test.go +++ b/pkg/controllers/vdb/podfacts_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/rebalanceshards_reconcile.go b/pkg/controllers/vdb/rebalanceshards_reconcile.go similarity index 97% rename from pkg/controllers/rebalanceshards_reconcile.go rename to pkg/controllers/vdb/rebalanceshards_reconcile.go index cf129d3fc..a5ad5b278 100644 --- a/pkg/controllers/rebalanceshards_reconcile.go +++ b/pkg/controllers/vdb/rebalanceshards_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -22,6 +22,7 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" corev1 "k8s.io/api/core/v1" @@ -40,7 +41,7 @@ type RebalanceShardsReconciler struct { // MakeRebalanceShardsReconciler will build a RebalanceShardsReconciler object func MakeRebalanceShardsReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts, scName string) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts, scName string) controllers.ReconcileActor { return &RebalanceShardsReconciler{ VRec: vdbrecon, Log: log, diff --git a/pkg/controllers/rebalanceshards_reconciler_test.go b/pkg/controllers/vdb/rebalanceshards_reconciler_test.go similarity index 99% rename from pkg/controllers/rebalanceshards_reconciler_test.go rename to pkg/controllers/vdb/rebalanceshards_reconciler_test.go index ba593d3eb..b079a3f5c 100644 --- a/pkg/controllers/rebalanceshards_reconciler_test.go +++ b/pkg/controllers/vdb/rebalanceshards_reconciler_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/restart_reconcile.go b/pkg/controllers/vdb/restart_reconcile.go similarity index 98% rename from pkg/controllers/restart_reconcile.go rename to pkg/controllers/vdb/restart_reconcile.go index 82e63f216..f8a867910 100644 --- a/pkg/controllers/restart_reconcile.go +++ b/pkg/controllers/vdb/restart_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -25,11 +25,12 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" "github.com/vertica/vertica-kubernetes/pkg/paths" - "github.com/vertica/vertica-kubernetes/pkg/status" + "github.com/vertica/vertica-kubernetes/pkg/vdbstatus" "github.com/vertica/vertica-kubernetes/pkg/version" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -61,7 +62,7 @@ type RestartReconciler struct { // MakeRestartReconciler will build a RestartReconciler object func MakeRestartReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts, restartReadOnly bool) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts, restartReadOnly bool) controllers.ReconcileActor { return &RestartReconciler{VRec: vdbrecon, Log: log, Vdb: vdb, PRunner: prunner, PFacts: pfacts, RestartReadOnly: restartReadOnly} } @@ -70,13 +71,13 @@ func MakeRestartReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, // On success, each node will have a running vertica process. func (r *RestartReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { if !r.Vdb.Spec.AutoRestartVertica { - err := status.UpdateCondition(ctx, r.VRec.Client, r.Vdb, + err := vdbstatus.UpdateCondition(ctx, r.VRec.Client, r.Vdb, vapi.VerticaDBCondition{Type: vapi.AutoRestartVertica, Status: corev1.ConditionFalse}, ) return ctrl.Result{}, err } - err := status.UpdateCondition(ctx, r.VRec.Client, r.Vdb, + err := vdbstatus.UpdateCondition(ctx, r.VRec.Client, r.Vdb, vapi.VerticaDBCondition{Type: vapi.AutoRestartVertica, Status: corev1.ConditionTrue}, ) if err != nil { diff --git a/pkg/controllers/restart_reconciler_test.go b/pkg/controllers/vdb/restart_reconciler_test.go similarity index 99% rename from pkg/controllers/restart_reconciler_test.go rename to pkg/controllers/vdb/restart_reconciler_test.go index a35ddd409..0c9837544 100644 --- a/pkg/controllers/restart_reconciler_test.go +++ b/pkg/controllers/vdb/restart_reconciler_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/revivedb_reconcile.go b/pkg/controllers/vdb/revivedb_reconcile.go similarity index 98% rename from pkg/controllers/revivedb_reconcile.go rename to pkg/controllers/vdb/revivedb_reconcile.go index 05bfc61cb..54424631a 100644 --- a/pkg/controllers/revivedb_reconcile.go +++ b/pkg/controllers/vdb/revivedb_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -26,6 +26,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cloud" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" "github.com/vertica/vertica-kubernetes/pkg/paths" @@ -45,7 +46,7 @@ type ReviveDBReconciler struct { // MakeReviveDBReconciler will build a ReviveDBReconciler object func MakeReviveDBReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &ReviveDBReconciler{VRec: vdbrecon, Log: log, Vdb: vdb, PRunner: prunner, PFacts: pfacts} } diff --git a/pkg/controllers/revivedb_reconcile_test.go b/pkg/controllers/vdb/revivedb_reconcile_test.go similarity index 99% rename from pkg/controllers/revivedb_reconcile_test.go rename to pkg/controllers/vdb/revivedb_reconcile_test.go index d14afaaff..5237ee24b 100644 --- a/pkg/controllers/revivedb_reconcile_test.go +++ b/pkg/controllers/vdb/revivedb_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/status_reconcile.go b/pkg/controllers/vdb/status_reconcile.go similarity index 95% rename from pkg/controllers/status_reconcile.go rename to pkg/controllers/vdb/status_reconcile.go index 0ca3f9f97..c319e7b30 100644 --- a/pkg/controllers/status_reconcile.go +++ b/pkg/controllers/vdb/status_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -21,9 +21,10 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" "github.com/vertica/vertica-kubernetes/pkg/iter" "github.com/vertica/vertica-kubernetes/pkg/names" - "github.com/vertica/vertica-kubernetes/pkg/status" + "github.com/vertica/vertica-kubernetes/pkg/vdbstatus" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -42,7 +43,7 @@ type StatusReconciler struct { // MakeStatusReconciler will build a StatusReconciler object func MakeStatusReconciler(cli client.Client, scheme *runtime.Scheme, log logr.Logger, - vdb *vapi.VerticaDB, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, pfacts *PodFacts) controllers.ReconcileActor { return &StatusReconciler{Client: cli, Scheme: scheme, Log: log, Vdb: vdb, PFacts: pfacts} } @@ -75,7 +76,7 @@ func (s *StatusReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ct return nil } - if err := status.Update(ctx, s.Client, s.Vdb, refreshStatus); err != nil { + if err := vdbstatus.Update(ctx, s.Client, s.Vdb, refreshStatus); err != nil { return ctrl.Result{}, err } return ctrl.Result{}, nil diff --git a/pkg/controllers/status_reconcile_test.go b/pkg/controllers/vdb/status_reconcile_test.go similarity index 99% rename from pkg/controllers/status_reconcile_test.go rename to pkg/controllers/vdb/status_reconcile_test.go index 5597327b7..31b7fd65a 100644 --- a/pkg/controllers/status_reconcile_test.go +++ b/pkg/controllers/vdb/status_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/suite_test.go b/pkg/controllers/vdb/suite_test.go similarity index 98% rename from pkg/controllers/suite_test.go rename to pkg/controllers/vdb/suite_test.go index 35c95f7b0..83245df6a 100644 --- a/pkg/controllers/suite_test.go +++ b/pkg/controllers/vdb/suite_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -53,7 +53,7 @@ var _ = BeforeSuite(func() { By("bootstrapping test environment") testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, ErrorIfCRDPathMissing: true, } @@ -94,7 +94,7 @@ func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) RunSpecsWithDefaultAndCustomReporters(t, - "K8s Suite", + "vdb Suite", []Reporter{printer.NewlineReporter{}}) } diff --git a/pkg/controllers/uninstall_reconcile.go b/pkg/controllers/vdb/uninstall_reconcile.go similarity index 98% rename from pkg/controllers/uninstall_reconcile.go rename to pkg/controllers/vdb/uninstall_reconcile.go index 2b8b442d2..a30885f6b 100644 --- a/pkg/controllers/uninstall_reconcile.go +++ b/pkg/controllers/vdb/uninstall_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -24,6 +24,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/atconf" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/iter" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -44,7 +45,7 @@ type UninstallReconciler struct { // MakeUninstallReconciler will build and return the UninstallReconciler object. func MakeUninstallReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) ReconcileActor { + vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts) controllers.ReconcileActor { return &UninstallReconciler{ VRec: vdbrecon, Log: log, diff --git a/pkg/controllers/uninstall_reconcile_test.go b/pkg/controllers/vdb/uninstall_reconcile_test.go similarity index 99% rename from pkg/controllers/uninstall_reconcile_test.go rename to pkg/controllers/vdb/uninstall_reconcile_test.go index 145dbc8f3..4c299dd72 100644 --- a/pkg/controllers/uninstall_reconcile_test.go +++ b/pkg/controllers/vdb/uninstall_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/upgrade.go b/pkg/controllers/vdb/upgrade.go similarity index 97% rename from pkg/controllers/upgrade.go rename to pkg/controllers/vdb/upgrade.go index 3c5ffd4fa..0b7995681 100644 --- a/pkg/controllers/upgrade.go +++ b/pkg/controllers/vdb/upgrade.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -26,7 +26,7 @@ import ( "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/iter" "github.com/vertica/vertica-kubernetes/pkg/names" - "github.com/vertica/vertica-kubernetes/pkg/status" + "github.com/vertica/vertica-kubernetes/pkg/vdbstatus" "github.com/vertica/vertica-kubernetes/pkg/version" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -148,20 +148,20 @@ func (i *UpgradeManager) finishUpgrade(ctx context.Context) (ctrl.Result, error) // ImageChangeInProgress condition's. We set the ImageChangeInProgress plus the // one defined in i.StatusCondition. func (i *UpgradeManager) toggleImageChangeInProgress(ctx context.Context, newVal corev1.ConditionStatus) error { - err := status.UpdateCondition(ctx, i.VRec.Client, i.Vdb, + err := vdbstatus.UpdateCondition(ctx, i.VRec.Client, i.Vdb, vapi.VerticaDBCondition{Type: vapi.ImageChangeInProgress, Status: newVal}, ) if err != nil { return err } - return status.UpdateCondition(ctx, i.VRec.Client, i.Vdb, + return vdbstatus.UpdateCondition(ctx, i.VRec.Client, i.Vdb, vapi.VerticaDBCondition{Type: i.StatusCondition, Status: newVal}, ) } // setUpgradeStatus is a helper to set the upgradeStatus message. func (i *UpgradeManager) setUpgradeStatus(ctx context.Context, msg string) error { - return status.UpdateUpgradeStatus(ctx, i.VRec.Client, i.Vdb, msg) + return vdbstatus.UpdateUpgradeStatus(ctx, i.VRec.Client, i.Vdb, msg) } // updateImageInStatefulSets will change the image in each of the statefulsets. diff --git a/pkg/controllers/upgrade_test.go b/pkg/controllers/vdb/upgrade_test.go similarity index 99% rename from pkg/controllers/upgrade_test.go rename to pkg/controllers/vdb/upgrade_test.go index f6aee26f4..04340acb6 100644 --- a/pkg/controllers/upgrade_test.go +++ b/pkg/controllers/vdb/upgrade_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/upgradeoperator120_reconciler.go b/pkg/controllers/vdb/upgradeoperator120_reconciler.go similarity index 95% rename from pkg/controllers/upgradeoperator120_reconciler.go rename to pkg/controllers/vdb/upgradeoperator120_reconciler.go index 8018b8e2d..d06105d96 100644 --- a/pkg/controllers/upgradeoperator120_reconciler.go +++ b/pkg/controllers/vdb/upgradeoperator120_reconciler.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -22,6 +22,7 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" + "github.com/vertica/vertica-kubernetes/pkg/controllers" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/iter" corev1 "k8s.io/api/core/v1" @@ -38,7 +39,7 @@ type UpgradeOperator120Reconciler struct { // MakeUpgradeOperator120Reconciler will build a UpgradeOperatorFrom120Reconciler object func MakeUpgradeOperator120Reconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, - vdb *vapi.VerticaDB) ReconcileActor { + vdb *vapi.VerticaDB) controllers.ReconcileActor { return &UpgradeOperator120Reconciler{VRec: vdbrecon, Log: log, Vdb: vdb} } diff --git a/pkg/controllers/upgradeoperator120_reconciler_test.go b/pkg/controllers/vdb/upgradeoperator120_reconciler_test.go similarity index 99% rename from pkg/controllers/upgradeoperator120_reconciler_test.go rename to pkg/controllers/vdb/upgradeoperator120_reconciler_test.go index 18d2e2ea9..c977a1dfc 100644 --- a/pkg/controllers/upgradeoperator120_reconciler_test.go +++ b/pkg/controllers/vdb/upgradeoperator120_reconciler_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/version_reconciler.go b/pkg/controllers/vdb/version_reconciler.go similarity index 97% rename from pkg/controllers/version_reconciler.go rename to pkg/controllers/vdb/version_reconciler.go index 79e43c168..e26b717d9 100644 --- a/pkg/controllers/version_reconciler.go +++ b/pkg/controllers/vdb/version_reconciler.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -21,6 +21,7 @@ import ( "github.com/go-logr/logr" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -44,7 +45,7 @@ type VersionReconciler struct { // MakeVersionReconciler will build a VersionReconciler object func MakeVersionReconciler(vdbrecon *VerticaDBReconciler, log logr.Logger, vdb *vapi.VerticaDB, prunner cmds.PodRunner, pfacts *PodFacts, - enforceUpgradePath bool) ReconcileActor { + enforceUpgradePath bool) controllers.ReconcileActor { return &VersionReconciler{ VRec: vdbrecon, Log: log, diff --git a/pkg/controllers/version_reconciler_test.go b/pkg/controllers/vdb/version_reconciler_test.go similarity index 99% rename from pkg/controllers/version_reconciler_test.go rename to pkg/controllers/vdb/version_reconciler_test.go index dbfd87c98..6bfb1451f 100644 --- a/pkg/controllers/version_reconciler_test.go +++ b/pkg/controllers/vdb/version_reconciler_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" diff --git a/pkg/controllers/verticadb_controller.go b/pkg/controllers/vdb/verticadb_controller.go similarity index 98% rename from pkg/controllers/verticadb_controller.go rename to pkg/controllers/vdb/verticadb_controller.go index 1685c4350..4e0b68562 100644 --- a/pkg/controllers/verticadb_controller.go +++ b/pkg/controllers/vdb/verticadb_controller.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" @@ -33,6 +33,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" "github.com/vertica/vertica-kubernetes/pkg/cmds" + "github.com/vertica/vertica-kubernetes/pkg/controllers" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "github.com/vertica/vertica-kubernetes/pkg/events" "github.com/vertica/vertica-kubernetes/pkg/names" @@ -130,11 +131,11 @@ func (r *VerticaDBReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( // Order matters in that some actors depend on the successeful execution of // earlier ones. func (r *VerticaDBReconciler) constructActors(log logr.Logger, vdb *vapi.VerticaDB, prunner *cmds.ClusterPodRunner, - pfacts *PodFacts) []ReconcileActor { + pfacts *PodFacts) []controllers.ReconcileActor { // The actors that will be applied, in sequence, to reconcile a vdb. // Note, we run the StatusReconciler multiple times. This allows us to // refresh the status of the vdb as we do operations that affect it. - return []ReconcileActor{ + return []controllers.ReconcileActor{ // Always start with a status reconcile in case the prior reconcile failed. MakeStatusReconciler(r.Client, r.Scheme, log, vdb, pfacts), // Handle upgrade actions for any k8s objects created in prior versions diff --git a/pkg/controllers/vr/k8s.go b/pkg/controllers/vr/k8s.go new file mode 100644 index 000000000..cc2149ae4 --- /dev/null +++ b/pkg/controllers/vr/k8s.go @@ -0,0 +1,59 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vr + +import ( + "context" + "fmt" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/events" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// fetchVdbOrVa will fetch the VerticaDB/VerticaArchive that is referenced in a VerticaRestore. +// This will log an event if the VerticaDB/VerticaArchive is not found. +func fetchVdbOrVa(ctx context.Context, vrrec *VerticaRestoreReconciler, + vr *vapi.VerticaRestore, nm types.NamespacedName, obj client.Object) (ctrl.Result, error) { + err := vrrec.Client.Get(ctx, nm, obj) + if err != nil && errors.IsNotFound(err) { + event := "" + objType := "" + ownedObjName := "" + switch v := obj.(type) { + case *vapi.VerticaDB: + event = events.VerticaDBNotFound + objType = vapi.VerticaDBKind + ownedObjName = vr.Spec.VerticaDBName + case *vapi.VerticaArchive: + event = events.VerticaArchiveNotFound + objType = vapi.VerticaArchiveKind + ownedObjName = vr.Spec.Archive + default: + event = events.ObjectNotFound + objType = fmt.Sprintf("%T", v) + ownedObjName = "Unknown" + } + vrrec.EVRec.Eventf(vr, corev1.EventTypeWarning, event, + "The '%s' named '%s' was not found", objType, ownedObjName) + return ctrl.Result{Requeue: true}, nil + } + return ctrl.Result{}, err +} diff --git a/pkg/controllers/vr/vaverify_reconcile.go b/pkg/controllers/vr/vaverify_reconcile.go new file mode 100644 index 000000000..0f0923456 --- /dev/null +++ b/pkg/controllers/vr/vaverify_reconcile.go @@ -0,0 +1,42 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +//nolint:dupl +package vr + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + ctrl "sigs.k8s.io/controller-runtime" +) + +// VARCVerifyReconciler will verify the VerticaArchive in the VR CR exists +type VAVerifyReconciler struct { + VRRec *VerticaRestoreReconciler + Vr *vapi.VerticaRestore + Va *vapi.VerticaArchive +} + +func MakeVAVerifyReconciler(r *VerticaRestoreReconciler, vr *vapi.VerticaRestore) controllers.ReconcileActor { + return &VAVerifyReconciler{VRRec: r, Vr: vr, Va: &vapi.VerticaArchive{}} +} + +// Reconcile will verify the VerticaArchive in the VR CR exists +func (s *VAVerifyReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + vaNm := controllers.GetNamespacedName(s.Vr.Namespace, s.Vr.Spec.Archive) + // This reconciler is to get a feedback if the VerticaArchive that is referenced in the vr doesn't exist. + // This will print out an event if the VerticaArchive cannot be found. + return fetchVdbOrVa(ctx, s.VRRec, s.Vr, vaNm, s.Va) +} diff --git a/pkg/controllers/vr/vdbverify_reconcile.go b/pkg/controllers/vr/vdbverify_reconcile.go new file mode 100644 index 000000000..ee1cbfbe7 --- /dev/null +++ b/pkg/controllers/vr/vdbverify_reconcile.go @@ -0,0 +1,42 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +//nolint:dupl +package vr + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + ctrl "sigs.k8s.io/controller-runtime" +) + +// VDBVerifyReconciler will verify the VerticaDB in the VR CR exists +type VDBVerifyReconciler struct { + VRRec *VerticaRestoreReconciler + Vr *vapi.VerticaRestore + Vdb *vapi.VerticaDB +} + +func MakeVDBVerifyReconciler(r *VerticaRestoreReconciler, vr *vapi.VerticaRestore) controllers.ReconcileActor { + return &VDBVerifyReconciler{VRRec: r, Vr: vr, Vdb: &vapi.VerticaDB{}} +} + +// Reconcile will verify the VerticaDB in the VR CR exists +func (s *VDBVerifyReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + vdbNm := controllers.GetNamespacedName(s.Vr.Namespace, s.Vr.Spec.VerticaDBName) + // This reconciler is to get a feedback if the VerticaDB that is referenced in the vr doesn't exist. + // This will print out an event if the VerticaDB cannot be found. + return fetchVdbOrVa(ctx, s.VRRec, s.Vr, vdbNm, s.Vdb) +} diff --git a/pkg/controllers/vr/verticarestore_controller.go b/pkg/controllers/vr/verticarestore_controller.go new file mode 100644 index 000000000..192a0f538 --- /dev/null +++ b/pkg/controllers/vr/verticarestore_controller.go @@ -0,0 +1,97 @@ +/* +Copyright [2021-2022] Micro Focus or one of its affiliates. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vr + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// VerticaRestoreReconciler reconciles a VerticaRestore object +type VerticaRestoreReconciler struct { + client.Client + Scheme *runtime.Scheme + Log logr.Logger + EVRec record.EventRecorder +} + +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticarestores,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticarestores/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticarestores/finalizers,verbs=update +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticadbs,verbs=get;list;create;update;patch;delete +//+kubebuilder:rbac:groups=vertica.com,namespace=WATCH_NAMESPACE,resources=verticaarchives,verbs=get;list;create;update;patch;delete + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.11.0/pkg/reconcile +func (r *VerticaRestoreReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := r.Log.WithValues("verticarestore", req.NamespacedName) + log.Info("starting reconcile of VerticaRestore") + + var res ctrl.Result + vr := &vapi.VerticaRestore{} + err := r.Get(ctx, req.NamespacedName, vr) + if err != nil { + if errors.IsNotFound(err) { + log.Info("VerticaRestore resource not found. Ignoring since object must be deleted") + return ctrl.Result{}, nil + } + log.Error(err, "failed to get VerticaRestore") + return ctrl.Result{}, err + } + + // The actors that will be applied, in sequence, to reconcile a vr. + actors := []controllers.ReconcileActor{ + MakeVDBVerifyReconciler(r, vr), + MakeVAVerifyReconciler(r, vr), + } + + // Iterate over each actor + for _, act := range actors { + log.Info("starting actor", "name", fmt.Sprintf("%T", act)) + res, err = act.Reconcile(ctx, &req) + // Error or a request to requeue will stop the reconciliation. + if verrors.IsReconcileAborted(res, err) { + log.Info("aborting reconcile of VerticaRestore", "result", res, "err", err) + return res, err + } + } + + log.Info("ending reconcile of VerticaRestore", "result", res, "err", err) + return res, err +} + +// SetupWithManager sets up the controller with the Manager. +func (r *VerticaRestoreReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&vapi.VerticaRestore{}). + // Not a strict ownership, but this is used so that the operator will + // reconcile the VerticaRestore for any change in the VerticaDB. + // This ensures the status fields are kept up to date. + Owns(&vapi.VerticaDB{}). + Owns(&vapi.VerticaArchive{}). + Complete(r) +} diff --git a/pkg/events/event.go b/pkg/events/event.go index c4cdbc08b..8479d2f64 100644 --- a/pkg/events/event.go +++ b/pkg/events/event.go @@ -15,6 +15,7 @@ package events +// Constants for VerticaDB reconciler const ( AddNodeStart = "AddNodeStart" AddNodeSucceeded = "AddNodeSucceeded" @@ -66,3 +67,14 @@ const ( RebalanceShards = "RebalanceShards" DrainNodeRetry = "DrainNodeRetry" ) + +const ( + VerticaDBNotFound = "VerticaDBNotFound" + VerticaArchiveNotFound = "VerticaArchiveNotFound" +) + +// Constants for VerticaAutoscaler reconciler +const ( + SubclusterServiceNameNotFound = "SubclusterServiceNameNotFound" + NoSubclusterTemplate = "NoSubclusterTemplate" +) diff --git a/pkg/test/helpers.go b/pkg/test/helpers.go index 74ca25ea3..9539a3043 100644 --- a/pkg/test/helpers.go +++ b/pkg/test/helpers.go @@ -176,6 +176,14 @@ func DeleteSvcs(ctx context.Context, c client.Client, vdb *vapi.VerticaDB) { } } +func CreateVAS(ctx context.Context, c client.Client, vas *vapi.VerticaAutoscaler) { + ExpectWithOffset(1, c.Create(ctx, vas)).Should(Succeed()) +} + +func DeleteVAS(ctx context.Context, c client.Client, vas *vapi.VerticaAutoscaler) { + ExpectWithOffset(1, c.Delete(ctx, vas)).Should(Succeed()) +} + func CreateVDB(ctx context.Context, c client.Client, vdb *vapi.VerticaDB) { ExpectWithOffset(1, c.Create(ctx, vdb)).Should(Succeed()) } diff --git a/pkg/vasstatus/status.go b/pkg/vasstatus/status.go new file mode 100644 index 000000000..1d1488795 --- /dev/null +++ b/pkg/vasstatus/status.go @@ -0,0 +1,120 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vasstatus + +import ( + "context" + "fmt" + "reflect" + + "github.com/go-logr/logr" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/builder" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func SetSelector(ctx context.Context, c client.Client, log logr.Logger, req *ctrl.Request) error { + return vasStatusUpdater(ctx, c, log, req, func(vas *vapi.VerticaAutoscaler) { + vas.Status.Selector = getLabelSelector(vas) + }) +} + +// ReportScalingOperation bumps up the count in the status field about the number of +// times we have scaled the VerticaDB. This is intended to be called each time +// we change the pod count up or down. +func ReportScalingOperation(ctx context.Context, c client.Client, log logr.Logger, req *ctrl.Request, currentSize int32) error { + return vasStatusUpdater(ctx, c, log, req, func(vas *vapi.VerticaAutoscaler) { + vas.Status.ScalingCount++ + vas.Status.CurrentSize = currentSize + }) +} + +// RefreshCurrentSize sets the current size in the VerticaAutoscaler +func RefreshCurrentSize(ctx context.Context, c client.Client, log logr.Logger, req *ctrl.Request, currentSize int32) error { + return vasStatusUpdater(ctx, c, log, req, func(vas *vapi.VerticaAutoscaler) { + vas.Status.CurrentSize = currentSize + }) +} + +// UpdateCondition will update a condition status. This is a no-op if the +// status condition is already set. +func UpdateCondition(ctx context.Context, clnt client.Client, log logr.Logger, + req *ctrl.Request, condition vapi.VerticaAutoscalerCondition) error { + if condition.LastTransitionTime.IsZero() { + condition.LastTransitionTime = metav1.Now() + } + // refreshConditionInPlace will update the status condition in vdb. The update + // will be applied in-place. + refreshConditionInPlace := func(vas *vapi.VerticaAutoscaler) { + if len(vas.Status.Conditions) == 0 { + vas.Status.Conditions = append(vas.Status.Conditions, vapi.VerticaAutoscalerCondition{}) + } + // Only update if status is different change. Cannot compare the entire + // condition since LastTransitionTime will be different each time. + if vas.Status.Conditions[vapi.TargetSizeInitializedIndex].Status != condition.Status { + vas.Status.Conditions[vapi.TargetSizeInitializedIndex] = condition + } + } + + return vasStatusUpdater(ctx, clnt, log, req, refreshConditionInPlace) +} + +func vasStatusUpdater(ctx context.Context, c client.Client, log logr.Logger, + req *ctrl.Request, statusUpdateFunc func(*vapi.VerticaAutoscaler)) error { + // Try the status update in a retry loop to handle the case where someone + // update the VerticaAutoscaler since we last fetched. + return retry.RetryOnConflict(retry.DefaultBackoff, func() error { + vas := &vapi.VerticaAutoscaler{} + err := c.Get(ctx, req.NamespacedName, vas) + if err != nil { + if errors.IsNotFound(err) { + log.Info("VerticaAutoscaler resource not found. Ignoring since object must be deleted") + return nil + } + return err + } + + // We will calculate the status for the vas object. This update is done in + // place. If anything differs from the copy then we will do a single update. + vasOrig := vas.DeepCopy() + + statusUpdateFunc(vas) + + if !reflect.DeepEqual(vasOrig, vas.Status) { + log.Info("Updating vas status", "status", vas.Status) + if err := c.Status().Update(ctx, vas); err != nil { + return err + } + } + return nil + }) +} + +// getLabelSelector will generate the label for use in the vas status field +func getLabelSelector(vas *vapi.VerticaAutoscaler) string { + return fmt.Sprintf("%s=%s,%s=%s,%s=%s", + builder.SubclusterSvcNameLabel, + vas.Spec.ServiceName, + builder.VDBInstanceLabel, + vas.Spec.VerticaDBName, + builder.ManagedByLabel, + builder.OperatorName, + ) +} diff --git a/pkg/vasstatus/status_test.go b/pkg/vasstatus/status_test.go new file mode 100644 index 000000000..6ae7ad19d --- /dev/null +++ b/pkg/vasstatus/status_test.go @@ -0,0 +1,142 @@ +/* + (c) Copyright [2021-2022] Micro Focus or one of its affiliates. + Licensed under the Apache License, Version 2.0 (the "License"); + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package vasstatus + +import ( + "context" + "path/filepath" + "testing" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/test" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" +) + +var k8sClient client.Client +var testEnv *envtest.Environment +var logger logr.Logger + +var _ = BeforeSuite(func() { + logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)) + logf.SetLogger(logger) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + } + + cfg, err := testEnv.Start() + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + ExpectWithOffset(1, cfg).NotTo(BeNil()) + restCfg := cfg + + err = vapi.AddToScheme(scheme.Scheme) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + k8sClient, err = client.New(restCfg, client.Options{Scheme: scheme.Scheme}) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) +}, 60) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + ExpectWithOffset(1, err).NotTo(HaveOccurred()) +}) + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecsWithDefaultAndCustomReporters(t, + "vasstatus Suite", + []Reporter{printer.NewlineReporter{}}) +} + +var _ = Describe("status", func() { + ctx := context.Background() + + It("should set the selector in the status field", func() { + vas := vapi.MakeVAS() + vas.Spec.ServiceName = "my-svc" + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + expectedSelector := getLabelSelector(vas) + + nm := vapi.MakeVASName() + req := ctrl.Request{NamespacedName: nm} + Expect(SetSelector(ctx, k8sClient, logger, &req)).Should(Succeed()) + + fetchVas := &vapi.VerticaAutoscaler{} + Expect(k8sClient.Get(ctx, nm, fetchVas)).Should(Succeed()) + Expect(fetchVas.Status.Selector).Should(Equal(expectedSelector)) + }) + + It("should increment the scaling count", func() { + vas := vapi.MakeVAS() + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + nm := vapi.MakeVASName() + req := ctrl.Request{NamespacedName: nm} + Expect(ReportScalingOperation(ctx, k8sClient, logger, &req, int32(5))).Should(Succeed()) + + Expect(k8sClient.Get(ctx, nm, vas)).Should(Succeed()) + Expect(vas.Status.ScalingCount).Should(Equal(1)) + Expect(vas.Status.CurrentSize).Should(Equal(int32(5))) + + Expect(ReportScalingOperation(ctx, k8sClient, logger, &req, int32(10))).Should(Succeed()) + + Expect(k8sClient.Get(ctx, nm, vas)).Should(Succeed()) + Expect(vas.Status.ScalingCount).Should(Equal(2)) + Expect(vas.Status.CurrentSize).Should(Equal(int32(10))) + }) + + It("should tolerate a non-existent vas", func() { + nm := vapi.MakeVASName() + req := ctrl.Request{NamespacedName: nm} + Expect(ReportScalingOperation(ctx, k8sClient, logger, &req, 0)).Should(Succeed()) + Expect(SetSelector(ctx, k8sClient, logger, &req)).Should(Succeed()) + }) + + It("should update the status condition", func() { + vas := vapi.MakeVAS() + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + nm := vapi.MakeVASName() + req := ctrl.Request{NamespacedName: nm} + cond := vapi.VerticaAutoscalerCondition{ + Type: vapi.TargetSizeInitialized, + Status: corev1.ConditionTrue, + } + Expect(UpdateCondition(ctx, k8sClient, logger, &req, cond)).Should(Succeed()) + + Expect(k8sClient.Get(ctx, nm, vas)).Should(Succeed()) + Expect(len(vas.Status.Conditions)).Should(Equal(1)) + Expect(vas.Status.Conditions[vapi.TargetSizeInitializedIndex].Status).Should(Equal(cond.Status)) + }) +}) diff --git a/pkg/vdbgen/vdb.go b/pkg/vdbgen/vdb.go index fd4e4e2ce..2833d447b 100644 --- a/pkg/vdbgen/vdb.go +++ b/pkg/vdbgen/vdb.go @@ -127,7 +127,7 @@ func (d *DBGenerator) connect(ctx context.Context) error { // setParmsFromOptions will set values in the vdb that are obtained from the // command line options. func (d *DBGenerator) setParmsFromOptions() { - d.Objs.Vdb.TypeMeta.APIVersion = vapi.VerticaDBAPIVersion + d.Objs.Vdb.TypeMeta.APIVersion = vapi.GroupVersion.String() d.Objs.Vdb.TypeMeta.Kind = vapi.VerticaDBKind d.Objs.Vdb.Spec.InitPolicy = vapi.CommunalInitPolicyRevive d.Objs.Vdb.Spec.DBName = d.Opts.DBName diff --git a/pkg/status/status.go b/pkg/vdbstatus/status.go similarity index 99% rename from pkg/status/status.go rename to pkg/vdbstatus/status.go index 3692d3d45..8e48735d9 100644 --- a/pkg/status/status.go +++ b/pkg/vdbstatus/status.go @@ -13,7 +13,7 @@ limitations under the License. */ -package status +package vdbstatus import ( "context" diff --git a/pkg/status/status_test.go b/pkg/vdbstatus/status_test.go similarity index 99% rename from pkg/status/status_test.go rename to pkg/vdbstatus/status_test.go index d1c15720c..4129583db 100644 --- a/pkg/status/status_test.go +++ b/pkg/vdbstatus/status_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package status +package vdbstatus import ( "context" @@ -74,7 +74,7 @@ func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) RunSpecsWithDefaultAndCustomReporters(t, - "conditions Suite", + "vdbstatus Suite", []Reporter{printer.NewlineReporter{}}) } diff --git a/scripts/create-helm-charts.sh b/scripts/create-helm-charts.sh index 281dae221..88a90d536 100755 --- a/scripts/create-helm-charts.sh +++ b/scripts/create-helm-charts.sh @@ -28,6 +28,10 @@ CRD_DIR=$OPERATOR_CHART/crds $KUSTOMIZE build $REPO_DIR/config/default | $KUBERNETES_SPLIT_YAML --outdir $TEMPLATE_DIR - mv $TEMPLATE_DIR/verticadbs.vertica.com-crd.yaml $CRD_DIR +mv $TEMPLATE_DIR/verticaarchives.vertica.com-crd.yaml $CRD_DIR +mv $TEMPLATE_DIR/verticabackups.vertica.com-crd.yaml $CRD_DIR +mv $TEMPLATE_DIR/verticaautoscalers.vertica.com-crd.yaml $CRD_DIR +mv $TEMPLATE_DIR/verticarestores.vertica.com-crd.yaml $CRD_DIR # Add in the templating # 1. Template the namespace diff --git a/scripts/setup-kustomize.sh b/scripts/setup-kustomize.sh index aba12b173..93dfb4c26 100755 --- a/scripts/setup-kustomize.sh +++ b/scripts/setup-kustomize.sh @@ -198,6 +198,15 @@ replacements: kind: Pod fieldPaths: - spec.containers.0.image + - source: + kind: ConfigMap + name: e2e + fieldPath: data.verticaImage + targets: + - select: + kind: Job + fieldPaths: + - spec.template.spec.containers.0.image - source: kind: ConfigMap name: e2e diff --git a/tests/e2e/revivedb-1-node/00-assert.yaml b/tests/e2e-extra/revivedb-1-node/00-assert.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/00-assert.yaml rename to tests/e2e-extra/revivedb-1-node/00-assert.yaml diff --git a/tests/e2e/revivedb-1-node/00-deploy-operator.yaml b/tests/e2e-extra/revivedb-1-node/00-deploy-operator.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/00-deploy-operator.yaml rename to tests/e2e-extra/revivedb-1-node/00-deploy-operator.yaml diff --git a/tests/e2e/revivedb-1-node/01-assert.yaml b/tests/e2e-extra/revivedb-1-node/01-assert.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/01-assert.yaml rename to tests/e2e-extra/revivedb-1-node/01-assert.yaml diff --git a/tests/e2e/revivedb-1-node/01-password-secret.yaml b/tests/e2e-extra/revivedb-1-node/01-password-secret.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/01-password-secret.yaml rename to tests/e2e-extra/revivedb-1-node/01-password-secret.yaml diff --git a/tests/e2e/revivedb-1-node/05-create-communal-creds.yaml b/tests/e2e-extra/revivedb-1-node/05-create-communal-creds.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/05-create-communal-creds.yaml rename to tests/e2e-extra/revivedb-1-node/05-create-communal-creds.yaml diff --git a/tests/e2e/revivedb-1-node/15-assert.yaml b/tests/e2e-extra/revivedb-1-node/15-assert.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/15-assert.yaml rename to tests/e2e-extra/revivedb-1-node/15-assert.yaml diff --git a/tests/e2e/revivedb-1-node/15-create-db.yaml b/tests/e2e-extra/revivedb-1-node/15-create-db.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/15-create-db.yaml rename to tests/e2e-extra/revivedb-1-node/15-create-db.yaml diff --git a/tests/e2e/revivedb-1-node/20-delete-crd.yaml b/tests/e2e-extra/revivedb-1-node/20-delete-crd.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/20-delete-crd.yaml rename to tests/e2e-extra/revivedb-1-node/20-delete-crd.yaml diff --git a/tests/e2e/revivedb-1-node/20-errors.yaml b/tests/e2e-extra/revivedb-1-node/20-errors.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/20-errors.yaml rename to tests/e2e-extra/revivedb-1-node/20-errors.yaml diff --git a/tests/e2e/revivedb-1-node/25-assert.yaml b/tests/e2e-extra/revivedb-1-node/25-assert.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/25-assert.yaml rename to tests/e2e-extra/revivedb-1-node/25-assert.yaml diff --git a/tests/e2e/revivedb-1-node/25-revive.yaml b/tests/e2e-extra/revivedb-1-node/25-revive.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/25-revive.yaml rename to tests/e2e-extra/revivedb-1-node/25-revive.yaml diff --git a/tests/e2e/revivedb-1-node/95-assert.yaml b/tests/e2e-extra/revivedb-1-node/95-assert.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/95-assert.yaml rename to tests/e2e-extra/revivedb-1-node/95-assert.yaml diff --git a/tests/e2e/revivedb-1-node/95-delete-crd.yaml b/tests/e2e-extra/revivedb-1-node/95-delete-crd.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/95-delete-crd.yaml rename to tests/e2e-extra/revivedb-1-node/95-delete-crd.yaml diff --git a/tests/e2e/revivedb-1-node/95-errors.yaml b/tests/e2e-extra/revivedb-1-node/95-errors.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/95-errors.yaml rename to tests/e2e-extra/revivedb-1-node/95-errors.yaml diff --git a/tests/e2e/revivedb-1-node/99-errors.yaml b/tests/e2e-extra/revivedb-1-node/99-errors.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/99-errors.yaml rename to tests/e2e-extra/revivedb-1-node/99-errors.yaml diff --git a/tests/e2e/revivedb-1-node/99-uninstall-operator.yaml b/tests/e2e-extra/revivedb-1-node/99-uninstall-operator.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/99-uninstall-operator.yaml rename to tests/e2e-extra/revivedb-1-node/99-uninstall-operator.yaml diff --git a/tests/e2e/revivedb-1-node/README.txt b/tests/e2e-extra/revivedb-1-node/README.txt similarity index 100% rename from tests/e2e/revivedb-1-node/README.txt rename to tests/e2e-extra/revivedb-1-node/README.txt diff --git a/tests/e2e/revivedb-1-node/vdb-to-create/base/kustomization.yaml b/tests/e2e-extra/revivedb-1-node/vdb-to-create/base/kustomization.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/vdb-to-create/base/kustomization.yaml rename to tests/e2e-extra/revivedb-1-node/vdb-to-create/base/kustomization.yaml diff --git a/tests/e2e/revivedb-1-node/vdb-to-create/base/setup-vdb.yaml b/tests/e2e-extra/revivedb-1-node/vdb-to-create/base/setup-vdb.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/vdb-to-create/base/setup-vdb.yaml rename to tests/e2e-extra/revivedb-1-node/vdb-to-create/base/setup-vdb.yaml diff --git a/tests/e2e/revivedb-1-node/vdb-to-revive/base/kustomization.yaml b/tests/e2e-extra/revivedb-1-node/vdb-to-revive/base/kustomization.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/vdb-to-revive/base/kustomization.yaml rename to tests/e2e-extra/revivedb-1-node/vdb-to-revive/base/kustomization.yaml diff --git a/tests/e2e/revivedb-1-node/vdb-to-revive/base/setup-vdb.yaml b/tests/e2e-extra/revivedb-1-node/vdb-to-revive/base/setup-vdb.yaml similarity index 100% rename from tests/e2e/revivedb-1-node/vdb-to-revive/base/setup-vdb.yaml rename to tests/e2e-extra/revivedb-1-node/vdb-to-revive/base/setup-vdb.yaml diff --git a/tests/e2e-online-upgrade/online-upgrade-kill-transient/45-assert.yaml b/tests/e2e-online-upgrade/online-upgrade-kill-transient/45-assert.yaml index 207204a87..0b696b70f 100644 --- a/tests/e2e-online-upgrade/online-upgrade-kill-transient/45-assert.yaml +++ b/tests/e2e-online-upgrade/online-upgrade-kill-transient/45-assert.yaml @@ -11,14 +11,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: v1 -kind: Pod +apiVersion: batch/v1 +kind: Job metadata: name: test-verify-accessing-primary-node status: - containerStatuses: - - name: test - state: - terminated: - exitCode: 0 - + succeeded: 1 diff --git a/tests/e2e-online-upgrade/online-upgrade-kill-transient/verify-vsql-access/base/verify-vsql-access.yaml b/tests/e2e-online-upgrade/online-upgrade-kill-transient/verify-vsql-access/base/verify-vsql-access.yaml index d67fda145..34798c780 100644 --- a/tests/e2e-online-upgrade/online-upgrade-kill-transient/verify-vsql-access/base/verify-vsql-access.yaml +++ b/tests/e2e-online-upgrade/online-upgrade-kill-transient/verify-vsql-access/base/verify-vsql-access.yaml @@ -34,28 +34,30 @@ data: echo "*** Did not connect to node 1 through primary subcluster: $PRI_CONNECTION_NODE" exit 1 fi - exit 0 + exit 0 --- -apiVersion: v1 -kind: Pod +apiVersion: batch/v1 +kind: Job metadata: name: test-verify-accessing-primary-node labels: stern: include spec: - restartPolicy: Never - containers: - - name: test - image: kustomize-vertica-image - command: ["/home/dbadmin/test.sh"] - volumeMounts: + template: + spec: + restartPolicy: OnFailure + containers: + - name: test + image: kustomize-vertica-image + command: ["/home/dbadmin/test.sh"] + volumeMounts: + - name: test-script + mountPath: /home/dbadmin/test.sh + readOnly: true + subPath: test.sh + volumes: - name: test-script - mountPath: /home/dbadmin/test.sh - readOnly: true - subPath: test.sh - volumes: - - name: test-script - configMap: - defaultMode: 0777 - name: script-verify-accessing-primary-node + configMap: + defaultMode: 0777 + name: script-verify-accessing-primary-node diff --git a/tests/e2e/autoscale-by-pod/05-create-communal-creds.yaml b/tests/e2e/autoscale-by-pod/05-create-communal-creds.yaml new file mode 100644 index 000000000..0e0a64cb3 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/05-create-communal-creds.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kustomize build ../../manifests/communal-creds/overlay | kubectl apply -f - --namespace $NAMESPACE diff --git a/tests/e2e/autoscale-by-pod/10-assert.yaml b/tests/e2e/autoscale-by-pod/10-assert.yaml new file mode 100644 index 000000000..fc6dfbf1c --- /dev/null +++ b/tests/e2e/autoscale-by-pod/10-assert.yaml @@ -0,0 +1,20 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Pod +metadata: + labels: + control-plane: controller-manager +status: + phase: Running diff --git a/tests/e2e/autoscale-by-pod/10-deploy-operator.yaml b/tests/e2e/autoscale-by-pod/10-deploy-operator.yaml new file mode 100644 index 000000000..298db6cf6 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/10-deploy-operator.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: sh -c "cd ../../.. && make deploy-operator NAMESPACE=$NAMESPACE" diff --git a/tests/e2e/autoscale-by-pod/15-assert.yaml b/tests/e2e/autoscale-by-pod/15-assert.yaml new file mode 100644 index 000000000..836e80b8c --- /dev/null +++ b/tests/e2e/autoscale-by-pod/15-assert.yaml @@ -0,0 +1,19 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc1 +status: + replicas: 2 diff --git a/tests/e2e/autoscale-by-pod/15-setup-vdb.yaml b/tests/e2e/autoscale-by-pod/15-setup-vdb.yaml new file mode 100644 index 000000000..3e10786a3 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/15-setup-vdb.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: bash -c "kustomize build setup-vdb/overlay | kubectl -n $NAMESPACE apply -f - " diff --git a/tests/e2e/autoscale-by-pod/20-assert.yaml b/tests/e2e/autoscale-by-pod/20-assert.yaml new file mode 100644 index 000000000..4bfa0d357 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/20-assert.yaml @@ -0,0 +1,39 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc1 +status: + replicas: 2 + readyReplicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc2 +status: + replicas: 1 + readyReplicas: 1 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaDB +metadata: + name: v-autoscale-by-pod +status: + subclusters: + - installCount: 2 + addedToDBCount: 2 + - installCount: 1 + addedToDBCount: 1 diff --git a/tests/e2e/autoscale-by-pod/20-wait-for-createdb.yaml b/tests/e2e/autoscale-by-pod/20-wait-for-createdb.yaml new file mode 100644 index 000000000..bf3726035 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/20-wait-for-createdb.yaml @@ -0,0 +1 @@ +# Intentionally empty to give this step a name in kuttl \ No newline at end of file diff --git a/tests/e2e/autoscale-by-pod/25-assert.yaml b/tests/e2e/autoscale-by-pod/25-assert.yaml new file mode 100644 index 000000000..3257979a5 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/25-assert.yaml @@ -0,0 +1,30 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-by-pod-sc1 +status: + selector: vertica.com/subcluster-svc=sc1,app.kubernetes.io/instance=v-autoscale-by-pod,app.kubernetes.io/managed-by=verticadb-operator + scalingCount: 0 + currentSize: 2 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-by-pod-sc2 +status: + selector: vertica.com/subcluster-svc=sc2,app.kubernetes.io/instance=v-autoscale-by-pod,app.kubernetes.io/managed-by=verticadb-operator + scalingCount: 0 + currentSize: 1 diff --git a/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml b/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml new file mode 100644 index 000000000..9b8f774e7 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml @@ -0,0 +1,30 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-by-pod-sc1 +spec: + verticaDBName: v-autoscale-by-pod + serviceName: sc1 + scalingGranularity: Pod +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-by-pod-sc2 +spec: + verticaDBName: v-autoscale-by-pod + serviceName: sc2 + scalingGranularity: Pod diff --git a/tests/e2e/autoscale-by-pod/30-assert.yaml b/tests/e2e/autoscale-by-pod/30-assert.yaml new file mode 100644 index 000000000..b3e4546f9 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/30-assert.yaml @@ -0,0 +1,34 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc1 +status: + replicas: 3 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc2 +status: + replicas: 1 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-by-pod-sc1 +status: + scalingCount: 1 + currentSize: 3 diff --git a/tests/e2e/autoscale-by-pod/30-scale-sc1-to-3.yaml b/tests/e2e/autoscale-by-pod/30-scale-sc1-to-3.yaml new file mode 100644 index 000000000..508551b24 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/30-scale-sc1-to-3.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-by-pod-sc1 --replicas 3 diff --git a/tests/e2e/autoscale-by-pod/35-assert.yaml b/tests/e2e/autoscale-by-pod/35-assert.yaml new file mode 100644 index 000000000..6f30c6ebb --- /dev/null +++ b/tests/e2e/autoscale-by-pod/35-assert.yaml @@ -0,0 +1,34 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc1 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc2 +status: + replicas: 1 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-by-pod-sc1 +status: + scalingCount: 2 + currentSize: 2 diff --git a/tests/e2e/autoscale-by-pod/35-scale-sc1-to-2.yaml b/tests/e2e/autoscale-by-pod/35-scale-sc1-to-2.yaml new file mode 100644 index 000000000..4692bc7b5 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/35-scale-sc1-to-2.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-by-pod-sc1 --replicas 2 diff --git a/tests/e2e/autoscale-by-pod/40-assert.yaml b/tests/e2e/autoscale-by-pod/40-assert.yaml new file mode 100644 index 000000000..c1a3a354d --- /dev/null +++ b/tests/e2e/autoscale-by-pod/40-assert.yaml @@ -0,0 +1,34 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc1 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc2 +status: + replicas: 3 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-by-pod-sc2 +status: + scalingCount: 1 + currentSize: 3 diff --git a/tests/e2e/autoscale-by-pod/40-scale-sc2-to-3.yaml b/tests/e2e/autoscale-by-pod/40-scale-sc2-to-3.yaml new file mode 100644 index 000000000..1f0ccfc61 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/40-scale-sc2-to-3.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-by-pod-sc2 --replicas 3 diff --git a/tests/e2e/autoscale-by-pod/45-assert.yaml b/tests/e2e/autoscale-by-pod/45-assert.yaml new file mode 100644 index 000000000..013a1c85a --- /dev/null +++ b/tests/e2e/autoscale-by-pod/45-assert.yaml @@ -0,0 +1,34 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc1 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-pod-sc2 +status: + replicas: 1 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-by-pod-sc2 +status: + scalingCount: 2 + currentSize: 1 diff --git a/tests/e2e/autoscale-by-pod/45-scale-sc2-to-1.yaml b/tests/e2e/autoscale-by-pod/45-scale-sc2-to-1.yaml new file mode 100644 index 000000000..306b277a4 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/45-scale-sc2-to-1.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-by-pod-sc2 --replicas 1 diff --git a/tests/e2e/autoscale-by-pod/90-errors.yaml b/tests/e2e/autoscale-by-pod/90-errors.yaml new file mode 100644 index 000000000..2d2e094b3 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/90-errors.yaml @@ -0,0 +1,18 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Pod +metadata: + labels: + control-plane: controller-manager diff --git a/tests/e2e/autoscale-by-pod/90-uninstall-operator.yaml b/tests/e2e/autoscale-by-pod/90-uninstall-operator.yaml new file mode 100644 index 000000000..674dcbecc --- /dev/null +++ b/tests/e2e/autoscale-by-pod/90-uninstall-operator.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: sh -c "cd ../../.. && make undeploy-operator NAMESPACE=$NAMESPACE" diff --git a/tests/e2e/autoscale-by-pod/95-assert.yaml b/tests/e2e/autoscale-by-pod/95-assert.yaml new file mode 100644 index 000000000..fe22a5139 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/95-assert.yaml @@ -0,0 +1,19 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Pod +metadata: + name: clean-communal +status: + phase: Succeeded diff --git a/tests/e2e/autoscale-by-pod/95-delete-crd.yaml b/tests/e2e/autoscale-by-pod/95-delete-crd.yaml new file mode 100644 index 000000000..b25eac54a --- /dev/null +++ b/tests/e2e/autoscale-by-pod/95-delete-crd.yaml @@ -0,0 +1,24 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: vertica.com/v1beta1 + kind: VerticaDB + - apiVersion: vertica.com/v1beta1 + kind: VerticaAutoscaler + - apiVersion: v1 + kind: PersistentVolumeClaim +commands: + - command: bash -c "kustomize build clean-communal/overlay | kubectl -n $NAMESPACE apply -f - " diff --git a/tests/e2e/autoscale-by-pod/95-errors.yaml b/tests/e2e/autoscale-by-pod/95-errors.yaml new file mode 100644 index 000000000..415cba0a7 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/95-errors.yaml @@ -0,0 +1,24 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/managed-by: verticadb-operator +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaDB diff --git a/tests/e2e/autoscale-by-pod/README.txt b/tests/e2e/autoscale-by-pod/README.txt new file mode 100644 index 000000000..5c6f8157a --- /dev/null +++ b/tests/e2e/autoscale-by-pod/README.txt @@ -0,0 +1,2 @@ +The autoscaler uses the scale API. This tests autoscaler indirectly by doing +scaling operations through that scale API. diff --git a/tests/e2e/autoscale-by-pod/setup-vdb/base/kustomization.yaml b/tests/e2e/autoscale-by-pod/setup-vdb/base/kustomization.yaml new file mode 100644 index 000000000..01b927990 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/setup-vdb/base/kustomization.yaml @@ -0,0 +1,15 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resources: + - setup-vdb.yaml diff --git a/tests/e2e/autoscale-by-pod/setup-vdb/base/setup-vdb.yaml b/tests/e2e/autoscale-by-pod/setup-vdb/base/setup-vdb.yaml new file mode 100644 index 000000000..baab2e6b9 --- /dev/null +++ b/tests/e2e/autoscale-by-pod/setup-vdb/base/setup-vdb.yaml @@ -0,0 +1,33 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaDB +metadata: + name: v-autoscale-by-pod +spec: + image: kustomize-vertica-image + communal: + includeUIDInPath: true + local: + requestSize: 100Mi + dbName: vert + shardCount: 3 + kSafety: "1" + subclusters: + - name: sc1 + size: 2 + - name: sc2 + size: 1 + requeueTime: 5 + certSecrets: [] diff --git a/tests/e2e/autoscale-by-subcluster/05-create-communal-creds.yaml b/tests/e2e/autoscale-by-subcluster/05-create-communal-creds.yaml new file mode 100644 index 000000000..0e0a64cb3 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/05-create-communal-creds.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kustomize build ../../manifests/communal-creds/overlay | kubectl apply -f - --namespace $NAMESPACE diff --git a/tests/e2e/autoscale-by-subcluster/10-assert.yaml b/tests/e2e/autoscale-by-subcluster/10-assert.yaml new file mode 100644 index 000000000..fc6dfbf1c --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/10-assert.yaml @@ -0,0 +1,20 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Pod +metadata: + labels: + control-plane: controller-manager +status: + phase: Running diff --git a/tests/e2e/autoscale-by-subcluster/10-deploy-operator.yaml b/tests/e2e/autoscale-by-subcluster/10-deploy-operator.yaml new file mode 100644 index 000000000..298db6cf6 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/10-deploy-operator.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: sh -c "cd ../../.. && make deploy-operator NAMESPACE=$NAMESPACE" diff --git a/tests/e2e/autoscale-by-subcluster/15-assert.yaml b/tests/e2e/autoscale-by-subcluster/15-assert.yaml new file mode 100644 index 000000000..904099c70 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/15-assert.yaml @@ -0,0 +1,19 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-pri +status: + replicas: 3 diff --git a/tests/e2e/autoscale-by-subcluster/15-setup-vdb.yaml b/tests/e2e/autoscale-by-subcluster/15-setup-vdb.yaml new file mode 100644 index 000000000..3e10786a3 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/15-setup-vdb.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: bash -c "kustomize build setup-vdb/overlay | kubectl -n $NAMESPACE apply -f - " diff --git a/tests/e2e/autoscale-by-subcluster/20-assert.yaml b/tests/e2e/autoscale-by-subcluster/20-assert.yaml new file mode 100644 index 000000000..7574ce3fa --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/20-assert.yaml @@ -0,0 +1,30 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-pri +status: + replicas: 3 + readyReplicas: 3 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaDB +metadata: + name: v-autoscale-by-subcluster +status: + subclusters: + - installCount: 3 + addedToDBCount: 3 + subclusterCount: 1 diff --git a/tests/e2e/autoscale-by-subcluster/20-wait-for-createdb.yaml b/tests/e2e/autoscale-by-subcluster/20-wait-for-createdb.yaml new file mode 100644 index 000000000..bf3726035 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/20-wait-for-createdb.yaml @@ -0,0 +1 @@ +# Intentionally empty to give this step a name in kuttl \ No newline at end of file diff --git a/tests/e2e/autoscale-by-subcluster/25-assert.yaml b/tests/e2e/autoscale-by-subcluster/25-assert.yaml new file mode 100644 index 000000000..8616d2530 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/25-assert.yaml @@ -0,0 +1,21 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + selector: vertica.com/subcluster-svc=as,app.kubernetes.io/instance=v-autoscale-by-subcluster,app.kubernetes.io/managed-by=verticadb-operator + scalingCount: 0 + currentSize: 0 diff --git a/tests/e2e/autoscale-by-subcluster/25-create-autoscale-CR.yaml b/tests/e2e/autoscale-by-subcluster/25-create-autoscale-CR.yaml new file mode 100644 index 000000000..d37374f0b --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/25-create-autoscale-CR.yaml @@ -0,0 +1,26 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +spec: + verticaDBName: v-autoscale-by-subcluster + serviceName: as + scalingGranularity: Subcluster + template: + name: as + size: 2 + serviceName: as + isPrimary: false diff --git a/tests/e2e/autoscale-by-subcluster/30-assert.yaml b/tests/e2e/autoscale-by-subcluster/30-assert.yaml new file mode 100644 index 000000000..6430e39ba --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/30-assert.yaml @@ -0,0 +1,34 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-0 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-1 +status: + replicas: 2 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + scalingCount: 1 + currentSize: 4 diff --git a/tests/e2e/autoscale-by-subcluster/30-errors.yaml b/tests/e2e/autoscale-by-subcluster/30-errors.yaml new file mode 100644 index 000000000..5d66bd2bc --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/30-errors.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-2 diff --git a/tests/e2e/autoscale-by-subcluster/30-scale-2-new-subclusters.yaml b/tests/e2e/autoscale-by-subcluster/30-scale-2-new-subclusters.yaml new file mode 100644 index 000000000..f4c378fbd --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/30-scale-2-new-subclusters.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale --replicas 5 diff --git a/tests/e2e/autoscale-by-subcluster/35-assert.yaml b/tests/e2e/autoscale-by-subcluster/35-assert.yaml new file mode 100644 index 000000000..c1cd0bbf1 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/35-assert.yaml @@ -0,0 +1,40 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-0 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-1 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-2 +status: + replicas: 2 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + scalingCount: 2 diff --git a/tests/e2e/autoscale-by-subcluster/35-scale-1-new-subclusters.yaml b/tests/e2e/autoscale-by-subcluster/35-scale-1-new-subclusters.yaml new file mode 100644 index 000000000..64c03fa0b --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/35-scale-1-new-subclusters.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale --replicas 6 diff --git a/tests/e2e/autoscale-by-subcluster/40-assert.yaml b/tests/e2e/autoscale-by-subcluster/40-assert.yaml new file mode 100644 index 000000000..c6699b5aa --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/40-assert.yaml @@ -0,0 +1,19 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-manual +status: + replicas: 1 diff --git a/tests/e2e/autoscale-by-subcluster/40-manually-add-new-subcluster.yaml b/tests/e2e/autoscale-by-subcluster/40-manually-add-new-subcluster.yaml new file mode 100644 index 000000000..f0305365e --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/40-manually-add-new-subcluster.yaml @@ -0,0 +1,37 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaDB +metadata: + name: v-autoscale-by-subcluster +spec: + subclusters: + - name: pri + size: 3 + isPrimary: true + - name: as-0 + size: 2 + isPrimary: false + serviceName: as + - name: as-1 + size: 2 + isPrimary: false + serviceName: as + - name: manual + size: 1 + isPrimary: false + - name: as-2 + size: 2 + isPrimary: false + serviceName: as diff --git a/tests/e2e/autoscale-by-subcluster/45-assert.yaml b/tests/e2e/autoscale-by-subcluster/45-assert.yaml new file mode 100644 index 000000000..e7d14df4f --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/45-assert.yaml @@ -0,0 +1,41 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-pri +status: + replicas: 3 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-manual +status: + replicas: 1 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-0 +status: + replicas: 2 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + scalingCount: 3 + currentSize: 2 diff --git a/tests/e2e/autoscale-by-subcluster/45-errors.yaml b/tests/e2e/autoscale-by-subcluster/45-errors.yaml new file mode 100644 index 000000000..795f32947 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/45-errors.yaml @@ -0,0 +1,22 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-1 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-2 diff --git a/tests/e2e/autoscale-by-subcluster/45-remove-all-but-one-scaled-subclusters.yaml b/tests/e2e/autoscale-by-subcluster/45-remove-all-but-one-scaled-subclusters.yaml new file mode 100644 index 000000000..969bf1c71 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/45-remove-all-but-one-scaled-subclusters.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale --replicas 1 diff --git a/tests/e2e/autoscale-by-subcluster/50-assert.yaml b/tests/e2e/autoscale-by-subcluster/50-assert.yaml new file mode 100644 index 000000000..f533d09d9 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/50-assert.yaml @@ -0,0 +1,34 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-pri +status: + replicas: 3 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-manual +status: + replicas: 1 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + scalingCount: 4 + currentSize: 0 diff --git a/tests/e2e/autoscale-by-subcluster/50-errors.yaml b/tests/e2e/autoscale-by-subcluster/50-errors.yaml new file mode 100644 index 000000000..552156978 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/50-errors.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-as-0 diff --git a/tests/e2e/autoscale-by-subcluster/50-remove-last-scaled-subcluster.yaml b/tests/e2e/autoscale-by-subcluster/50-remove-last-scaled-subcluster.yaml new file mode 100644 index 000000000..3a0503cc8 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/50-remove-last-scaled-subcluster.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale --replicas 0 diff --git a/tests/e2e/autoscale-by-subcluster/55-remove-template-from-vas.yaml b/tests/e2e/autoscale-by-subcluster/55-remove-template-from-vas.yaml new file mode 100644 index 000000000..dc92fd23c --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/55-remove-template-from-vas.yaml @@ -0,0 +1,26 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +spec: + verticaDBName: v-autoscale-by-subcluster + serviceName: pri + scalingGranularity: Subcluster + template: + name: "" + size: 0 + serviceName: "" + isPrimary: false diff --git a/tests/e2e/autoscale-by-subcluster/60-assert.yaml b/tests/e2e/autoscale-by-subcluster/60-assert.yaml new file mode 100644 index 000000000..db5070851 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/60-assert.yaml @@ -0,0 +1,26 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-v-autoscale-0 +status: + replicas: 3 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + currentSize: 6 diff --git a/tests/e2e/autoscale-by-subcluster/60-scale-new-subcluster.yaml b/tests/e2e/autoscale-by-subcluster/60-scale-new-subcluster.yaml new file mode 100644 index 000000000..64c03fa0b --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/60-scale-new-subcluster.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale --replicas 6 diff --git a/tests/e2e/autoscale-by-subcluster/90-errors.yaml b/tests/e2e/autoscale-by-subcluster/90-errors.yaml new file mode 100644 index 000000000..2d2e094b3 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/90-errors.yaml @@ -0,0 +1,18 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Pod +metadata: + labels: + control-plane: controller-manager diff --git a/tests/e2e/autoscale-by-subcluster/90-uninstall-operator.yaml b/tests/e2e/autoscale-by-subcluster/90-uninstall-operator.yaml new file mode 100644 index 000000000..674dcbecc --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/90-uninstall-operator.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: sh -c "cd ../../.. && make undeploy-operator NAMESPACE=$NAMESPACE" diff --git a/tests/e2e/autoscale-by-subcluster/95-assert.yaml b/tests/e2e/autoscale-by-subcluster/95-assert.yaml new file mode 100644 index 000000000..fe22a5139 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/95-assert.yaml @@ -0,0 +1,19 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Pod +metadata: + name: clean-communal +status: + phase: Succeeded diff --git a/tests/e2e/autoscale-by-subcluster/95-delete-crd.yaml b/tests/e2e/autoscale-by-subcluster/95-delete-crd.yaml new file mode 100644 index 000000000..b25eac54a --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/95-delete-crd.yaml @@ -0,0 +1,24 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: vertica.com/v1beta1 + kind: VerticaDB + - apiVersion: vertica.com/v1beta1 + kind: VerticaAutoscaler + - apiVersion: v1 + kind: PersistentVolumeClaim +commands: + - command: bash -c "kustomize build clean-communal/overlay | kubectl -n $NAMESPACE apply -f - " diff --git a/tests/e2e/autoscale-by-subcluster/95-errors.yaml b/tests/e2e/autoscale-by-subcluster/95-errors.yaml new file mode 100644 index 000000000..415cba0a7 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/95-errors.yaml @@ -0,0 +1,24 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: StatefulSet +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/managed-by: verticadb-operator +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaDB diff --git a/tests/e2e/autoscale-by-subcluster/README.txt b/tests/e2e/autoscale-by-subcluster/README.txt new file mode 100644 index 000000000..5c6f8157a --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/README.txt @@ -0,0 +1,2 @@ +The autoscaler uses the scale API. This tests autoscaler indirectly by doing +scaling operations through that scale API. diff --git a/tests/e2e/autoscale-by-subcluster/setup-vdb/base/kustomization.yaml b/tests/e2e/autoscale-by-subcluster/setup-vdb/base/kustomization.yaml new file mode 100644 index 000000000..01b927990 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/setup-vdb/base/kustomization.yaml @@ -0,0 +1,15 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resources: + - setup-vdb.yaml diff --git a/tests/e2e/autoscale-by-subcluster/setup-vdb/base/setup-vdb.yaml b/tests/e2e/autoscale-by-subcluster/setup-vdb/base/setup-vdb.yaml new file mode 100644 index 000000000..5ef926547 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/setup-vdb/base/setup-vdb.yaml @@ -0,0 +1,31 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaDB +metadata: + name: v-autoscale-by-subcluster +spec: + image: kustomize-vertica-image + communal: + includeUIDInPath: true + local: + requestSize: 100Mi + dbName: vert + shardCount: 3 + kSafety: "1" + subclusters: + - name: pri + size: 3 + requeueTime: 5 + certSecrets: [] diff --git a/tests/e2e/vas-webhook/05-assert.yaml b/tests/e2e/vas-webhook/05-assert.yaml new file mode 100644 index 000000000..fc6dfbf1c --- /dev/null +++ b/tests/e2e/vas-webhook/05-assert.yaml @@ -0,0 +1,20 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Pod +metadata: + labels: + control-plane: controller-manager +status: + phase: Running diff --git a/tests/e2e/vas-webhook/05-deploy-operator.yaml b/tests/e2e/vas-webhook/05-deploy-operator.yaml new file mode 100644 index 000000000..298db6cf6 --- /dev/null +++ b/tests/e2e/vas-webhook/05-deploy-operator.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: sh -c "cd ../../.. && make deploy-operator NAMESPACE=$NAMESPACE" diff --git a/tests/e2e/vas-webhook/10-assert.yaml b/tests/e2e/vas-webhook/10-assert.yaml new file mode 100644 index 000000000..2b40ebce4 --- /dev/null +++ b/tests/e2e/vas-webhook/10-assert.yaml @@ -0,0 +1,22 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: vas-webhook +spec: + serviceName: sc1 + scalingGranularity: Subcluster + template: + serviceName: sc1 diff --git a/tests/e2e/vas-webhook/10-create-vas-with-default-serviceName.yaml b/tests/e2e/vas-webhook/10-create-vas-with-default-serviceName.yaml new file mode 100644 index 000000000..1d7d7ed3f --- /dev/null +++ b/tests/e2e/vas-webhook/10-create-vas-with-default-serviceName.yaml @@ -0,0 +1,19 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: vas-webhook +spec: + serviceName: sc1 diff --git a/tests/e2e/vas-webhook/15-assert.yaml b/tests/e2e/vas-webhook/15-assert.yaml new file mode 100644 index 000000000..2b40ebce4 --- /dev/null +++ b/tests/e2e/vas-webhook/15-assert.yaml @@ -0,0 +1,22 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: vas-webhook +spec: + serviceName: sc1 + scalingGranularity: Subcluster + template: + serviceName: sc1 diff --git a/tests/e2e/vas-webhook/15-invalid-scalingGranularity.yaml b/tests/e2e/vas-webhook/15-invalid-scalingGranularity.yaml new file mode 100644 index 000000000..bfaa803b7 --- /dev/null +++ b/tests/e2e/vas-webhook/15-invalid-scalingGranularity.yaml @@ -0,0 +1,18 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl -n $NAMESPACE get vas vas-webhook -o json | jq '.spec.scalingGranularity="BadValue"' | kubectl -n $NAMESPACE replace -f - + ignoreFailure: true diff --git a/tests/e2e/vas-webhook/20-assert.yaml b/tests/e2e/vas-webhook/20-assert.yaml new file mode 100644 index 000000000..2b40ebce4 --- /dev/null +++ b/tests/e2e/vas-webhook/20-assert.yaml @@ -0,0 +1,22 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: vas-webhook +spec: + serviceName: sc1 + scalingGranularity: Subcluster + template: + serviceName: sc1 diff --git a/tests/e2e/vas-webhook/20-change-serviceName-invalid.yaml b/tests/e2e/vas-webhook/20-change-serviceName-invalid.yaml new file mode 100644 index 000000000..55e960287 --- /dev/null +++ b/tests/e2e/vas-webhook/20-change-serviceName-invalid.yaml @@ -0,0 +1,18 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl -n $NAMESPACE get vas vas-webhook -o json | jq '.spec.serviceName="NewValue"' | kubectl -n $NAMESPACE replace -f - + ignoreFailure: true diff --git a/tests/e2e/vas-webhook/25-assert.yaml b/tests/e2e/vas-webhook/25-assert.yaml new file mode 100644 index 000000000..0096340be --- /dev/null +++ b/tests/e2e/vas-webhook/25-assert.yaml @@ -0,0 +1,22 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: vas-webhook +spec: + serviceName: NewValue2 + scalingGranularity: Subcluster + template: + serviceName: NewValue2 diff --git a/tests/e2e/vas-webhook/25-change-serviceName-valid.yaml b/tests/e2e/vas-webhook/25-change-serviceName-valid.yaml new file mode 100644 index 000000000..6adf4ec25 --- /dev/null +++ b/tests/e2e/vas-webhook/25-change-serviceName-valid.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl -n $NAMESPACE get vas vas-webhook -o json | jq '.spec.serviceName="NewValue2"' | jq '.spec.template.serviceName="NewValue2"' | kubectl -n $NAMESPACE replace -f - diff --git a/tests/e2e/vas-webhook/95-errors.yaml b/tests/e2e/vas-webhook/95-errors.yaml new file mode 100644 index 000000000..2d2e094b3 --- /dev/null +++ b/tests/e2e/vas-webhook/95-errors.yaml @@ -0,0 +1,18 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Pod +metadata: + labels: + control-plane: controller-manager diff --git a/tests/e2e/vas-webhook/95-uninstall-operator.yaml b/tests/e2e/vas-webhook/95-uninstall-operator.yaml new file mode 100644 index 000000000..674dcbecc --- /dev/null +++ b/tests/e2e/vas-webhook/95-uninstall-operator.yaml @@ -0,0 +1,17 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: sh -c "cd ../../.. && make undeploy-operator NAMESPACE=$NAMESPACE" diff --git a/tests/e2e/vas-webhook/99-delete-vas.yaml b/tests/e2e/vas-webhook/99-delete-vas.yaml new file mode 100644 index 000000000..b58a671aa --- /dev/null +++ b/tests/e2e/vas-webhook/99-delete-vas.yaml @@ -0,0 +1,18 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: vertica.com/v1beta1 + kind: VerticaAutoscaler diff --git a/tests/e2e/vas-webhook/99-errors.yaml b/tests/e2e/vas-webhook/99-errors.yaml new file mode 100644 index 000000000..6cda45167 --- /dev/null +++ b/tests/e2e/vas-webhook/99-errors.yaml @@ -0,0 +1,15 @@ +# (c) Copyright [2021-2022] Micro Focus or one of its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler