From 934789ba47f1e213e883227c694f4fe1812c2dfd Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Thu, 10 Mar 2022 15:42:13 -0400 Subject: [PATCH 01/27] Add autoscaler CR scafolding --- .gitignore | 2 +- PROJECT | 8 +++ api/v1beta1/verticaautoscaler_types.go | 65 +++++++++++++++++++ cmd/operator/main.go | 10 ++- config/crd/kustomization.yaml | 3 + .../cainjection_in_verticaautoscalers.yaml | 7 ++ .../webhook_in_verticaautoscalers.yaml | 16 +++++ .../rbac/verticaautoscaler_editor_role.yaml | 24 +++++++ .../rbac/verticaautoscaler_viewer_role.yaml | 20 ++++++ config/samples/kustomization.yaml | 1 + config/samples/v1beta1_verticaautoscaler.yaml | 6 ++ .../verticaautoscaler_controller.go | 62 ++++++++++++++++++ 12 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 api/v1beta1/verticaautoscaler_types.go create mode 100644 config/crd/patches/cainjection_in_verticaautoscalers.yaml create mode 100644 config/crd/patches/webhook_in_verticaautoscalers.yaml create mode 100644 config/rbac/verticaautoscaler_editor_role.yaml create mode 100644 config/rbac/verticaautoscaler_viewer_role.yaml create mode 100644 config/samples/v1beta1_verticaautoscaler.yaml create mode 100644 pkg/controllers/verticaautoscaler_controller.go diff --git a/.gitignore b/.gitignore index b469cdc36..b5796d187 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,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..5c2642f2e 100644 --- a/PROJECT +++ b/PROJECT @@ -19,4 +19,12 @@ 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 version: "3" diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go new file mode 100644 index 000000000..1fbe2aa3f --- /dev/null +++ b/api/v1beta1/verticaautoscaler_types.go @@ -0,0 +1,65 @@ +/* +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" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// VerticaAutoscalerSpec defines the desired state of VerticaAutoscaler +type VerticaAutoscalerSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of VerticaAutoscaler. Edit verticaautoscaler_types.go to remove/update + Foo string `json:"foo,omitempty"` +} + +// VerticaAutoscalerStatus defines the observed state of VerticaAutoscaler +type VerticaAutoscalerStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:resource:shortName=vas +//+kubebuilder:subresource:status + +// 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{}) +} diff --git a/cmd/operator/main.go b/cmd/operator/main.go index b8a5d9942..62346f227 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -284,9 +284,17 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "VerticaDB") os.Exit(1) } - //+kubebuilder:scaffold:builder } + if err = (&controllers.VerticaAutoscalerReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VerticaAutoscaler") + os.Exit(1) + } + //+kubebuilder:scaffold:builder + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "unable to set up health check") os.Exit(1) diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 4b89cc615..4c08ea1f1 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -3,17 +3,20 @@ # It should be run by config/default resources: - bases/vertica.com_verticadbs.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_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_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/webhook_in_verticaautoscalers.yaml b/config/crd/patches/webhook_in_verticaautoscalers.yaml new file mode 100644 index 000000000..44943ce03 --- /dev/null +++ b/config/crd/patches/webhook_in_verticaautoscalers.yaml @@ -0,0 +1,16 @@ +# 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: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 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..3540f2127 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -1,4 +1,5 @@ ## Append samples you want in your CSV to this file as resources ## resources: - v1beta1_verticadb.yaml +- v1beta1_verticaautoscaler.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/v1beta1_verticaautoscaler.yaml b/config/samples/v1beta1_verticaautoscaler.yaml new file mode 100644 index 000000000..d2eca7eee --- /dev/null +++ b/config/samples/v1beta1_verticaautoscaler.yaml @@ -0,0 +1,6 @@ +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: verticaautoscaler-sample +spec: + # SPILLY: Add fields here diff --git a/pkg/controllers/verticaautoscaler_controller.go b/pkg/controllers/verticaautoscaler_controller.go new file mode 100644 index 000000000..bf71c5907 --- /dev/null +++ b/pkg/controllers/verticaautoscaler_controller.go @@ -0,0 +1,62 @@ +/* +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 controllers + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + verticacomv1beta1 "github.com/vertica/vertica-kubernetes/api/v1beta1" +) + +// VerticaAutoscalerReconciler reconciles a VerticaAutoscaler object +type VerticaAutoscalerReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=vertica.com,resources=verticaautoscalers,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=vertica.com,resources=verticaautoscalers/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=vertica.com,resources=verticaautoscalers/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. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the VerticaAutoscaler object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// 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.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *VerticaAutoscalerReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&verticacomv1beta1.VerticaAutoscaler{}). + Complete(r) +} From c8de100f9d37a47c85554b74fda29faae26f19dc Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 11 Mar 2022 13:29:06 -0400 Subject: [PATCH 02/27] More autoscaler CR updates --- api/v1beta1/verticaautoscaler_types.go | 32 +++++++++++++++++-- api/v1beta1/verticadb_types.go | 2 ++ config/samples/v1beta1_verticaautoscaler.yaml | 6 +++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 1fbe2aa3f..b1a055b6c 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -28,10 +28,38 @@ type VerticaAutoscalerSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - // Foo is an example field of VerticaAutoscaler. Edit verticaautoscaler_types.go to remove/update - Foo string `json:"foo,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 VerticaDB CR that this autoscaler is defined for. The + // VerticaDB object must exist in the same namespaec as this object. + VerticaDBName string `json:"vdbName,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +kubebuilder:default:="Pod" + // +kubebuilder:validation:Optional + // This defines how the scaling will happen. This can be one of the following: + // - Pod: Only increase or decrease the size of an existing subcluster. + // This cannot be used if more than one subcluster is defined in subclusters. + // - Subcluster: Scaling will be achieved by creating or deleting entire subclusters. + // New subclusters are created using subclusterTemplate as a template. + // Sizes of existing subclusters will remain the same. + ScalingGranularity ScalingGranularityType `json:"scalingGranularity"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // A list of subclusters, as defined in the VerticaDB, that this + // autoscaler will manage. If scalingGranularity of Subcluster, this is + // also where you define the template of new subclusters that the autoscaler + // may create. + Subclusters SubclusterSelection `json:"subclusters"` } +type ScalingGranularityType string + +const ( + PodScalingGranularity = "Pod" + SubclusterScalingGranularity = "Subcluster" +) + // VerticaAutoscalerStatus defines the observed state of VerticaAutoscaler type VerticaAutoscalerStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster diff --git a/api/v1beta1/verticadb_types.go b/api/v1beta1/verticadb_types.go index 219940185..95adf3f41 100644 --- a/api/v1beta1/verticadb_types.go +++ b/api/v1beta1/verticadb_types.go @@ -315,6 +315,8 @@ type LocalObjectReference struct { // subcluster gets client routing for subcluster we are restarting during online // upgrade. type SubclusterSelection struct { + // SPILLY - if we do end up using this for the autoscaler, lets update the + // comments so that it isn't specific to online upgrade // +operator-sdk:csv:customresourcedefinitions:type=spec // +kubebuilder:validation:Optional // Names of existing subclusters to use for temporary routing of client diff --git a/config/samples/v1beta1_verticaautoscaler.yaml b/config/samples/v1beta1_verticaautoscaler.yaml index d2eca7eee..d43666555 100644 --- a/config/samples/v1beta1_verticaautoscaler.yaml +++ b/config/samples/v1beta1_verticaautoscaler.yaml @@ -3,4 +3,8 @@ kind: VerticaAutoscaler metadata: name: verticaautoscaler-sample spec: - # SPILLY: Add fields here + verticaDBName: verticadb-sample + subclusters: + names: + - defaultsubcluster + scalePolicy: ResizeSubcluster From 03d0f73e83df4b6700743a1cb2234b2494614dd0 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Mon, 14 Mar 2022 15:45:52 -0300 Subject: [PATCH 03/27] Finish subcluster resize --- api/v1beta1/verticaautoscaler_types.go | 71 +++++-- api/v1beta1/verticadb_types.go | 13 +- cmd/operator/main.go | 2 + config/samples/v1beta1_verticaautoscaler.yaml | 6 +- config/samples/v1beta1_verticadb.yaml | 7 + pkg/controllers/k8s.go | 17 ++ pkg/controllers/subclusterresize_reconcile.go | 116 ++++++++++++ .../subclusterresize_reconcile_test.go | 177 ++++++++++++++++++ pkg/controllers/suite_test.go | 9 + pkg/controllers/vasstatus_reconciler.go | 74 ++++++++ .../verticaautoscaler_controller.go | 62 ++++-- pkg/events/event.go | 7 + pkg/test/helpers.go | 17 ++ scripts/create-helm-charts.sh | 3 +- 14 files changed, 549 insertions(+), 32 deletions(-) create mode 100644 pkg/controllers/subclusterresize_reconcile.go create mode 100644 pkg/controllers/subclusterresize_reconcile_test.go create mode 100644 pkg/controllers/vasstatus_reconciler.go diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index b1a055b6c..97710b0b6 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -14,15 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ +// nolint:lll package v1beta1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - // VerticaAutoscalerSpec defines the desired state of VerticaAutoscaler type VerticaAutoscalerSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster @@ -32,25 +31,41 @@ type VerticaAutoscalerSpec struct { // +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 namespaec as this object. - VerticaDBName string `json:"vdbName,omitempty"` + VerticaDBName string `json:"verticaDBName,omitempty"` // +operator-sdk:csv:customresourcedefinitions:type=spec // +kubebuilder:default:="Pod" // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:select:Create","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: // - Pod: Only increase or decrease the size of an existing subcluster. - // This cannot be used if more than one subcluster is defined in subclusters. + // This cannot be used if more than one subcluster is selected with + // subclusterServiceName. // - Subcluster: Scaling will be achieved by creating or deleting entire subclusters. // New subclusters are created using subclusterTemplate as a template. // Sizes of existing subclusters will remain the same. ScalingGranularity ScalingGranularityType `json:"scalingGranularity"` // +operator-sdk:csv:customresourcedefinitions:type=spec - // A list of subclusters, as defined in the VerticaDB, that this - // autoscaler will manage. If scalingGranularity of Subcluster, this is - // also where you define the template of new subclusters that the autoscaler - // may create. - Subclusters SubclusterSelection `json:"subclusters"` + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:text" + // This acts as a selector for the subclusters that being scaled together. + // The name refers to the service name as defined in the subcluster section + // of the VerticaDB, which is typically the same name as the subcluster name. + SubclusterServiceName string `json:"subclusterServiceName"` + + // +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 + // subclusterServiceName. Changing this value may trigger a change in the + // VerticaDB that is associated with this object. This value is generally + // left as the default and modified by the horizontal autoscaler through the + // /scale subresource. + TargetSize int32 `json:"targetSize,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +kubebuilder:validation:Optional + Selector metav1.LabelSelector `json:"selector"` } type ScalingGranularityType string @@ -62,13 +77,16 @@ const ( // VerticaAutoscalerStatus defines the observed state of VerticaAutoscaler type VerticaAutoscalerStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file + Size int32 `json:"size"` + Selector string `json:"selector"` } //+kubebuilder:object:root=true //+kubebuilder:resource:shortName=vas //+kubebuilder:subresource:status +//+kubebuilder:subresource:scale:specpath=.spec.targetSize,statuspath=.status.size,selectorpath=.status.selector +//+kubebuilder:printcolumn:name="Size",type="integer",JSONPath=".status.size" +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // VerticaAutoscaler is the Schema for the verticaautoscalers API type VerticaAutoscaler struct { @@ -91,3 +109,32 @@ type VerticaAutoscalerList struct { 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: "vertica.com/v1beta1", + Kind: "VerticaAutoscaler", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: vasNm.Name, + Namespace: vasNm.Namespace, + UID: "abcdef-ghi", + Annotations: make(map[string]string), + }, + Spec: VerticaAutoscalerSpec{ + VerticaDBName: vdbNm.Name, + ScalingGranularity: "Pod", + SubclusterServiceName: "sc1", + }, + } +} diff --git a/api/v1beta1/verticadb_types.go b/api/v1beta1/verticadb_types.go index 95adf3f41..7ccf379d7 100644 --- a/api/v1beta1/verticadb_types.go +++ b/api/v1beta1/verticadb_types.go @@ -315,8 +315,6 @@ type LocalObjectReference struct { // subcluster gets client routing for subcluster we are restarting during online // upgrade. type SubclusterSelection struct { - // SPILLY - if we do end up using this for the autoscaler, lets update the - // comments so that it isn't specific to online upgrade // +operator-sdk:csv:customresourcedefinitions:type=spec // +kubebuilder:validation:Optional // Names of existing subclusters to use for temporary routing of client @@ -958,6 +956,17 @@ 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) []*Subcluster { + scs := []*Subcluster{} + for i := range v.Spec.Subclusters { + if v.Spec.Subclusters[i].GetServiceName() == svcName { + scs = append(scs, &v.Spec.Subclusters[i]) + } + } + return scs +} + // RequiresTransientSubcluster checks if an online upgrade requires a // transient subcluster. A transient subcluster exists if the template is // filled out. diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 62346f227..28552a8a4 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -289,6 +289,8 @@ func main() { if err = (&controllers.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) diff --git a/config/samples/v1beta1_verticaautoscaler.yaml b/config/samples/v1beta1_verticaautoscaler.yaml index d43666555..34a0f8f93 100644 --- a/config/samples/v1beta1_verticaautoscaler.yaml +++ b/config/samples/v1beta1_verticaautoscaler.yaml @@ -4,7 +4,5 @@ metadata: name: verticaautoscaler-sample spec: verticaDBName: verticadb-sample - subclusters: - names: - - defaultsubcluster - scalePolicy: ResizeSubcluster + subclusterServiceName: defaultsubcluster + scalingGranularity: Pod diff --git a/config/samples/v1beta1_verticadb.yaml b/config/samples/v1beta1_verticadb.yaml index 2e51ddd1a..c52a76868 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 as a sample so that 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/pkg/controllers/k8s.go b/pkg/controllers/k8s.go index 6c015ba9b..1fd1a353f 100644 --- a/pkg/controllers/k8s.go +++ b/pkg/controllers/k8s.go @@ -72,3 +72,20 @@ func getConfigMapOrSecret(ctx context.Context, vrec *VerticaDBReconciler, vdb *v } return ctrl.Result{}, nil } + +// 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/subclusterresize_reconcile.go b/pkg/controllers/subclusterresize_reconcile.go new file mode 100644 index 000000000..51abe4ed4 --- /dev/null +++ b/pkg/controllers/subclusterresize_reconcile.go @@ -0,0 +1,116 @@ +/* + (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 controllers + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/events" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" +) + +// StatusReconciler will update the status field of the vdb. +type SubclusterResizeReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler + Vdb *vapi.VerticaDB +} + +// MakeStatusReconciler will build a StatusReconciler object +func MakeSubclusterResizeReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { + return &SubclusterResizeReconciler{VRec: r, Vas: vas, Vdb: &vapi.VerticaDB{}} +} + +// Reconcile will update the status of the Vdb based on the pod facts +func (s *SubclusterResizeReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + if s.Vas.Spec.ScalingGranularity != vapi.PodScalingGranularity { + return ctrl.Result{}, nil + } + + if res, err := fetchVDB(ctx, s.VRec, s.Vas, s.Vdb); verrors.IsReconcileAborted(res, err) { + return res, err + } + + if s.Vas.Spec.TargetSize == 0 { + s.VRec.Log.Info("Target not set yet in VerticaAutoscaler") + return ctrl.Result{}, nil + } + + return s.resizeSubcluster(ctx) +} + +// resizeSubcluster will change the size of a subcluster given the target pod count +func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context) (ctrl.Result, error) { + var res ctrl.Result + // Update the VerticaAutoscaler with a retry mechanism for any conflict updates + 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 := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + if len(subclusters) == 0 { + s.VRec.EVRec.Eventf(s.Vas, corev1.EventTypeWarning, events.VerticaDBNotFound, + "Could not find any subclusters with service name '%s'", s.Vas.Spec.SubclusterServiceName) + res.Requeue = true + return nil + } + + delta := s.findResizeDelta(subclusters) + 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 + } + } + + return s.VRec.Client.Update(ctx, s.Vdb) + }) + + return res, err +} + +// findResizeDelta determines the change that must occur to reach the target +// size. If the number is positive, then we are going to increase the size of a +// subcluster. If the number is negative, we need to decrease the size. +func (s *SubclusterResizeReconciler) findResizeDelta(subclusters []*vapi.Subcluster) int32 { + var curSize int32 + for i := range subclusters { + curSize += subclusters[i].Size + } + return s.Vas.Spec.TargetSize - curSize +} diff --git a/pkg/controllers/subclusterresize_reconcile_test.go b/pkg/controllers/subclusterresize_reconcile_test.go new file mode 100644 index 000000000..2aca44bef --- /dev/null +++ b/pkg/controllers/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 controllers + +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.SubclusterServiceName = "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.SubclusterServiceName = 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.SubclusterServiceName = 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.SubclusterServiceName = 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.SubclusterServiceName = 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.SubclusterServiceName = 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/suite_test.go b/pkg/controllers/suite_test.go index 8baeccfe7..ce47fc3c8 100644 --- a/pkg/controllers/suite_test.go +++ b/pkg/controllers/suite_test.go @@ -45,6 +45,7 @@ var testEnv *envtest.Environment var logger logr.Logger var restCfg *rest.Config var vrec *VerticaDBReconciler +var vasRec *VerticaAutoscalerReconciler var _ = BeforeSuite(func() { logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)) @@ -73,6 +74,7 @@ var _ = BeforeSuite(func() { }) Expect(err).NotTo(HaveOccurred()) + // SPILLY - rename vrec vrec = &VerticaDBReconciler{ Client: k8sClient, Log: logger, @@ -80,6 +82,13 @@ var _ = BeforeSuite(func() { Cfg: restCfg, EVRec: mgr.GetEventRecorderFor(builder.OperatorName), } + + vasRec = &VerticaAutoscalerReconciler{ + Client: k8sClient, + Log: logger, + Scheme: scheme.Scheme, + EVRec: mgr.GetEventRecorderFor(builder.OperatorName), + } }, 60) var _ = AfterSuite(func() { diff --git a/pkg/controllers/vasstatus_reconciler.go b/pkg/controllers/vasstatus_reconciler.go new file mode 100644 index 000000000..86768ca3d --- /dev/null +++ b/pkg/controllers/vasstatus_reconciler.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 controllers + +import ( + "context" + "fmt" + "reflect" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/builder" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" +) + +type VASStatusReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler +} + +// MakeVASStatusReconciler will create a VASStatusReconciler object and return it +func MakeVASStatusReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { + return &VASStatusReconciler{VRec: v, Vas: vas} +} + +// Reconcile will handle updating the status portion of a VerticaAutoscaler +func (v *VASStatusReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { + var res ctrl.Result + vdb := &vapi.VerticaDB{} + + // Try the status update in a retry loop to handle the case where someone + // update the VerticaAutoscaler since we last fetched. + err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + if r, e := fetchVDB(ctx, v.VRec, v.Vas, vdb); verrors.IsReconcileAborted(r, e) { + res = r + return e + } + + // 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 := v.Vas.DeepCopy() + + v.Vas.Status.Selector = fmt.Sprintf("%s=%s", builder.SubclusterSvcNameLabel, v.Vas.Spec.SubclusterServiceName) + + subclusters := vdb.FindSubclusterForServiceName(v.Vas.Spec.SubclusterServiceName) + v.Vas.Status.Size = 0 + for i := range subclusters { + v.Vas.Status.Size += subclusters[i].Size + } + + if !reflect.DeepEqual(vasOrig, v.Vas.Status) { + if err := v.VRec.Client.Status().Update(ctx, v.Vas); err != nil { + return err + } + } + return nil + }) + + return res, err +} diff --git a/pkg/controllers/verticaautoscaler_controller.go b/pkg/controllers/verticaautoscaler_controller.go index bf71c5907..69a913c6a 100644 --- a/pkg/controllers/verticaautoscaler_controller.go +++ b/pkg/controllers/verticaautoscaler_controller.go @@ -18,45 +18,81 @@ package controllers 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" - "sigs.k8s.io/controller-runtime/pkg/log" - verticacomv1beta1 "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/go-logr/logr" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + 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 } -//+kubebuilder:rbac:groups=vertica.com,resources=verticaautoscalers,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=vertica.com,resources=verticaautoscalers/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=vertica.com,resources=verticaautoscalers/finalizers,verbs=update +//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. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the VerticaAutoscaler object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. // // 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.FromContext(ctx) + log := r.Log.WithValues("verticaautoscaler", req.NamespacedName) + log.Info("starting reconcile of VerticaAutoscaler") - // TODO(user): your logic here + 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{}, nil + } - return ctrl.Result{}, nil + // The actors that will be applied, in sequence, to reconcile a vas. + actors := []ReconcileActor{ + // If scaling granularity is Pod, this will resize existing subclusters + // depending on the targetSize. + MakeSubclusterResizeReconciler(r, vas), + // Update the status portion of the VerticaAutoscaler + MakeVASStatusReconciler(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(&verticacomv1beta1.VerticaAutoscaler{}). + For(&vapi.VerticaAutoscaler{}). Complete(r) } diff --git a/pkg/events/event.go b/pkg/events/event.go index a98ab815d..e5c8e984e 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" @@ -65,3 +66,9 @@ const ( InvalidUpgradePath = "InvalidUpgradePath" RebalanceShards = "RebalanceShards" ) + +// Constants for VerticaAutoscaler reconciler +const ( + SubclusterServiceNameNotFound = "SubclusterServiceNameNotFound" + VerticaDBNotFound = "VerticaDBNotFound" +) diff --git a/pkg/test/helpers.go b/pkg/test/helpers.go index 4f9c91cca..35bb203f3 100644 --- a/pkg/test/helpers.go +++ b/pkg/test/helpers.go @@ -175,3 +175,20 @@ func DeleteSvcs(ctx context.Context, c client.Client, vdb *vapi.VerticaDB) { ExpectWithOffset(1, c.Delete(ctx, svc)).Should(Succeed()) } } + +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()) +} + +// SPILLY - remove similar functions in suite_test.go +func CreateVDB(ctx context.Context, c client.Client, vdb *vapi.VerticaDB) { + ExpectWithOffset(1, c.Create(ctx, vdb)).Should(Succeed()) +} + +func DeleteVDB(ctx context.Context, c client.Client, vdb *vapi.VerticaDB) { + ExpectWithOffset(1, c.Delete(ctx, vdb)).Should(Succeed()) +} diff --git a/scripts/create-helm-charts.sh b/scripts/create-helm-charts.sh index d4cdf224b..5e3d2408c 100755 --- a/scripts/create-helm-charts.sh +++ b/scripts/create-helm-charts.sh @@ -27,6 +27,7 @@ TEMPLATE_DIR=$OPERATOR_CHART/templates $KUSTOMIZE build $REPO_DIR/config/default | $KUBERNETES_SPLIT_YAML --outdir $TEMPLATE_DIR - mv $TEMPLATE_DIR/verticadbs.vertica.com-crd.yaml $OPERATOR_CHART/crds +mv $TEMPLATE_DIR/verticaautoscalers.vertica.com-crd.yaml $OPERATOR_CHART/crds # Add in the templating # 1. Template the namespace @@ -59,4 +60,4 @@ sed -i "s/--dev=.*/--dev={{ .Values.logging.dev }}/" $TEMPLATE_DIR/verticadb-ope # Delete openshift clusterRole and clusterRoleBinding files rm $TEMPLATE_DIR/verticadb-operator-openshift-cluster-role-cr.yaml -rm $TEMPLATE_DIR/verticadb-operator-openshift-cluster-rolebinding-crb.yaml \ No newline at end of file +rm $TEMPLATE_DIR/verticadb-operator-openshift-cluster-rolebinding-crb.yaml From 7fb4cb7db3423f794fd601e5c24614e3c829b721 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Tue, 15 Mar 2022 09:46:05 -0300 Subject: [PATCH 04/27] Add autoscale e2e test --- .../05-create-communal-creds.yaml | 17 ++++++++ tests/e2e/autoscale-sanity/10-assert.yaml | 20 ++++++++++ .../autoscale-sanity/10-deploy-operator.yaml | 17 ++++++++ tests/e2e/autoscale-sanity/15-assert.yaml | 19 +++++++++ tests/e2e/autoscale-sanity/15-setup-vdb.yaml | 17 ++++++++ tests/e2e/autoscale-sanity/20-assert.yaml | 39 +++++++++++++++++++ .../20-wait-for-createdb.yaml | 1 + tests/e2e/autoscale-sanity/25-assert.yaml | 28 +++++++++++++ .../25-create-autoscale-CR.yaml | 30 ++++++++++++++ tests/e2e/autoscale-sanity/30-assert.yaml | 26 +++++++++++++ .../autoscale-sanity/30-scale-sc1-to-3.yaml | 17 ++++++++ tests/e2e/autoscale-sanity/35-assert.yaml | 26 +++++++++++++ .../autoscale-sanity/35-scale-sc1-to-2.yaml | 17 ++++++++ tests/e2e/autoscale-sanity/40-assert.yaml | 26 +++++++++++++ .../autoscale-sanity/40-scale-sc2-to-3.yaml | 17 ++++++++ tests/e2e/autoscale-sanity/45-assert.yaml | 26 +++++++++++++ .../autoscale-sanity/45-scale-sc2-to-1.yaml | 17 ++++++++ tests/e2e/autoscale-sanity/90-errors.yaml | 18 +++++++++ .../90-uninstall-operator.yaml | 17 ++++++++ tests/e2e/autoscale-sanity/95-assert.yaml | 19 +++++++++ tests/e2e/autoscale-sanity/95-delete-crd.yaml | 24 ++++++++++++ tests/e2e/autoscale-sanity/95-errors.yaml | 24 ++++++++++++ tests/e2e/autoscale-sanity/README.txt | 2 + .../setup-vdb/base/kustomization.yaml | 15 +++++++ .../setup-vdb/base/setup-vdb.yaml | 33 ++++++++++++++++ 25 files changed, 512 insertions(+) create mode 100644 tests/e2e/autoscale-sanity/05-create-communal-creds.yaml create mode 100644 tests/e2e/autoscale-sanity/10-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/10-deploy-operator.yaml create mode 100644 tests/e2e/autoscale-sanity/15-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/15-setup-vdb.yaml create mode 100644 tests/e2e/autoscale-sanity/20-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/20-wait-for-createdb.yaml create mode 100644 tests/e2e/autoscale-sanity/25-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/25-create-autoscale-CR.yaml create mode 100644 tests/e2e/autoscale-sanity/30-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/30-scale-sc1-to-3.yaml create mode 100644 tests/e2e/autoscale-sanity/35-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/35-scale-sc1-to-2.yaml create mode 100644 tests/e2e/autoscale-sanity/40-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/40-scale-sc2-to-3.yaml create mode 100644 tests/e2e/autoscale-sanity/45-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/45-scale-sc2-to-1.yaml create mode 100644 tests/e2e/autoscale-sanity/90-errors.yaml create mode 100644 tests/e2e/autoscale-sanity/90-uninstall-operator.yaml create mode 100644 tests/e2e/autoscale-sanity/95-assert.yaml create mode 100644 tests/e2e/autoscale-sanity/95-delete-crd.yaml create mode 100644 tests/e2e/autoscale-sanity/95-errors.yaml create mode 100644 tests/e2e/autoscale-sanity/README.txt create mode 100644 tests/e2e/autoscale-sanity/setup-vdb/base/kustomization.yaml create mode 100644 tests/e2e/autoscale-sanity/setup-vdb/base/setup-vdb.yaml diff --git a/tests/e2e/autoscale-sanity/05-create-communal-creds.yaml b/tests/e2e/autoscale-sanity/05-create-communal-creds.yaml new file mode 100644 index 000000000..0e0a64cb3 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/10-assert.yaml b/tests/e2e/autoscale-sanity/10-assert.yaml new file mode 100644 index 000000000..fc6dfbf1c --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/10-deploy-operator.yaml b/tests/e2e/autoscale-sanity/10-deploy-operator.yaml new file mode 100644 index 000000000..298db6cf6 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/15-assert.yaml b/tests/e2e/autoscale-sanity/15-assert.yaml new file mode 100644 index 000000000..b8ae6635e --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity-sc1 +status: + replicas: 2 diff --git a/tests/e2e/autoscale-sanity/15-setup-vdb.yaml b/tests/e2e/autoscale-sanity/15-setup-vdb.yaml new file mode 100644 index 000000000..3e10786a3 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/20-assert.yaml b/tests/e2e/autoscale-sanity/20-assert.yaml new file mode 100644 index 000000000..3dabcc77d --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity-sc1 +status: + replicas: 2 + readyReplicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-sanity-sc2 +status: + replicas: 1 + readyReplicas: 1 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaDB +metadata: + name: v-autoscale-sanity +status: + subclusters: + - installCount: 2 + addedToDBCount: 2 + - installCount: 1 + addedToDBCount: 1 diff --git a/tests/e2e/autoscale-sanity/20-wait-for-createdb.yaml b/tests/e2e/autoscale-sanity/20-wait-for-createdb.yaml new file mode 100644 index 000000000..bf3726035 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/25-assert.yaml b/tests/e2e/autoscale-sanity/25-assert.yaml new file mode 100644 index 000000000..3f89f65a8 --- /dev/null +++ b/tests/e2e/autoscale-sanity/25-assert.yaml @@ -0,0 +1,28 @@ +# (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-sanity-sc1 +status: + selector: vertica.com/subcluster-svc=sc1 + size: 2 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-sanity-sc2 +status: + selector: vertica.com/subcluster-svc=sc2 + size: 1 diff --git a/tests/e2e/autoscale-sanity/25-create-autoscale-CR.yaml b/tests/e2e/autoscale-sanity/25-create-autoscale-CR.yaml new file mode 100644 index 000000000..c23524511 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity-sc1 +spec: + verticaDBName: v-autoscale-sanity + subclusterServiceName: sc1 + scalingGranularity: Pod +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale-sanity-sc2 +spec: + verticaDBName: v-autoscale-sanity + subclusterServiceName: sc2 + scalingGranularity: Pod diff --git a/tests/e2e/autoscale-sanity/30-assert.yaml b/tests/e2e/autoscale-sanity/30-assert.yaml new file mode 100644 index 000000000..5a279aa9f --- /dev/null +++ b/tests/e2e/autoscale-sanity/30-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-sanity-sc1 +status: + replicas: 3 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-sanity-sc2 +status: + replicas: 1 diff --git a/tests/e2e/autoscale-sanity/30-scale-sc1-to-3.yaml b/tests/e2e/autoscale-sanity/30-scale-sc1-to-3.yaml new file mode 100644 index 000000000..f5d047df1 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity-sc1 --replicas 3 diff --git a/tests/e2e/autoscale-sanity/35-assert.yaml b/tests/e2e/autoscale-sanity/35-assert.yaml new file mode 100644 index 000000000..cc1dd0e0f --- /dev/null +++ b/tests/e2e/autoscale-sanity/35-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-sanity-sc1 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-sanity-sc2 +status: + replicas: 1 diff --git a/tests/e2e/autoscale-sanity/35-scale-sc1-to-2.yaml b/tests/e2e/autoscale-sanity/35-scale-sc1-to-2.yaml new file mode 100644 index 000000000..3eebc0703 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity-sc1 --replicas 2 diff --git a/tests/e2e/autoscale-sanity/40-assert.yaml b/tests/e2e/autoscale-sanity/40-assert.yaml new file mode 100644 index 000000000..eee94b476 --- /dev/null +++ b/tests/e2e/autoscale-sanity/40-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-sanity-sc1 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-sanity-sc2 +status: + replicas: 3 diff --git a/tests/e2e/autoscale-sanity/40-scale-sc2-to-3.yaml b/tests/e2e/autoscale-sanity/40-scale-sc2-to-3.yaml new file mode 100644 index 000000000..e191ef92c --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity-sc2 --replicas 3 diff --git a/tests/e2e/autoscale-sanity/45-assert.yaml b/tests/e2e/autoscale-sanity/45-assert.yaml new file mode 100644 index 000000000..cc1dd0e0f --- /dev/null +++ b/tests/e2e/autoscale-sanity/45-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-sanity-sc1 +status: + replicas: 2 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-sanity-sc2 +status: + replicas: 1 diff --git a/tests/e2e/autoscale-sanity/45-scale-sc2-to-1.yaml b/tests/e2e/autoscale-sanity/45-scale-sc2-to-1.yaml new file mode 100644 index 000000000..e029a5bfc --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity-sc2 --replicas 1 diff --git a/tests/e2e/autoscale-sanity/90-errors.yaml b/tests/e2e/autoscale-sanity/90-errors.yaml new file mode 100644 index 000000000..2d2e094b3 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/90-uninstall-operator.yaml b/tests/e2e/autoscale-sanity/90-uninstall-operator.yaml new file mode 100644 index 000000000..674dcbecc --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/95-assert.yaml b/tests/e2e/autoscale-sanity/95-assert.yaml new file mode 100644 index 000000000..fe22a5139 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/95-delete-crd.yaml b/tests/e2e/autoscale-sanity/95-delete-crd.yaml new file mode 100644 index 000000000..b25eac54a --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/95-errors.yaml b/tests/e2e/autoscale-sanity/95-errors.yaml new file mode 100644 index 000000000..415cba0a7 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/README.txt b/tests/e2e/autoscale-sanity/README.txt new file mode 100644 index 000000000..5c6f8157a --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/setup-vdb/base/kustomization.yaml b/tests/e2e/autoscale-sanity/setup-vdb/base/kustomization.yaml new file mode 100644 index 000000000..01b927990 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity/setup-vdb/base/setup-vdb.yaml b/tests/e2e/autoscale-sanity/setup-vdb/base/setup-vdb.yaml new file mode 100644 index 000000000..0b09489f2 --- /dev/null +++ b/tests/e2e/autoscale-sanity/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-sanity +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: [] From 4b17cfe99b3fcde4ba51fd1eaf3a6d5a4ac5da45 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Tue, 22 Mar 2022 08:47:08 -0300 Subject: [PATCH 05/27] Fix merge conflicts --- pkg/controllers/suite_test.go | 6 +----- pkg/test/helpers.go | 8 ++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pkg/controllers/suite_test.go b/pkg/controllers/suite_test.go index c0a6a65a4..52fe60324 100644 --- a/pkg/controllers/suite_test.go +++ b/pkg/controllers/suite_test.go @@ -44,12 +44,8 @@ var k8sClient client.Client var testEnv *envtest.Environment var logger logr.Logger var restCfg *rest.Config -<<<<<<< HEAD -var vrec *VerticaDBReconciler -var vasRec *VerticaAutoscalerReconciler -======= var vdbRec *VerticaDBReconciler ->>>>>>> main +var vasRec *VerticaAutoscalerReconciler var _ = BeforeSuite(func() { logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)) 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()) } From 6c18e7a6dd645b0cd9410d74ee1aa54708c1d598 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Thu, 24 Mar 2022 15:53:26 -0300 Subject: [PATCH 06/27] Add scaling by subcluster --- api/v1beta1/verticaautoscaler_types.go | 13 +- api/v1beta1/verticadb_types.go | 8 +- go.mod | 1 + go.sum | 2 + pkg/controllers/subclusterresize_reconcile.go | 25 +--- pkg/controllers/subclusterscale_reconcile.go | 136 ++++++++++++++++++ .../subclusterscale_reconcile_test.go | 112 +++++++++++++++ pkg/controllers/vasstatus_reconciler.go | 7 +- pkg/controllers/vdbverify_reconcile.go | 42 ++++++ .../verticaautoscaler_controller.go | 5 + 10 files changed, 319 insertions(+), 32 deletions(-) create mode 100644 pkg/controllers/subclusterscale_reconcile.go create mode 100644 pkg/controllers/subclusterscale_reconcile_test.go create mode 100644 pkg/controllers/vdbverify_reconcile.go diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 97710b0b6..032e87345 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -53,6 +53,15 @@ type VerticaAutoscalerSpec struct { // of the VerticaDB, which is typically the same name as the subcluster name. SubclusterServiceName string `json:"subclusterServiceName"` + // +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. The service name + // must match the subclusterServiceName parameter. The name of the + // subcluster will be auto generated when the subcluster is added to the + // VerticaDB. + 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" @@ -62,10 +71,6 @@ type VerticaAutoscalerSpec struct { // left as the default and modified by the horizontal autoscaler through the // /scale subresource. TargetSize int32 `json:"targetSize,omitempty"` - - // +operator-sdk:csv:customresourcedefinitions:type=spec - // +kubebuilder:validation:Optional - Selector metav1.LabelSelector `json:"selector"` } type ScalingGranularityType string diff --git a/api/v1beta1/verticadb_types.go b/api/v1beta1/verticadb_types.go index 5c994a283..b5df9411d 100644 --- a/api/v1beta1/verticadb_types.go +++ b/api/v1beta1/verticadb_types.go @@ -968,14 +968,16 @@ func (s *Subcluster) GetServiceName() string { } // FindSubclusterForServiceName will find any subclusters that match the given service name -func (v *VerticaDB) FindSubclusterForServiceName(svcName string) []*Subcluster { - scs := []*Subcluster{} +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 + return scs, totalSize } // RequiresTransientSubcluster checks if an online upgrade requires a diff --git a/go.mod b/go.mod index 6b10bfb43..ffb24e3f6 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.17 require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/bigkevmcd/go-configparser v0.0.0-20210106142102-909504547ead + github.com/docker/docker v20.10.14+incompatible github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v1.2.0 github.com/go-logr/zapr v1.2.0 diff --git a/go.sum b/go.sum index 5706c14a3..52628ad24 100644 --- a/go.sum +++ b/go.sum @@ -121,6 +121,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/docker v20.10.14+incompatible h1:+T9/PRYWNDo5SZl5qS1r9Mo/0Q8AwxKKPtu9S1yxM0w= +github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= diff --git a/pkg/controllers/subclusterresize_reconcile.go b/pkg/controllers/subclusterresize_reconcile.go index 51abe4ed4..db12e1877 100644 --- a/pkg/controllers/subclusterresize_reconcile.go +++ b/pkg/controllers/subclusterresize_reconcile.go @@ -26,28 +26,24 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ) -// StatusReconciler will update the status field of the vdb. +// 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 } -// MakeStatusReconciler will build a StatusReconciler object func MakeSubclusterResizeReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { return &SubclusterResizeReconciler{VRec: r, Vas: vas, Vdb: &vapi.VerticaDB{}} } -// Reconcile will update the status of the Vdb based on the pod facts +// 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 } - if res, err := fetchVDB(ctx, s.VRec, s.Vas, s.Vdb); verrors.IsReconcileAborted(res, err) { - return res, err - } - if s.Vas.Spec.TargetSize == 0 { s.VRec.Log.Info("Target not set yet in VerticaAutoscaler") return ctrl.Result{}, nil @@ -66,7 +62,7 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context) (ctrl return e } - subclusters := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + subclusters, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) if len(subclusters) == 0 { s.VRec.EVRec.Eventf(s.Vas, corev1.EventTypeWarning, events.VerticaDBNotFound, "Could not find any subclusters with service name '%s'", s.Vas.Spec.SubclusterServiceName) @@ -74,7 +70,7 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context) (ctrl return nil } - delta := s.findResizeDelta(subclusters) + delta := s.Vas.Spec.TargetSize - totSize if delta == 0 { return nil } @@ -103,14 +99,3 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context) (ctrl return res, err } - -// findResizeDelta determines the change that must occur to reach the target -// size. If the number is positive, then we are going to increase the size of a -// subcluster. If the number is negative, we need to decrease the size. -func (s *SubclusterResizeReconciler) findResizeDelta(subclusters []*vapi.Subcluster) int32 { - var curSize int32 - for i := range subclusters { - curSize += subclusters[i].Size - } - return s.Vas.Spec.TargetSize - curSize -} diff --git a/pkg/controllers/subclusterscale_reconcile.go b/pkg/controllers/subclusterscale_reconcile.go new file mode 100644 index 000000000..4d3212132 --- /dev/null +++ b/pkg/controllers/subclusterscale_reconcile.go @@ -0,0 +1,136 @@ +/* + (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 controllers + +import ( + "context" + "fmt" + "strings" + + "github.com/docker/docker/pkg/namesgenerator" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "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) 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 + } + + if s.Vas.Spec.TargetSize == 0 { + s.VRec.Log.Info("Target not set yet in VerticaAutoscaler") + return ctrl.Result{}, nil + } + + return s.scaleSubcluster(ctx) +} + +// scaleSubcluster will decide to add or remove whole subclusters to reach the +// target size +func (s *SubclusterScaleReconciler) scaleSubcluster(ctx context.Context) (ctrl.Result, error) { + var res ctrl.Result + // Update the VerticaAutoscaler with a retry mechanism for any conflict updates + 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.SubclusterServiceName) + 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 + } + + return s.VRec.Client.Update(ctx, s.Vdb) + }) + return res, err +} + +// considerRemovingSubclusters will shrink the Vdb by removing new subclusters. +// 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.SubclusterServiceName { + if podsToRemove > 0 && sc.Size <= podsToRemove { + s.Vdb.Spec.Subclusters = append(s.Vdb.Spec.Subclusters[:j], s.Vdb.Spec.Subclusters[j+1:]...) + podsToRemove -= sc.Size + s.VRec.Log.Info("Removing subcluster to VerticaDB", "VerticaDB", s.Vdb.Name, "Subcluster", sc.Name) + 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(nowPodsNeeded int32) bool { + origSize := len(s.Vdb.Spec.Subclusters) + scMap := s.Vdb.GenSubclusterMap() + for nowPodsNeeded >= s.Vas.Spec.Template.Size { + s.Vdb.Spec.Subclusters = append(s.Vdb.Spec.Subclusters, s.Vas.Spec.Template) + sc := &s.Vdb.Spec.Subclusters[len(s.Vdb.Spec.Subclusters)-1] + sc.Name = s.genNextSubclusterName(scMap) + scMap[sc.Name] = sc + nowPodsNeeded -= sc.Size + s.VRec.Log.Info("Adding subcluster to VerticaDB", "VerticaDB", s.Vdb.Name, "Subcluster", sc.Name, "Size", sc.Size) + } + return origSize != 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 { + name := "" + for { + // Generate a name by using the docker naming convention. Replacing '_' + // with '-' so that the name is valid. + name = fmt.Sprintf("%s-%s", + s.Vas.Spec.Template.Name, + strings.Replace(namesgenerator.GetRandomName(0), "_", "-", -1)) + _, ok := scMap[name] + if !ok { + return name + } + } +} diff --git a/pkg/controllers/subclusterscale_reconcile_test.go b/pkg/controllers/subclusterscale_reconcile_test.go new file mode 100644 index 000000000..f2aed421d --- /dev/null +++ b/pkg/controllers/subclusterscale_reconcile_test.go @@ -0,0 +1,112 @@ +/* + (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 controllers + +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("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[2].Size).Should(Equal(vas.Spec.Template.Size)) + Expect(fetchVdb.Spec.Subclusters[1].Name).ShouldNot(Equal(fetchVdb.Spec.Subclusters[2])) + Expect(fetchVdb.Spec.Subclusters[1].Name).Should(HavePrefix(vas.Spec.Template.Name)) + }) + + 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.SubclusterServiceName = 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)) + }) +}) diff --git a/pkg/controllers/vasstatus_reconciler.go b/pkg/controllers/vasstatus_reconciler.go index 86768ca3d..0e274002e 100644 --- a/pkg/controllers/vasstatus_reconciler.go +++ b/pkg/controllers/vasstatus_reconciler.go @@ -56,11 +56,8 @@ func (v *VASStatusReconciler) Reconcile(ctx context.Context, req *ctrl.Request) v.Vas.Status.Selector = fmt.Sprintf("%s=%s", builder.SubclusterSvcNameLabel, v.Vas.Spec.SubclusterServiceName) - subclusters := vdb.FindSubclusterForServiceName(v.Vas.Spec.SubclusterServiceName) - v.Vas.Status.Size = 0 - for i := range subclusters { - v.Vas.Status.Size += subclusters[i].Size - } + _, totSize := vdb.FindSubclusterForServiceName(v.Vas.Spec.SubclusterServiceName) + v.Vas.Status.Size = totSize if !reflect.DeepEqual(vasOrig, v.Vas.Status) { if err := v.VRec.Client.Status().Update(ctx, v.Vas); err != nil { diff --git a/pkg/controllers/vdbverify_reconcile.go b/pkg/controllers/vdbverify_reconcile.go new file mode 100644 index 000000000..32a66348f --- /dev/null +++ b/pkg/controllers/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. +*/ + +package controllers + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + 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) 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/verticaautoscaler_controller.go b/pkg/controllers/verticaautoscaler_controller.go index 69a913c6a..836a492c8 100644 --- a/pkg/controllers/verticaautoscaler_controller.go +++ b/pkg/controllers/verticaautoscaler_controller.go @@ -68,9 +68,14 @@ func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Re // The actors that will be applied, in sequence, to reconcile a vas. actors := []ReconcileActor{ + // Sanity check to make sure the VerticaDB referenced in vas actually exists. + MakeVDBVerifyReconciler(r, vas), // If scaling granularity is Pod, this will resize existing subclusters // depending on the targetSize. MakeSubclusterResizeReconciler(r, vas), + // If scaling granulariyt is Subcluster, this will create or delete + // entire subcluster to match the targetSize. + MakeSubclusterScaleReconciler(r, vas), // Update the status portion of the VerticaAutoscaler MakeVASStatusReconciler(r, vas), } From 48bb4b02601169c89f0f24169f63c289d038eb8f Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Thu, 24 Mar 2022 15:54:39 -0300 Subject: [PATCH 07/27] Rename autoscale-sanity to autoscale-by-pod --- .../05-create-communal-creds.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/10-assert.yaml | 0 .../10-deploy-operator.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/15-assert.yaml | 0 .../e2e/{autoscale-sanity => autoscale-by-pod}/15-setup-vdb.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/20-assert.yaml | 0 .../20-wait-for-createdb.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/25-assert.yaml | 0 .../25-create-autoscale-CR.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/30-assert.yaml | 0 .../{autoscale-sanity => autoscale-by-pod}/30-scale-sc1-to-3.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/35-assert.yaml | 0 .../{autoscale-sanity => autoscale-by-pod}/35-scale-sc1-to-2.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/40-assert.yaml | 0 .../{autoscale-sanity => autoscale-by-pod}/40-scale-sc2-to-3.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/45-assert.yaml | 0 .../{autoscale-sanity => autoscale-by-pod}/45-scale-sc2-to-1.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/90-errors.yaml | 0 .../90-uninstall-operator.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/95-assert.yaml | 0 .../e2e/{autoscale-sanity => autoscale-by-pod}/95-delete-crd.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/95-errors.yaml | 0 tests/e2e/{autoscale-sanity => autoscale-by-pod}/README.txt | 0 .../setup-vdb/base/kustomization.yaml | 0 .../setup-vdb/base/setup-vdb.yaml | 0 25 files changed, 0 insertions(+), 0 deletions(-) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/05-create-communal-creds.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/10-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/10-deploy-operator.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/15-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/15-setup-vdb.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/20-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/20-wait-for-createdb.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/25-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/25-create-autoscale-CR.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/30-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/30-scale-sc1-to-3.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/35-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/35-scale-sc1-to-2.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/40-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/40-scale-sc2-to-3.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/45-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/45-scale-sc2-to-1.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/90-errors.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/90-uninstall-operator.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/95-assert.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/95-delete-crd.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/95-errors.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/README.txt (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/setup-vdb/base/kustomization.yaml (100%) rename tests/e2e/{autoscale-sanity => autoscale-by-pod}/setup-vdb/base/setup-vdb.yaml (100%) diff --git a/tests/e2e/autoscale-sanity/05-create-communal-creds.yaml b/tests/e2e/autoscale-by-pod/05-create-communal-creds.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/05-create-communal-creds.yaml rename to tests/e2e/autoscale-by-pod/05-create-communal-creds.yaml diff --git a/tests/e2e/autoscale-sanity/10-assert.yaml b/tests/e2e/autoscale-by-pod/10-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/10-assert.yaml rename to tests/e2e/autoscale-by-pod/10-assert.yaml diff --git a/tests/e2e/autoscale-sanity/10-deploy-operator.yaml b/tests/e2e/autoscale-by-pod/10-deploy-operator.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/10-deploy-operator.yaml rename to tests/e2e/autoscale-by-pod/10-deploy-operator.yaml diff --git a/tests/e2e/autoscale-sanity/15-assert.yaml b/tests/e2e/autoscale-by-pod/15-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/15-assert.yaml rename to tests/e2e/autoscale-by-pod/15-assert.yaml diff --git a/tests/e2e/autoscale-sanity/15-setup-vdb.yaml b/tests/e2e/autoscale-by-pod/15-setup-vdb.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/15-setup-vdb.yaml rename to tests/e2e/autoscale-by-pod/15-setup-vdb.yaml diff --git a/tests/e2e/autoscale-sanity/20-assert.yaml b/tests/e2e/autoscale-by-pod/20-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/20-assert.yaml rename to tests/e2e/autoscale-by-pod/20-assert.yaml diff --git a/tests/e2e/autoscale-sanity/20-wait-for-createdb.yaml b/tests/e2e/autoscale-by-pod/20-wait-for-createdb.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/20-wait-for-createdb.yaml rename to tests/e2e/autoscale-by-pod/20-wait-for-createdb.yaml diff --git a/tests/e2e/autoscale-sanity/25-assert.yaml b/tests/e2e/autoscale-by-pod/25-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/25-assert.yaml rename to tests/e2e/autoscale-by-pod/25-assert.yaml diff --git a/tests/e2e/autoscale-sanity/25-create-autoscale-CR.yaml b/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/25-create-autoscale-CR.yaml rename to tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml diff --git a/tests/e2e/autoscale-sanity/30-assert.yaml b/tests/e2e/autoscale-by-pod/30-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/30-assert.yaml rename to tests/e2e/autoscale-by-pod/30-assert.yaml diff --git a/tests/e2e/autoscale-sanity/30-scale-sc1-to-3.yaml b/tests/e2e/autoscale-by-pod/30-scale-sc1-to-3.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/30-scale-sc1-to-3.yaml rename to tests/e2e/autoscale-by-pod/30-scale-sc1-to-3.yaml diff --git a/tests/e2e/autoscale-sanity/35-assert.yaml b/tests/e2e/autoscale-by-pod/35-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/35-assert.yaml rename to tests/e2e/autoscale-by-pod/35-assert.yaml diff --git a/tests/e2e/autoscale-sanity/35-scale-sc1-to-2.yaml b/tests/e2e/autoscale-by-pod/35-scale-sc1-to-2.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/35-scale-sc1-to-2.yaml rename to tests/e2e/autoscale-by-pod/35-scale-sc1-to-2.yaml diff --git a/tests/e2e/autoscale-sanity/40-assert.yaml b/tests/e2e/autoscale-by-pod/40-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/40-assert.yaml rename to tests/e2e/autoscale-by-pod/40-assert.yaml diff --git a/tests/e2e/autoscale-sanity/40-scale-sc2-to-3.yaml b/tests/e2e/autoscale-by-pod/40-scale-sc2-to-3.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/40-scale-sc2-to-3.yaml rename to tests/e2e/autoscale-by-pod/40-scale-sc2-to-3.yaml diff --git a/tests/e2e/autoscale-sanity/45-assert.yaml b/tests/e2e/autoscale-by-pod/45-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/45-assert.yaml rename to tests/e2e/autoscale-by-pod/45-assert.yaml diff --git a/tests/e2e/autoscale-sanity/45-scale-sc2-to-1.yaml b/tests/e2e/autoscale-by-pod/45-scale-sc2-to-1.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/45-scale-sc2-to-1.yaml rename to tests/e2e/autoscale-by-pod/45-scale-sc2-to-1.yaml diff --git a/tests/e2e/autoscale-sanity/90-errors.yaml b/tests/e2e/autoscale-by-pod/90-errors.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/90-errors.yaml rename to tests/e2e/autoscale-by-pod/90-errors.yaml diff --git a/tests/e2e/autoscale-sanity/90-uninstall-operator.yaml b/tests/e2e/autoscale-by-pod/90-uninstall-operator.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/90-uninstall-operator.yaml rename to tests/e2e/autoscale-by-pod/90-uninstall-operator.yaml diff --git a/tests/e2e/autoscale-sanity/95-assert.yaml b/tests/e2e/autoscale-by-pod/95-assert.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/95-assert.yaml rename to tests/e2e/autoscale-by-pod/95-assert.yaml diff --git a/tests/e2e/autoscale-sanity/95-delete-crd.yaml b/tests/e2e/autoscale-by-pod/95-delete-crd.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/95-delete-crd.yaml rename to tests/e2e/autoscale-by-pod/95-delete-crd.yaml diff --git a/tests/e2e/autoscale-sanity/95-errors.yaml b/tests/e2e/autoscale-by-pod/95-errors.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/95-errors.yaml rename to tests/e2e/autoscale-by-pod/95-errors.yaml diff --git a/tests/e2e/autoscale-sanity/README.txt b/tests/e2e/autoscale-by-pod/README.txt similarity index 100% rename from tests/e2e/autoscale-sanity/README.txt rename to tests/e2e/autoscale-by-pod/README.txt diff --git a/tests/e2e/autoscale-sanity/setup-vdb/base/kustomization.yaml b/tests/e2e/autoscale-by-pod/setup-vdb/base/kustomization.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/setup-vdb/base/kustomization.yaml rename to tests/e2e/autoscale-by-pod/setup-vdb/base/kustomization.yaml diff --git a/tests/e2e/autoscale-sanity/setup-vdb/base/setup-vdb.yaml b/tests/e2e/autoscale-by-pod/setup-vdb/base/setup-vdb.yaml similarity index 100% rename from tests/e2e/autoscale-sanity/setup-vdb/base/setup-vdb.yaml rename to tests/e2e/autoscale-by-pod/setup-vdb/base/setup-vdb.yaml From 0f1f015a907e085b01efd1e608a164b4c7314c3e Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 25 Mar 2022 10:09:49 -0300 Subject: [PATCH 08/27] e2e test --- go.mod | 1 - .../dbremovenode_reconcile_test.go | 1 + pkg/controllers/subclusterscale_reconcile.go | 9 ++--- .../subclusterscale_reconcile_test.go | 4 +- tests/e2e/autoscale-by-pod/15-assert.yaml | 2 +- tests/e2e/autoscale-by-pod/20-assert.yaml | 6 +-- tests/e2e/autoscale-by-pod/25-assert.yaml | 4 +- .../25-create-autoscale-CR.yaml | 8 ++-- tests/e2e/autoscale-by-pod/30-assert.yaml | 4 +- .../autoscale-by-pod/30-scale-sc1-to-3.yaml | 2 +- tests/e2e/autoscale-by-pod/35-assert.yaml | 4 +- .../autoscale-by-pod/35-scale-sc1-to-2.yaml | 2 +- tests/e2e/autoscale-by-pod/40-assert.yaml | 4 +- .../autoscale-by-pod/40-scale-sc2-to-3.yaml | 2 +- tests/e2e/autoscale-by-pod/45-assert.yaml | 4 +- .../autoscale-by-pod/45-scale-sc2-to-1.yaml | 2 +- .../setup-vdb/base/setup-vdb.yaml | 2 +- .../05-create-communal-creds.yaml | 17 +++++++++ .../autoscale-by-subcluster/10-assert.yaml | 20 ++++++++++ .../10-deploy-operator.yaml | 17 +++++++++ .../autoscale-by-subcluster/15-assert.yaml | 19 ++++++++++ .../autoscale-by-subcluster/15-setup-vdb.yaml | 17 +++++++++ .../autoscale-by-subcluster/20-assert.yaml | 30 +++++++++++++++ .../20-wait-for-createdb.yaml | 1 + .../autoscale-by-subcluster/25-assert.yaml | 20 ++++++++++ .../25-create-autoscale-CR.yaml | 26 +++++++++++++ .../autoscale-by-subcluster/30-assert.yaml | 35 ++++++++++++++++++ .../autoscale-by-subcluster/30-errors.yaml | 17 +++++++++ .../30-scale-2-new-subclusters.yaml | 17 +++++++++ .../autoscale-by-subcluster/35-assert.yaml | 33 +++++++++++++++++ .../35-scale-1-new-subclusters.yaml | 17 +++++++++ .../autoscale-by-subcluster/40-assert.yaml | 19 ++++++++++ .../40-manually-add-new-subcluster.yaml | 37 +++++++++++++++++++ .../autoscale-by-subcluster/45-assert.yaml | 33 +++++++++++++++++ .../autoscale-by-subcluster/45-errors.yaml | 22 +++++++++++ .../45-remove-scaled-subclusters.yaml | 17 +++++++++ .../autoscale-by-subcluster/90-errors.yaml | 18 +++++++++ .../90-uninstall-operator.yaml | 17 +++++++++ .../autoscale-by-subcluster/95-assert.yaml | 19 ++++++++++ .../95-delete-crd.yaml | 24 ++++++++++++ .../autoscale-by-subcluster/95-errors.yaml | 24 ++++++++++++ tests/e2e/autoscale-by-subcluster/README.txt | 2 + .../setup-vdb/base/kustomization.yaml | 15 ++++++++ .../setup-vdb/base/setup-vdb.yaml | 31 ++++++++++++++++ 44 files changed, 593 insertions(+), 32 deletions(-) create mode 100644 tests/e2e/autoscale-by-subcluster/05-create-communal-creds.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/10-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/10-deploy-operator.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/15-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/15-setup-vdb.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/20-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/20-wait-for-createdb.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/25-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/25-create-autoscale-CR.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/30-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/30-errors.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/30-scale-2-new-subclusters.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/35-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/35-scale-1-new-subclusters.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/40-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/40-manually-add-new-subcluster.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/45-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/45-errors.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/45-remove-scaled-subclusters.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/90-errors.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/90-uninstall-operator.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/95-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/95-delete-crd.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/95-errors.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/README.txt create mode 100644 tests/e2e/autoscale-by-subcluster/setup-vdb/base/kustomization.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/setup-vdb/base/setup-vdb.yaml diff --git a/go.mod b/go.mod index ffb24e3f6..6b10bfb43 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.17 require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/bigkevmcd/go-configparser v0.0.0-20210106142102-909504547ead - github.com/docker/docker v20.10.14+incompatible github.com/ghodss/yaml v1.0.0 github.com/go-logr/logr v1.2.0 github.com/go-logr/zapr v1.2.0 diff --git a/pkg/controllers/dbremovenode_reconcile_test.go b/pkg/controllers/dbremovenode_reconcile_test.go index a4c655b95..694698a02 100644 --- a/pkg/controllers/dbremovenode_reconcile_test.go +++ b/pkg/controllers/dbremovenode_reconcile_test.go @@ -92,6 +92,7 @@ var _ = Describe("dbremovenode_reconcile", func() { )) }) + // SPILLY - add a bool, which controls whether you can scale down to 0. It("should skip remove node and requeue because there aren't any pods running", func() { vdb := vapi.MakeVDB() sc := &vdb.Spec.Subclusters[0] diff --git a/pkg/controllers/subclusterscale_reconcile.go b/pkg/controllers/subclusterscale_reconcile.go index 4d3212132..87418cc0d 100644 --- a/pkg/controllers/subclusterscale_reconcile.go +++ b/pkg/controllers/subclusterscale_reconcile.go @@ -18,9 +18,7 @@ package controllers import ( "context" "fmt" - "strings" - "github.com/docker/docker/pkg/namesgenerator" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" "k8s.io/client-go/util/retry" @@ -121,16 +119,15 @@ func (s *SubclusterScaleReconciler) considerAddingSubclusters(nowPodsNeeded int3 // genNextSubclusterName will come up with a unique name to give a new subcluster func (s *SubclusterScaleReconciler) genNextSubclusterName(scMap map[string]*vapi.Subcluster) string { - name := "" + i := 0 for { // Generate a name by using the docker naming convention. Replacing '_' // with '-' so that the name is valid. - name = fmt.Sprintf("%s-%s", - s.Vas.Spec.Template.Name, - strings.Replace(namesgenerator.GetRandomName(0), "_", "-", -1)) + name := fmt.Sprintf("%s-%d", s.Vas.Spec.Template.Name, i) _, ok := scMap[name] if !ok { return name } + i++ } } diff --git a/pkg/controllers/subclusterscale_reconcile_test.go b/pkg/controllers/subclusterscale_reconcile_test.go index f2aed421d..1b232f9fe 100644 --- a/pkg/controllers/subclusterscale_reconcile_test.go +++ b/pkg/controllers/subclusterscale_reconcile_test.go @@ -53,9 +53,9 @@ var _ = Describe("subclusterscale_reconcile", func() { 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[1].Name).ShouldNot(Equal(fetchVdb.Spec.Subclusters[2])) - Expect(fetchVdb.Spec.Subclusters[1].Name).Should(HavePrefix(vas.Spec.Template.Name)) + Expect(fetchVdb.Spec.Subclusters[2].Name).Should(Equal("blah-1")) }) It("should shrink only when delta from targetPod is an entire subcluster", func() { diff --git a/tests/e2e/autoscale-by-pod/15-assert.yaml b/tests/e2e/autoscale-by-pod/15-assert.yaml index b8ae6635e..836e80b8c 100644 --- a/tests/e2e/autoscale-by-pod/15-assert.yaml +++ b/tests/e2e/autoscale-by-pod/15-assert.yaml @@ -14,6 +14,6 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc1 + name: v-autoscale-by-pod-sc1 status: replicas: 2 diff --git a/tests/e2e/autoscale-by-pod/20-assert.yaml b/tests/e2e/autoscale-by-pod/20-assert.yaml index 3dabcc77d..4bfa0d357 100644 --- a/tests/e2e/autoscale-by-pod/20-assert.yaml +++ b/tests/e2e/autoscale-by-pod/20-assert.yaml @@ -14,7 +14,7 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc1 + name: v-autoscale-by-pod-sc1 status: replicas: 2 readyReplicas: 2 @@ -22,7 +22,7 @@ status: apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc2 + name: v-autoscale-by-pod-sc2 status: replicas: 1 readyReplicas: 1 @@ -30,7 +30,7 @@ status: apiVersion: vertica.com/v1beta1 kind: VerticaDB metadata: - name: v-autoscale-sanity + name: v-autoscale-by-pod status: subclusters: - installCount: 2 diff --git a/tests/e2e/autoscale-by-pod/25-assert.yaml b/tests/e2e/autoscale-by-pod/25-assert.yaml index 3f89f65a8..18852068f 100644 --- a/tests/e2e/autoscale-by-pod/25-assert.yaml +++ b/tests/e2e/autoscale-by-pod/25-assert.yaml @@ -14,7 +14,7 @@ apiVersion: vertica.com/v1beta1 kind: VerticaAutoscaler metadata: - name: v-autoscale-sanity-sc1 + name: v-autoscale-by-pod-sc1 status: selector: vertica.com/subcluster-svc=sc1 size: 2 @@ -22,7 +22,7 @@ status: apiVersion: vertica.com/v1beta1 kind: VerticaAutoscaler metadata: - name: v-autoscale-sanity-sc2 + name: v-autoscale-by-pod-sc2 status: selector: vertica.com/subcluster-svc=sc2 size: 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 index c23524511..924413f75 100644 --- a/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml +++ b/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml @@ -14,17 +14,17 @@ apiVersion: vertica.com/v1beta1 kind: VerticaAutoscaler metadata: - name: v-autoscale-sanity-sc1 + name: v-autoscale-by-pod-sc1 spec: - verticaDBName: v-autoscale-sanity + verticaDBName: v-autoscale-by-pod subclusterServiceName: sc1 scalingGranularity: Pod --- apiVersion: vertica.com/v1beta1 kind: VerticaAutoscaler metadata: - name: v-autoscale-sanity-sc2 + name: v-autoscale-by-pod-sc2 spec: - verticaDBName: v-autoscale-sanity + verticaDBName: v-autoscale-by-pod subclusterServiceName: sc2 scalingGranularity: Pod diff --git a/tests/e2e/autoscale-by-pod/30-assert.yaml b/tests/e2e/autoscale-by-pod/30-assert.yaml index 5a279aa9f..a00ca436c 100644 --- a/tests/e2e/autoscale-by-pod/30-assert.yaml +++ b/tests/e2e/autoscale-by-pod/30-assert.yaml @@ -14,13 +14,13 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc1 + name: v-autoscale-by-pod-sc1 status: replicas: 3 --- apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc2 + name: v-autoscale-by-pod-sc2 status: replicas: 1 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 index f5d047df1..508551b24 100644 --- a/tests/e2e/autoscale-by-pod/30-scale-sc1-to-3.yaml +++ b/tests/e2e/autoscale-by-pod/30-scale-sc1-to-3.yaml @@ -14,4 +14,4 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: - - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-sanity-sc1 --replicas 3 + - 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 index cc1dd0e0f..87114174d 100644 --- a/tests/e2e/autoscale-by-pod/35-assert.yaml +++ b/tests/e2e/autoscale-by-pod/35-assert.yaml @@ -14,13 +14,13 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc1 + name: v-autoscale-by-pod-sc1 status: replicas: 2 --- apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc2 + name: v-autoscale-by-pod-sc2 status: replicas: 1 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 index 3eebc0703..4692bc7b5 100644 --- a/tests/e2e/autoscale-by-pod/35-scale-sc1-to-2.yaml +++ b/tests/e2e/autoscale-by-pod/35-scale-sc1-to-2.yaml @@ -14,4 +14,4 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: - - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-sanity-sc1 --replicas 2 + - 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 index eee94b476..4cbebfb75 100644 --- a/tests/e2e/autoscale-by-pod/40-assert.yaml +++ b/tests/e2e/autoscale-by-pod/40-assert.yaml @@ -14,13 +14,13 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc1 + name: v-autoscale-by-pod-sc1 status: replicas: 2 --- apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc2 + name: v-autoscale-by-pod-sc2 status: replicas: 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 index e191ef92c..1f0ccfc61 100644 --- a/tests/e2e/autoscale-by-pod/40-scale-sc2-to-3.yaml +++ b/tests/e2e/autoscale-by-pod/40-scale-sc2-to-3.yaml @@ -14,4 +14,4 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: - - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-sanity-sc2 --replicas 3 + - 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 index cc1dd0e0f..87114174d 100644 --- a/tests/e2e/autoscale-by-pod/45-assert.yaml +++ b/tests/e2e/autoscale-by-pod/45-assert.yaml @@ -14,13 +14,13 @@ apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc1 + name: v-autoscale-by-pod-sc1 status: replicas: 2 --- apiVersion: apps/v1 kind: StatefulSet metadata: - name: v-autoscale-sanity-sc2 + name: v-autoscale-by-pod-sc2 status: replicas: 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 index e029a5bfc..306b277a4 100644 --- a/tests/e2e/autoscale-by-pod/45-scale-sc2-to-1.yaml +++ b/tests/e2e/autoscale-by-pod/45-scale-sc2-to-1.yaml @@ -14,4 +14,4 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: - - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-sanity-sc2 --replicas 1 + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale-by-pod-sc2 --replicas 1 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 index 0b09489f2..baab2e6b9 100644 --- a/tests/e2e/autoscale-by-pod/setup-vdb/base/setup-vdb.yaml +++ b/tests/e2e/autoscale-by-pod/setup-vdb/base/setup-vdb.yaml @@ -14,7 +14,7 @@ apiVersion: vertica.com/v1beta1 kind: VerticaDB metadata: - name: v-autoscale-sanity + name: v-autoscale-by-pod spec: image: kustomize-vertica-image communal: 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..ef7281702 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/25-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: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + selector: vertica.com/subcluster-svc=as + size: 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..b86394dd7 --- /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 + subclusterServiceName: 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..f99364844 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/30-assert.yaml @@ -0,0 +1,35 @@ +# (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 +spec: + targetSize: 5 +status: + size: 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..66598ed21 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/35-assert.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: 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 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..0c134dd0e --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/45-assert.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: 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 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-scaled-subclusters.yaml b/tests/e2e/autoscale-by-subcluster/45-remove-scaled-subclusters.yaml new file mode 100644 index 000000000..969bf1c71 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/45-remove-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/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: [] From ab311cee563111435ed44bf9259e3a66307f4758 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 25 Mar 2022 15:16:35 -0300 Subject: [PATCH 09/27] Fixes for e2e test --- api/v1beta1/verticaautoscaler_types.go | 15 +++++- .../dbremovenode_reconcile_test.go | 1 - pkg/controllers/subclusterresize_reconcile.go | 5 +- pkg/controllers/subclusterscale_reconcile.go | 15 +++--- .../subclusterscale_reconcile_test.go | 47 +++++++++++++++++++ pkg/controllers/vasstatus_reconciler.go | 1 + .../verticaautoscaler_controller.go | 6 +++ ...emove-all-but-one-scaled-subclusters.yaml} | 0 .../autoscale-by-subcluster/50-assert.yaml | 26 ++++++++++ .../autoscale-by-subcluster/50-errors.yaml | 17 +++++++ .../50-remove-last-scaled-subcluster.yaml | 24 ++++++++++ 11 files changed, 146 insertions(+), 11 deletions(-) rename tests/e2e/autoscale-by-subcluster/{45-remove-scaled-subclusters.yaml => 45-remove-all-but-one-scaled-subclusters.yaml} (100%) create mode 100644 tests/e2e/autoscale-by-subcluster/50-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/50-errors.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/50-remove-last-scaled-subcluster.yaml diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 032e87345..2b50a513d 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -24,7 +24,6 @@ import ( // VerticaAutoscalerSpec defines the desired state of VerticaAutoscaler type VerticaAutoscalerSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file // +operator-sdk:csv:customresourcedefinitions:type=spec @@ -71,6 +70,15 @@ type VerticaAutoscalerSpec struct { // left as the default and modified by the horizontal autoscaler through the // /scale subresource. TargetSize int32 `json:"targetSize,omitempty"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:hidden" + // 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. + AllowScaleToZero bool `json:"allowScaleToZero,omitempty"` } type ScalingGranularityType string @@ -143,3 +151,8 @@ func MakeVAS() *VerticaAutoscaler { }, } } + +// IsScalingAllowed returns true if scaling should proceed based on the targetSize +func (v *VerticaAutoscaler) IsScalingAllowed() bool { + return v.Spec.TargetSize > 0 || v.Spec.AllowScaleToZero +} diff --git a/pkg/controllers/dbremovenode_reconcile_test.go b/pkg/controllers/dbremovenode_reconcile_test.go index 694698a02..a4c655b95 100644 --- a/pkg/controllers/dbremovenode_reconcile_test.go +++ b/pkg/controllers/dbremovenode_reconcile_test.go @@ -92,7 +92,6 @@ var _ = Describe("dbremovenode_reconcile", func() { )) }) - // SPILLY - add a bool, which controls whether you can scale down to 0. It("should skip remove node and requeue because there aren't any pods running", func() { vdb := vapi.MakeVDB() sc := &vdb.Spec.Subclusters[0] diff --git a/pkg/controllers/subclusterresize_reconcile.go b/pkg/controllers/subclusterresize_reconcile.go index db12e1877..92f6921ab 100644 --- a/pkg/controllers/subclusterresize_reconcile.go +++ b/pkg/controllers/subclusterresize_reconcile.go @@ -44,8 +44,9 @@ func (s *SubclusterResizeReconciler) Reconcile(ctx context.Context, req *ctrl.Re return ctrl.Result{}, nil } - if s.Vas.Spec.TargetSize == 0 { - s.VRec.Log.Info("Target not set yet in VerticaAutoscaler") + if !s.Vas.IsScalingAllowed() { + s.VRec.Log.Info("Scaling isn't allowed yet", "targetSize", s.Vas.Spec.TargetSize, + "allowScaleToZero", s.Vas.Spec.AllowScaleToZero) return ctrl.Result{}, nil } diff --git a/pkg/controllers/subclusterscale_reconcile.go b/pkg/controllers/subclusterscale_reconcile.go index 87418cc0d..f744f1f6c 100644 --- a/pkg/controllers/subclusterscale_reconcile.go +++ b/pkg/controllers/subclusterscale_reconcile.go @@ -42,8 +42,9 @@ func (s *SubclusterScaleReconciler) Reconcile(ctx context.Context, req *ctrl.Req return ctrl.Result{}, nil } - if s.Vas.Spec.TargetSize == 0 { - s.VRec.Log.Info("Target not set yet in VerticaAutoscaler") + if !s.Vas.IsScalingAllowed() { + s.VRec.Log.Info("Scaling isn't allowed yet", "targetSize", s.Vas.Spec.TargetSize, + "allowScaleToZero", s.Vas.Spec.AllowScaleToZero) return ctrl.Result{}, nil } @@ -89,9 +90,9 @@ func (s *SubclusterScaleReconciler) considerRemovingSubclusters(podsToRemove int sc := &s.Vdb.Spec.Subclusters[j] if sc.GetServiceName() == s.Vas.Spec.SubclusterServiceName { if podsToRemove > 0 && sc.Size <= podsToRemove { - s.Vdb.Spec.Subclusters = append(s.Vdb.Spec.Subclusters[:j], s.Vdb.Spec.Subclusters[j+1:]...) podsToRemove -= sc.Size - s.VRec.Log.Info("Removing subcluster to VerticaDB", "VerticaDB", s.Vdb.Name, "Subcluster", sc.Name) + 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) @@ -103,15 +104,15 @@ func (s *SubclusterScaleReconciler) considerRemovingSubclusters(podsToRemove int // considerAddingSubclusters will grow the Vdb by adding new subclusters. // Changes are made in-place in s.Vdb -func (s *SubclusterScaleReconciler) considerAddingSubclusters(nowPodsNeeded int32) bool { +func (s *SubclusterScaleReconciler) considerAddingSubclusters(newPodsNeeded int32) bool { origSize := len(s.Vdb.Spec.Subclusters) scMap := s.Vdb.GenSubclusterMap() - for nowPodsNeeded >= s.Vas.Spec.Template.Size { + for newPodsNeeded >= s.Vas.Spec.Template.Size { s.Vdb.Spec.Subclusters = append(s.Vdb.Spec.Subclusters, s.Vas.Spec.Template) sc := &s.Vdb.Spec.Subclusters[len(s.Vdb.Spec.Subclusters)-1] sc.Name = s.genNextSubclusterName(scMap) scMap[sc.Name] = sc - nowPodsNeeded -= sc.Size + newPodsNeeded -= sc.Size s.VRec.Log.Info("Adding subcluster to VerticaDB", "VerticaDB", s.Vdb.Name, "Subcluster", sc.Name, "Size", sc.Size) } return origSize != len(s.Vdb.Spec.Subclusters) diff --git a/pkg/controllers/subclusterscale_reconcile_test.go b/pkg/controllers/subclusterscale_reconcile_test.go index 1b232f9fe..5218c177e 100644 --- a/pkg/controllers/subclusterscale_reconcile_test.go +++ b/pkg/controllers/subclusterscale_reconcile_test.go @@ -109,4 +109,51 @@ var _ = Describe("subclusterscale_reconcile", func() { 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.SubclusterServiceName = 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.AllowScaleToZero = true + 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)) + }) }) diff --git a/pkg/controllers/vasstatus_reconciler.go b/pkg/controllers/vasstatus_reconciler.go index 0e274002e..d3e65d047 100644 --- a/pkg/controllers/vasstatus_reconciler.go +++ b/pkg/controllers/vasstatus_reconciler.go @@ -60,6 +60,7 @@ func (v *VASStatusReconciler) Reconcile(ctx context.Context, req *ctrl.Request) v.Vas.Status.Size = totSize if !reflect.DeepEqual(vasOrig, v.Vas.Status) { + v.VRec.Log.Info("Updating vas status", "status", v.Vas.Status) if err := v.VRec.Client.Status().Update(ctx, v.Vas); err != nil { return err } diff --git a/pkg/controllers/verticaautoscaler_controller.go b/pkg/controllers/verticaautoscaler_controller.go index 836a492c8..b8184debd 100644 --- a/pkg/controllers/verticaautoscaler_controller.go +++ b/pkg/controllers/verticaautoscaler_controller.go @@ -70,6 +70,8 @@ func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Re actors := []ReconcileActor{ // Sanity check to make sure the VerticaDB referenced in vas actually exists. MakeVDBVerifyReconciler(r, vas), + // Update the status portion of the VerticaAutoscaler + MakeVASStatusReconciler(r, vas), // If scaling granularity is Pod, this will resize existing subclusters // depending on the targetSize. MakeSubclusterResizeReconciler(r, vas), @@ -99,5 +101,9 @@ func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Re 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/tests/e2e/autoscale-by-subcluster/45-remove-scaled-subclusters.yaml b/tests/e2e/autoscale-by-subcluster/45-remove-all-but-one-scaled-subclusters.yaml similarity index 100% rename from tests/e2e/autoscale-by-subcluster/45-remove-scaled-subclusters.yaml rename to tests/e2e/autoscale-by-subcluster/45-remove-all-but-one-scaled-subclusters.yaml 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..c0b445066 --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/50-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-pri +status: + replicas: 3 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: v-autoscale-by-subcluster-manual +status: + replicas: 1 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..c48801ddd --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/50-remove-last-scaled-subcluster.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: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +spec: + allowScaleToZero: true +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl scale -n $NAMESPACE verticaautoscaler/v-autoscale --replicas 0 From 30d4d06d2fd4ad3e6892d466c8abcfcde8c87ad8 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 25 Mar 2022 15:40:54 -0300 Subject: [PATCH 10/27] Fix scorecard tests --- api/v1beta1/verticaautoscaler_types.go | 8 +- ...ticadb-operator.clusterserviceversion.yaml | 182 ++++++++++++++++++ .../autoscale-by-subcluster/30-assert.yaml | 9 - 3 files changed, 189 insertions(+), 10 deletions(-) diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 2b50a513d..4d6f22d6e 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -90,7 +90,12 @@ const ( // VerticaAutoscalerStatus defines the observed state of VerticaAutoscaler type VerticaAutoscalerStatus struct { - Size int32 `json:"size"` + // +operator-sdk:csv:customresourcedefinitions:type=status + // The total number of pods across all subclusters that share the service name. + Size int32 `json:"size"` + + // +operator-sdk:csv:customresourcedefinitions:type=status + // The selector used to find all of the pods for this autoscaler. Selector string `json:"selector"` } @@ -100,6 +105,7 @@ type VerticaAutoscalerStatus struct { //+kubebuilder:subresource:scale:specpath=.spec.targetSize,statuspath=.status.size,selectorpath=.status.selector //+kubebuilder:printcolumn:name="Size",type="integer",JSONPath=".status.size" //+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 { diff --git a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml index 25dd403c2..64971bea9 100644 --- a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml @@ -16,6 +16,188 @@ 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: - Pod: Only increase or decrease the size of an existing + subcluster. This cannot be used if more than one subcluster is selected + with subclusterServiceName. - Subcluster: Scaling will be achieved by + creating or deleting entire subclusters. New subclusters are created using + subclusterTemplate as a template. Sizes of existing subclusters will remain + the same.' + displayName: Scaling Granularity + path: scalingGranularity + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:select:Create + - 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 being scaled + together. The name refers to the service name as defined in the subcluster + section of the VerticaDB, which is typically the same name as the subcluster + name. + displayName: Subcluster Service Name + path: subclusterServiceName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:text + - description: This is the total pod count for all subclusters that match the + subclusterServiceName. Changing this value may trigger a change in the + VerticaDB that is associated with this object. This value is generally + left as the default and modified by the horizontal autoscaler through 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. The service + name must match the subclusterServiceName parameter. The name of the subcluster + will be auto generated when the subcluster is added to the VerticaDB. + 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: 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: 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 namespaec as this object. + displayName: Vertica DBName + path: verticaDBName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:text + statusDescriptors: + - description: The selector used to find all of the pods for this autoscaler. + displayName: Selector + path: selector + - description: The total number of pods across all subclusters that share the + service name. + displayName: Size + path: size + version: v1beta1 - description: VerticaDB is the CR that defines a Vertica Eon mode cluster that is managed by the verticadb-operator. displayName: Vertica DB diff --git a/tests/e2e/autoscale-by-subcluster/30-assert.yaml b/tests/e2e/autoscale-by-subcluster/30-assert.yaml index f99364844..f1131b78a 100644 --- a/tests/e2e/autoscale-by-subcluster/30-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/30-assert.yaml @@ -24,12 +24,3 @@ metadata: name: v-autoscale-by-subcluster-as-1 status: replicas: 2 ---- -apiVersion: vertica.com/v1beta1 -kind: VerticaAutoscaler -metadata: - name: v-autoscale -spec: - targetSize: 5 -status: - size: 4 From 20c235204dccdea4946cf556574b055d61f5a76e Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Mon, 28 Mar 2022 11:21:15 -0300 Subject: [PATCH 11/27] Status changes --- api/v1beta1/verticaautoscaler_types.go | 8 +- pkg/controllers/init_db.go | 4 +- pkg/controllers/restart_reconcile.go | 6 +- pkg/controllers/status_reconcile.go | 4 +- pkg/controllers/subclusterresize_reconcile.go | 22 +++- pkg/controllers/subclusterscale_reconcile.go | 22 +++- pkg/controllers/upgrade.go | 8 +- pkg/controllers/vasselector_reconciler.go | 39 ++++++ pkg/controllers/vasstatus_reconciler.go | 72 ---------- .../verticaautoscaler_controller.go | 6 +- pkg/vasstatus/status.go | 76 +++++++++++ pkg/vasstatus/status_test.go | 123 ++++++++++++++++++ pkg/{status => vdbstatus}/status.go | 2 +- pkg/{status => vdbstatus}/status_test.go | 4 +- tests/e2e/autoscale-by-pod/25-assert.yaml | 2 - tests/e2e/autoscale-by-pod/30-assert.yaml | 7 + tests/e2e/autoscale-by-pod/35-assert.yaml | 7 + tests/e2e/autoscale-by-pod/40-assert.yaml | 7 + tests/e2e/autoscale-by-pod/45-assert.yaml | 7 + .../autoscale-by-subcluster/25-assert.yaml | 1 - .../autoscale-by-subcluster/30-assert.yaml | 7 + .../autoscale-by-subcluster/35-assert.yaml | 7 + .../autoscale-by-subcluster/45-assert.yaml | 7 + .../autoscale-by-subcluster/50-assert.yaml | 7 + 24 files changed, 350 insertions(+), 105 deletions(-) create mode 100644 pkg/controllers/vasselector_reconciler.go delete mode 100644 pkg/controllers/vasstatus_reconciler.go create mode 100644 pkg/vasstatus/status.go create mode 100644 pkg/vasstatus/status_test.go rename pkg/{status => vdbstatus}/status.go (99%) rename pkg/{status => vdbstatus}/status_test.go (99%) diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 4d6f22d6e..b5707e80b 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -91,8 +91,8 @@ const ( // VerticaAutoscalerStatus defines the observed state of VerticaAutoscaler type VerticaAutoscalerStatus struct { // +operator-sdk:csv:customresourcedefinitions:type=status - // The total number of pods across all subclusters that share the service name. - Size int32 `json:"size"` + // The total number of times the operator has scaled up/down the VerticaDB. + ScalingCount int `json:"scalingCount"` // +operator-sdk:csv:customresourcedefinitions:type=status // The selector used to find all of the pods for this autoscaler. @@ -102,8 +102,8 @@ type VerticaAutoscalerStatus struct { //+kubebuilder:object:root=true //+kubebuilder:resource:shortName=vas //+kubebuilder:subresource:status -//+kubebuilder:subresource:scale:specpath=.spec.targetSize,statuspath=.status.size,selectorpath=.status.selector -//+kubebuilder:printcolumn:name="Size",type="integer",JSONPath=".status.size" +//+kubebuilder:subresource:scale:specpath=.spec.targetSize,statuspath=.status.scalingCount,selectorpath=.status.selector +//+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,""}} diff --git a/pkg/controllers/init_db.go b/pkg/controllers/init_db.go index 215d0230f..f3406ad6d 100644 --- a/pkg/controllers/init_db.go +++ b/pkg/controllers/init_db.go @@ -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/restart_reconcile.go b/pkg/controllers/restart_reconcile.go index 82e63f216..e8a438b74 100644 --- a/pkg/controllers/restart_reconcile.go +++ b/pkg/controllers/restart_reconcile.go @@ -29,7 +29,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" @@ -70,13 +70,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/status_reconcile.go b/pkg/controllers/status_reconcile.go index 0ca3f9f97..36ec15b94 100644 --- a/pkg/controllers/status_reconcile.go +++ b/pkg/controllers/status_reconcile.go @@ -23,7 +23,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" "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" @@ -75,7 +75,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/subclusterresize_reconcile.go b/pkg/controllers/subclusterresize_reconcile.go index 92f6921ab..6a31d854a 100644 --- a/pkg/controllers/subclusterresize_reconcile.go +++ b/pkg/controllers/subclusterresize_reconcile.go @@ -21,6 +21,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" 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" @@ -50,13 +51,14 @@ func (s *SubclusterResizeReconciler) Reconcile(ctx context.Context, req *ctrl.Re return ctrl.Result{}, nil } - return s.resizeSubcluster(ctx) + 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) (ctrl.Result, error) { +func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { var res ctrl.Result - // Update the VerticaAutoscaler with a retry mechanism for any conflict updates + scalingDone := false + // Update the VerticaDB with a retry mechanism for any conflict updates err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { if r, e := fetchVDB(ctx, s.VRec, s.Vas, s.Vdb); verrors.IsReconcileAborted(r, e) { res = r @@ -95,8 +97,20 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context) (ctrl } } - return s.VRec.Client.Update(ctx, s.Vdb) + 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 { + err = vasstatus.IncrScalingCount(ctx, s.VRec.Client, s.VRec.Log, req) + } + return res, err } diff --git a/pkg/controllers/subclusterscale_reconcile.go b/pkg/controllers/subclusterscale_reconcile.go index f744f1f6c..067b956d0 100644 --- a/pkg/controllers/subclusterscale_reconcile.go +++ b/pkg/controllers/subclusterscale_reconcile.go @@ -21,6 +21,7 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/vasstatus" "k8s.io/client-go/util/retry" ctrl "sigs.k8s.io/controller-runtime" ) @@ -48,14 +49,15 @@ func (s *SubclusterScaleReconciler) Reconcile(ctx context.Context, req *ctrl.Req return ctrl.Result{}, nil } - return s.scaleSubcluster(ctx) + 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) (ctrl.Result, error) { +func (s *SubclusterScaleReconciler) scaleSubcluster(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { var res ctrl.Result - // Update the VerticaAutoscaler with a retry mechanism for any conflict updates + scalingDone := false + // Update the VerticaDB with a retry mechanism for any conflict updates err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { if r, e := fetchVDB(ctx, s.VRec, s.Vas, s.Vdb); verrors.IsReconcileAborted(r, e) { res = r @@ -77,8 +79,20 @@ func (s *SubclusterScaleReconciler) scaleSubcluster(ctx context.Context) (ctrl.R return nil // No change } - return s.VRec.Client.Update(ctx, s.Vdb) + 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 { + err = vasstatus.IncrScalingCount(ctx, s.VRec.Client, s.VRec.Log, req) + } return res, err } diff --git a/pkg/controllers/upgrade.go b/pkg/controllers/upgrade.go index 3c5ffd4fa..c8030e1d7 100644 --- a/pkg/controllers/upgrade.go +++ b/pkg/controllers/upgrade.go @@ -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/vasselector_reconciler.go b/pkg/controllers/vasselector_reconciler.go new file mode 100644 index 000000000..e4a37cfb4 --- /dev/null +++ b/pkg/controllers/vasselector_reconciler.go @@ -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. +*/ + +package controllers + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/vasstatus" + ctrl "sigs.k8s.io/controller-runtime" +) + +type SelectorReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler +} + +// MakeSelectorReconciler will create a SelectorReconciler object and return it +func MakeSelectorReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { + return &SelectorReconciler{VRec: v, Vas: vas} +} + +// Reconcile will handle updating the selector in the status portion of a VerticaAutoscaler +func (v *SelectorReconciler) 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/vasstatus_reconciler.go b/pkg/controllers/vasstatus_reconciler.go deleted file mode 100644 index d3e65d047..000000000 --- a/pkg/controllers/vasstatus_reconciler.go +++ /dev/null @@ -1,72 +0,0 @@ -/* - (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 controllers - -import ( - "context" - "fmt" - "reflect" - - vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" - "github.com/vertica/vertica-kubernetes/pkg/builder" - verrors "github.com/vertica/vertica-kubernetes/pkg/errors" - "k8s.io/client-go/util/retry" - ctrl "sigs.k8s.io/controller-runtime" -) - -type VASStatusReconciler struct { - VRec *VerticaAutoscalerReconciler - Vas *vapi.VerticaAutoscaler -} - -// MakeVASStatusReconciler will create a VASStatusReconciler object and return it -func MakeVASStatusReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { - return &VASStatusReconciler{VRec: v, Vas: vas} -} - -// Reconcile will handle updating the status portion of a VerticaAutoscaler -func (v *VASStatusReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { - var res ctrl.Result - vdb := &vapi.VerticaDB{} - - // Try the status update in a retry loop to handle the case where someone - // update the VerticaAutoscaler since we last fetched. - err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { - if r, e := fetchVDB(ctx, v.VRec, v.Vas, vdb); verrors.IsReconcileAborted(r, e) { - res = r - return e - } - - // 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 := v.Vas.DeepCopy() - - v.Vas.Status.Selector = fmt.Sprintf("%s=%s", builder.SubclusterSvcNameLabel, v.Vas.Spec.SubclusterServiceName) - - _, totSize := vdb.FindSubclusterForServiceName(v.Vas.Spec.SubclusterServiceName) - v.Vas.Status.Size = totSize - - if !reflect.DeepEqual(vasOrig, v.Vas.Status) { - v.VRec.Log.Info("Updating vas status", "status", v.Vas.Status) - if err := v.VRec.Client.Status().Update(ctx, v.Vas); err != nil { - return err - } - } - return nil - }) - - return res, err -} diff --git a/pkg/controllers/verticaautoscaler_controller.go b/pkg/controllers/verticaautoscaler_controller.go index b8184debd..03ed58ac9 100644 --- a/pkg/controllers/verticaautoscaler_controller.go +++ b/pkg/controllers/verticaautoscaler_controller.go @@ -63,7 +63,7 @@ func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Re return ctrl.Result{}, nil } log.Error(err, "failed to get VerticaAutoscaler") - return ctrl.Result{}, nil + return ctrl.Result{}, err } // The actors that will be applied, in sequence, to reconcile a vas. @@ -71,15 +71,13 @@ func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Re // Sanity check to make sure the VerticaDB referenced in vas actually exists. MakeVDBVerifyReconciler(r, vas), // Update the status portion of the VerticaAutoscaler - MakeVASStatusReconciler(r, vas), + MakeSelectorReconciler(r, vas), // If scaling granularity is Pod, this will resize existing subclusters // depending on the targetSize. MakeSubclusterResizeReconciler(r, vas), // If scaling granulariyt is Subcluster, this will create or delete // entire subcluster to match the targetSize. MakeSubclusterScaleReconciler(r, vas), - // Update the status portion of the VerticaAutoscaler - MakeVASStatusReconciler(r, vas), } // Iterate over each actor diff --git a/pkg/vasstatus/status.go b/pkg/vasstatus/status.go new file mode 100644 index 000000000..c60848b48 --- /dev/null +++ b/pkg/vasstatus/status.go @@ -0,0 +1,76 @@ +/* + (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" + "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 = fmt.Sprintf("%s=%s", builder.SubclusterSvcNameLabel, vas.Spec.SubclusterServiceName) + }) +} + +// IncrScalingCount 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 IncrScalingCount(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.ScalingCount++ + }) +} + +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 + }) +} diff --git a/pkg/vasstatus/status_test.go b/pkg/vasstatus/status_test.go new file mode 100644 index 000000000..badab7093 --- /dev/null +++ b/pkg/vasstatus/status_test.go @@ -0,0 +1,123 @@ +/* + (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" + "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" + "github.com/vertica/vertica-kubernetes/pkg/test" + "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.SubclusterServiceName = "my-svc" + test.CreateVAS(ctx, k8sClient, vas) + defer test.DeleteVAS(ctx, k8sClient, vas) + + expectedSelector := fmt.Sprintf("%s=%s", builder.SubclusterSvcNameLabel, vas.Spec.SubclusterServiceName) + + 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(IncrScalingCount(ctx, k8sClient, logger, &req)).Should(Succeed()) + + Expect(k8sClient.Get(ctx, nm, vas)).Should(Succeed()) + Expect(vas.Status.ScalingCount).Should(Equal(1)) + + Expect(IncrScalingCount(ctx, k8sClient, logger, &req)).Should(Succeed()) + + Expect(k8sClient.Get(ctx, nm, vas)).Should(Succeed()) + Expect(vas.Status.ScalingCount).Should(Equal(2)) + }) + + It("should tolerate a non-existent vas", func() { + nm := vapi.MakeVASName() + req := ctrl.Request{NamespacedName: nm} + Expect(IncrScalingCount(ctx, k8sClient, logger, &req)).Should(Succeed()) + Expect(SetSelector(ctx, k8sClient, logger, &req)).Should(Succeed()) + }) +}) 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/tests/e2e/autoscale-by-pod/25-assert.yaml b/tests/e2e/autoscale-by-pod/25-assert.yaml index 18852068f..cb1a30da5 100644 --- a/tests/e2e/autoscale-by-pod/25-assert.yaml +++ b/tests/e2e/autoscale-by-pod/25-assert.yaml @@ -17,7 +17,6 @@ metadata: name: v-autoscale-by-pod-sc1 status: selector: vertica.com/subcluster-svc=sc1 - size: 2 --- apiVersion: vertica.com/v1beta1 kind: VerticaAutoscaler @@ -25,4 +24,3 @@ metadata: name: v-autoscale-by-pod-sc2 status: selector: vertica.com/subcluster-svc=sc2 - size: 1 diff --git a/tests/e2e/autoscale-by-pod/30-assert.yaml b/tests/e2e/autoscale-by-pod/30-assert.yaml index a00ca436c..a0e7dd68c 100644 --- a/tests/e2e/autoscale-by-pod/30-assert.yaml +++ b/tests/e2e/autoscale-by-pod/30-assert.yaml @@ -24,3 +24,10 @@ 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 diff --git a/tests/e2e/autoscale-by-pod/35-assert.yaml b/tests/e2e/autoscale-by-pod/35-assert.yaml index 87114174d..4adfa15ed 100644 --- a/tests/e2e/autoscale-by-pod/35-assert.yaml +++ b/tests/e2e/autoscale-by-pod/35-assert.yaml @@ -24,3 +24,10 @@ 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 diff --git a/tests/e2e/autoscale-by-pod/40-assert.yaml b/tests/e2e/autoscale-by-pod/40-assert.yaml index 4cbebfb75..f625003d7 100644 --- a/tests/e2e/autoscale-by-pod/40-assert.yaml +++ b/tests/e2e/autoscale-by-pod/40-assert.yaml @@ -24,3 +24,10 @@ 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 diff --git a/tests/e2e/autoscale-by-pod/45-assert.yaml b/tests/e2e/autoscale-by-pod/45-assert.yaml index 87114174d..05fa29acd 100644 --- a/tests/e2e/autoscale-by-pod/45-assert.yaml +++ b/tests/e2e/autoscale-by-pod/45-assert.yaml @@ -24,3 +24,10 @@ 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 diff --git a/tests/e2e/autoscale-by-subcluster/25-assert.yaml b/tests/e2e/autoscale-by-subcluster/25-assert.yaml index ef7281702..8fd8d5820 100644 --- a/tests/e2e/autoscale-by-subcluster/25-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/25-assert.yaml @@ -17,4 +17,3 @@ metadata: name: v-autoscale status: selector: vertica.com/subcluster-svc=as - size: 0 diff --git a/tests/e2e/autoscale-by-subcluster/30-assert.yaml b/tests/e2e/autoscale-by-subcluster/30-assert.yaml index f1131b78a..7fc979142 100644 --- a/tests/e2e/autoscale-by-subcluster/30-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/30-assert.yaml @@ -24,3 +24,10 @@ metadata: name: v-autoscale-by-subcluster-as-1 status: replicas: 2 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + scalingCount: 1 diff --git a/tests/e2e/autoscale-by-subcluster/35-assert.yaml b/tests/e2e/autoscale-by-subcluster/35-assert.yaml index 66598ed21..c1cd0bbf1 100644 --- a/tests/e2e/autoscale-by-subcluster/35-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/35-assert.yaml @@ -31,3 +31,10 @@ 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/45-assert.yaml b/tests/e2e/autoscale-by-subcluster/45-assert.yaml index 0c134dd0e..f23060847 100644 --- a/tests/e2e/autoscale-by-subcluster/45-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/45-assert.yaml @@ -31,3 +31,10 @@ metadata: name: v-autoscale-by-subcluster-as-0 status: replicas: 2 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + scalingCount: 3 diff --git a/tests/e2e/autoscale-by-subcluster/50-assert.yaml b/tests/e2e/autoscale-by-subcluster/50-assert.yaml index c0b445066..9691fc2c8 100644 --- a/tests/e2e/autoscale-by-subcluster/50-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/50-assert.yaml @@ -24,3 +24,10 @@ metadata: name: v-autoscale-by-subcluster-manual status: replicas: 1 +--- +apiVersion: vertica.com/v1beta1 +kind: VerticaAutoscaler +metadata: + name: v-autoscale +status: + scalingCount: 4 From 21d6356ea1068e44b0c85fc681670bccd0253ab2 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Tue, 29 Mar 2022 14:44:24 -0300 Subject: [PATCH 12/27] Handling pending pods better Two changes to the restart reconciler for pending pods: - when we do re-ip, lets ignore pods that are pending. The old behaviour would requeue them. They don't have an IP, so there is nothing we can do - don't requeue restart if pods are running. We ended up getting into an infinite loop without anyway to get out. Lets continue on with the reconciler. I was trying to remove the pending pods but I couldn't because it was blocked in the restart. --- api/v1beta1/verticaautoscaler_types.go | 6 +++++- cmd/operator/main.go | 2 ++ pkg/controllers/podfacts.go | 16 ++-------------- pkg/controllers/restart_reconcile.go | 15 ++------------- pkg/controllers/restart_reconciler_test.go | 4 ++-- 5 files changed, 13 insertions(+), 30 deletions(-) diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index b5707e80b..8eb2aab84 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -100,9 +100,13 @@ type VerticaAutoscalerStatus struct { } //+kubebuilder:object:root=true -//+kubebuilder:resource:shortName=vas +//+kubebuilder:resource:categories=all;verticaautoscalers,shortName=vas //+kubebuilder:subresource:status +// SPILLY - statusPath needs to a replica count. It needs to count the number +// of pods in the vdb. We will need to account for missing values. Perhaps we +// always requeue if the count doesn't equal expected. //+kubebuilder:subresource:scale:specpath=.spec.targetSize,statuspath=.status.scalingCount,selectorpath=.status.selector +//+kubebuilder:printcolumn:name="Granularity",type="string",JSONPath=".spec.scalingGranularity" //+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,""}} diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 9d6ad998a..4290d8361 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -221,6 +221,8 @@ func getLogger(logArgs Logging) *zap.Logger { return zap.New(core, opts...) } +// SPILLY - address this +// nolint:funlen func main() { flagArgs := &FlagConfig{} flagArgs.setFlagArgs() diff --git a/pkg/controllers/podfacts.go b/pkg/controllers/podfacts.go index bf61991b4..7f6a29e1f 100644 --- a/pkg/controllers/podfacts.go +++ b/pkg/controllers/podfacts.go @@ -629,8 +629,8 @@ func (p *PodFacts) findInstalledPods() []*PodFact { // An empty list implies there are no pods that match the criteria. func (p *PodFacts) findReIPPods(onlyPodsWithoutDBs bool) []*PodFact { return p.filterPods(func(pod *PodFact) bool { - // Only consider pods that exist and have an installation - if !pod.exists || pod.isInstalled.IsFalse() { + // Only consider running pods that have an installation + if !pod.exists || !pod.isPodRunning || pod.isInstalled.IsFalse() { return false } // If requested don't return pods that have a DB @@ -684,18 +684,6 @@ func (p *PodFacts) countRunningAndInstalled() int { }) } -// countNotRunning returns number of pods that aren't running yet -func (p *PodFacts) countNotRunning() int { - return p.countPods(func(v *PodFact) int { - // We don't count non-running pods that aren't yet managed by the parent - // sts. The sts needs to be created or sized first. - if !v.isPodRunning && v.managedByParent { - return 1 - } - return 0 - }) -} - // countUpPrimaryNodes returns the number of primary nodes that are UP func (p *PodFacts) countUpPrimaryNodes() int { return p.countPods(func(v *PodFact) int { diff --git a/pkg/controllers/restart_reconcile.go b/pkg/controllers/restart_reconcile.go index e8a438b74..6bffc9ec8 100644 --- a/pkg/controllers/restart_reconcile.go +++ b/pkg/controllers/restart_reconcile.go @@ -182,7 +182,7 @@ func (r *RestartReconciler) reconcileNodes(ctx context.Context) (ctrl.Result, er // didn't originate the install. So we will skip the rest if running in // that mode. if r.Vdb.Spec.InitPolicy == vapi.CommunalInitPolicyScheduleOnly { - return ctrl.Result{Requeue: r.shouldRequeueIfPodsNotRunning()}, nil + return ctrl.Result{}, nil } // Find any pods that need to have their IP updated. These are nodes that @@ -198,7 +198,7 @@ func (r *RestartReconciler) reconcileNodes(ctx context.Context) (ctrl.Result, er } } - return ctrl.Result{Requeue: r.shouldRequeueIfPodsNotRunning()}, nil + return ctrl.Result{}, nil } // restartPods restart the down pods using admintools @@ -601,14 +601,3 @@ func (r *RestartReconciler) setATPod(findFunc func() (*PodFact, bool)) bool { } return true } - -// shouldRequeueIfPodsNotRunning is a helper function that will determine -// whether a requeue of the reconcile is necessary because some pods are not yet -// running. -func (r *RestartReconciler) shouldRequeueIfPodsNotRunning() bool { - if r.PFacts.countNotRunning() > 0 { - r.Log.Info("Requeue. Some pods are not yet running.") - return true - } - return false -} diff --git a/pkg/controllers/restart_reconciler_test.go b/pkg/controllers/restart_reconciler_test.go index a35ddd409..ea748c635 100644 --- a/pkg/controllers/restart_reconciler_test.go +++ b/pkg/controllers/restart_reconciler_test.go @@ -500,7 +500,7 @@ var _ = Describe("restart_reconciler", func() { Expect(len(reip)).Should(Equal(1)) }) - It("should requeue if one pod is not running", func() { + It("should not requeue if one pod is not running", func() { vdb := vapi.MakeVDB() vdb.Spec.InitPolicy = vapi.CommunalInitPolicyScheduleOnly sc := &vdb.Spec.Subclusters[0] @@ -519,7 +519,7 @@ var _ = Describe("restart_reconciler", func() { pfacts := createPodFactsWithRestartNeeded(ctx, vdb, sc, fpr, []int32{DownPodIndex}, PodNotReadOnly) r := MakeRestartReconciler(vdbRec, logger, vdb, fpr, pfacts, RestartProcessReadOnly) - Expect(r.Reconcile(ctx, &ctrl.Request{})).Should(Equal(ctrl.Result{Requeue: true})) + Expect(r.Reconcile(ctx, &ctrl.Request{})).Should(Equal(ctrl.Result{})) }) It("should avoid restart_node of read-only nodes when that setting is used", func() { From aa9dd52f2f3a9907f783eb1a0fa880d21bf5fcdd Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Thu, 31 Mar 2022 09:00:31 -0300 Subject: [PATCH 13/27] Add vertica category to kubectl --- api/v1beta1/verticaautoscaler_types.go | 2 +- api/v1beta1/verticadb_types.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 8eb2aab84..1a71d4147 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -100,7 +100,7 @@ type VerticaAutoscalerStatus struct { } //+kubebuilder:object:root=true -//+kubebuilder:resource:categories=all;verticaautoscalers,shortName=vas +//+kubebuilder:resource:categories=all;vertica,shortName=vas //+kubebuilder:subresource:status // SPILLY - statusPath needs to a replica count. It needs to count the number // of pods in the vdb. We will need to account for missing values. Perhaps we diff --git a/api/v1beta1/verticadb_types.go b/api/v1beta1/verticadb_types.go index c239ae581..958854e60 100644 --- a/api/v1beta1/verticadb_types.go +++ b/api/v1beta1/verticadb_types.go @@ -797,7 +797,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" From bc07fcde9ab1c2dce3051d4ae89d0098d01fd5d3 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Thu, 31 Mar 2022 09:42:25 -0300 Subject: [PATCH 14/27] Expand label selector --- pkg/builder/labels_annotations.go | 11 ++++++----- pkg/vasstatus/status.go | 14 +++++++++++++- pkg/vasstatus/status_test.go | 4 +--- tests/e2e/autoscale-by-pod/25-assert.yaml | 4 ++-- tests/e2e/autoscale-by-subcluster/25-assert.yaml | 2 +- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/pkg/builder/labels_annotations.go b/pkg/builder/labels_annotations.go index d77aab684..522926b71 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.3.1" // The version number of the operator @@ -71,11 +72,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/vasstatus/status.go b/pkg/vasstatus/status.go index c60848b48..8c9ac89f7 100644 --- a/pkg/vasstatus/status.go +++ b/pkg/vasstatus/status.go @@ -31,7 +31,7 @@ import ( 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 = fmt.Sprintf("%s=%s", builder.SubclusterSvcNameLabel, vas.Spec.SubclusterServiceName) + vas.Status.Selector = getLabelSelector(vas) }) } @@ -74,3 +74,15 @@ func vasStatusUpdater(ctx context.Context, c client.Client, log logr.Logger, 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.SubclusterServiceName, + builder.VDBInstanceLabel, + vas.Spec.VerticaDBName, + builder.ManagedByLabel, + builder.OperatorName, + ) +} diff --git a/pkg/vasstatus/status_test.go b/pkg/vasstatus/status_test.go index badab7093..1c4d047ba 100644 --- a/pkg/vasstatus/status_test.go +++ b/pkg/vasstatus/status_test.go @@ -17,7 +17,6 @@ package vasstatus import ( "context" - "fmt" "path/filepath" "testing" @@ -25,7 +24,6 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" - "github.com/vertica/vertica-kubernetes/pkg/builder" "github.com/vertica/vertica-kubernetes/pkg/test" "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" @@ -85,7 +83,7 @@ var _ = Describe("status", func() { test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) - expectedSelector := fmt.Sprintf("%s=%s", builder.SubclusterSvcNameLabel, vas.Spec.SubclusterServiceName) + expectedSelector := getLabelSelector(vas) nm := vapi.MakeVASName() req := ctrl.Request{NamespacedName: nm} diff --git a/tests/e2e/autoscale-by-pod/25-assert.yaml b/tests/e2e/autoscale-by-pod/25-assert.yaml index cb1a30da5..f0a5b3f06 100644 --- a/tests/e2e/autoscale-by-pod/25-assert.yaml +++ b/tests/e2e/autoscale-by-pod/25-assert.yaml @@ -16,11 +16,11 @@ kind: VerticaAutoscaler metadata: name: v-autoscale-by-pod-sc1 status: - selector: vertica.com/subcluster-svc=sc1 + selector: vertica.com/subcluster-svc=sc1,app.kubernetes.io/instance=v-autoscale-by-pod,app.kubernetes.io/managed-by=verticadb-operator --- apiVersion: vertica.com/v1beta1 kind: VerticaAutoscaler metadata: name: v-autoscale-by-pod-sc2 status: - selector: vertica.com/subcluster-svc=sc2 + selector: vertica.com/subcluster-svc=sc2,app.kubernetes.io/instance=v-autoscale-by-pod,app.kubernetes.io/managed-by=verticadb-operator diff --git a/tests/e2e/autoscale-by-subcluster/25-assert.yaml b/tests/e2e/autoscale-by-subcluster/25-assert.yaml index 8fd8d5820..369817eb4 100644 --- a/tests/e2e/autoscale-by-subcluster/25-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/25-assert.yaml @@ -16,4 +16,4 @@ kind: VerticaAutoscaler metadata: name: v-autoscale status: - selector: vertica.com/subcluster-svc=as + selector: vertica.com/subcluster-svc=as,app.kubernetes.io/instance=v-autoscale-by-subcluster,app.kubernetes.io/managed-by=verticadb-operator From 584b4fc0bfd3ea79bd3f5c15ece2ab6a92760939 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Thu, 31 Mar 2022 15:57:20 -0300 Subject: [PATCH 15/27] Add webhook --- PROJECT | 3 + api/v1beta1/groupversion_info.go | 10 +- api/v1beta1/verticaautoscaler_types.go | 26 ++-- api/v1beta1/verticaautoscaler_webhook.go | 123 ++++++++++++++++++ api/v1beta1/verticaautoscaler_webhook_test.go | 52 ++++++++ api/v1beta1/verticadb_types.go | 7 +- api/v1beta1/verticadb_webhook.go | 4 +- api/v1beta1/webhook_suite_test.go | 3 + cmd/operator/main.go | 26 ++-- config/crd/kustomization.yaml | 4 +- .../webhook_in_verticaautoscalers.yaml | 10 +- ...ticadb-operator.clusterserviceversion.yaml | 44 +++++-- config/webhook/manifests.yaml | 50 +++++++ go.sum | 2 - pkg/vdbgen/vdb.go | 2 +- tests/e2e/vas-webhook/05-assert.yaml | 20 +++ tests/e2e/vas-webhook/05-deploy-operator.yaml | 17 +++ tests/e2e/vas-webhook/10-assert.yaml | 22 ++++ ...0-create-vas-with-default-serviceName.yaml | 19 +++ tests/e2e/vas-webhook/15-assert.yaml | 22 ++++ .../15-invalid-scalingGranularity.yaml | 18 +++ tests/e2e/vas-webhook/20-assert.yaml | 22 ++++ .../20-change-serviceName-invalid.yaml | 18 +++ tests/e2e/vas-webhook/25-assert.yaml | 22 ++++ .../25-change-serviceName-valid.yaml | 17 +++ tests/e2e/vas-webhook/95-errors.yaml | 18 +++ .../vas-webhook/95-uninstall-operator.yaml | 17 +++ tests/e2e/vas-webhook/99-delete-vas.yaml | 18 +++ tests/e2e/vas-webhook/99-errors.yaml | 15 +++ 29 files changed, 578 insertions(+), 53 deletions(-) create mode 100644 api/v1beta1/verticaautoscaler_webhook.go create mode 100644 api/v1beta1/verticaautoscaler_webhook_test.go create mode 100644 tests/e2e/vas-webhook/05-assert.yaml create mode 100644 tests/e2e/vas-webhook/05-deploy-operator.yaml create mode 100644 tests/e2e/vas-webhook/10-assert.yaml create mode 100644 tests/e2e/vas-webhook/10-create-vas-with-default-serviceName.yaml create mode 100644 tests/e2e/vas-webhook/15-assert.yaml create mode 100644 tests/e2e/vas-webhook/15-invalid-scalingGranularity.yaml create mode 100644 tests/e2e/vas-webhook/20-assert.yaml create mode 100644 tests/e2e/vas-webhook/20-change-serviceName-invalid.yaml create mode 100644 tests/e2e/vas-webhook/25-assert.yaml create mode 100644 tests/e2e/vas-webhook/25-change-serviceName-valid.yaml create mode 100644 tests/e2e/vas-webhook/95-errors.yaml create mode 100644 tests/e2e/vas-webhook/95-uninstall-operator.yaml create mode 100644 tests/e2e/vas-webhook/99-delete-vas.yaml create mode 100644 tests/e2e/vas-webhook/99-errors.yaml diff --git a/PROJECT b/PROJECT index 5c2642f2e..e898c1f42 100644 --- a/PROJECT +++ b/PROJECT @@ -27,4 +27,7 @@ resources: 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/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 1a71d4147..966bfaf63 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -29,11 +29,11 @@ type VerticaAutoscalerSpec struct { // +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 namespaec as this object. + // VerticaDB object must exist in the same namespace as this object. VerticaDBName string `json:"verticaDBName,omitempty"` // +operator-sdk:csv:customresourcedefinitions:type=spec - // +kubebuilder:default:="Pod" + // +kubebuilder:default:="Subcluster" // +kubebuilder:validation:Optional // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:select:Create","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: @@ -47,18 +47,24 @@ type VerticaAutoscalerSpec struct { // +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 being scaled together. + // This acts as a selector for the subclusters that are being scaled together. // The name refers to the service name as defined in the subcluster section - // of the VerticaDB, which is typically the same name as the subcluster name. + // of the VerticaDB, which if omitted is the same name as the subcluster name. SubclusterServiceName string `json:"subclusterServiceName"` + // SPILLY - add logic to pick an existing subcluster as a template + // SPILLY - add logic to handle an empty name in the template + // +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. The service name - // must match the subclusterServiceName parameter. The name of the - // subcluster will be auto generated when the subcluster is added to the - // VerticaDB. + // 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 subclusterServiceName + // 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 @@ -145,8 +151,8 @@ func MakeVAS() *VerticaAutoscaler { vdbNm := MakeVDBName() return &VerticaAutoscaler{ TypeMeta: metav1.TypeMeta{ - APIVersion: "vertica.com/v1beta1", - Kind: "VerticaAutoscaler", + APIVersion: GroupVersion.String(), + Kind: VerticaAutoscalerKind, }, ObjectMeta: metav1.ObjectMeta{ Name: vasNm.Name, diff --git a/api/v1beta1/verticaautoscaler_webhook.go b/api/v1beta1/verticaautoscaler_webhook.go new file mode 100644 index 000000000..6c07a538c --- /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.SubclusterServiceName + } +} + +//+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.subclusterServiceName. 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.SubclusterServiceName { + err := field.Invalid(pathPrefix.Child("serviceName"), + v.Spec.Template.ServiceName, + "The serviceName in the subcluster template must match spec.subclusterServiceName") + 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..8d8c4e5b8 --- /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.SubclusterServiceName)) + }) + + 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.SubclusterServiceName + Expect(vas.ValidateUpdate(MakeVAS())).Should(Succeed()) + }) +}) diff --git a/api/v1beta1/verticadb_types.go b/api/v1beta1/verticadb_types.go index 958854e60..1367dc264 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 @@ -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, diff --git a/api/v1beta1/verticadb_webhook.go b/api/v1beta1/verticadb_webhook.go index 39f6f0878..97480d06b 100644 --- a/api/v1beta1/verticadb_webhook.go +++ b/api/v1beta1/verticadb_webhook.go @@ -134,7 +134,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 +145,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 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 4290d8361..ca3260582 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -286,6 +286,17 @@ func main() { os.Exit(1) } + if err = (&controllers.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) + } + //+kubebuilder:scaffold:builder + 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 @@ -300,19 +311,12 @@ func main() { 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) + } } - if err = (&controllers.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) - } - //+kubebuilder:scaffold:builder - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "unable to set up health check") os.Exit(1) diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 4c08ea1f1..ba4de1b61 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -10,13 +10,13 @@ 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 + - 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_verticaautoscalers.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/webhook_in_verticaautoscalers.yaml b/config/crd/patches/webhook_in_verticaautoscalers.yaml index 44943ce03..0f463c965 100644 --- a/config/crd/patches/webhook_in_verticaautoscalers.yaml +++ b/config/crd/patches/webhook_in_verticaautoscalers.yaml @@ -5,12 +5,4 @@ metadata: name: verticaautoscalers.vertica.com spec: conversion: - strategy: Webhook - webhook: - clientConfig: - service: - namespace: system - name: webhook-service - path: /convert - conversionReviewVersions: - - v1 + strategy: None diff --git a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml index 64971bea9..3ef42acde 100644 --- a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml @@ -46,9 +46,9 @@ spec: - urn:alm:descriptor:com.tectonic.ui:select:Create - 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 being scaled + - description: This acts as a selector for the subclusters that are being scaled together. The name refers to the service name as defined in the subcluster - section of the VerticaDB, which is typically the same name as the subcluster + section of the VerticaDB, which if omitted is the same name as the subcluster name. displayName: Subcluster Service Name path: subclusterServiceName @@ -64,9 +64,12 @@ spec: 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. The service - name must match the subclusterServiceName parameter. The name of the subcluster - will be auto generated when the subcluster is added to the VerticaDB. + 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 subclusterServiceName 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 @@ -116,6 +119,10 @@ spec: 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 @@ -145,6 +152,9 @@ spec: 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 @@ -184,19 +194,19 @@ spec: 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 namespaec as this object. + 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: 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 - - description: The total number of pods across all subclusters that share the - service name. - displayName: Size - path: size version: v1beta1 - description: VerticaDB is the CR that defines a Vertica Eon mode cluster that is managed by the verticadb-operator. @@ -541,6 +551,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 @@ -570,6 +584,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 @@ -682,6 +699,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 @@ -711,6 +732,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/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/go.sum b/go.sum index 52628ad24..5706c14a3 100644 --- a/go.sum +++ b/go.sum @@ -121,8 +121,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/docker v20.10.14+incompatible h1:+T9/PRYWNDo5SZl5qS1r9Mo/0Q8AwxKKPtu9S1yxM0w= -github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= 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/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..6d42be6c7 --- /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: + subclusterServiceName: 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..771221223 --- /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: + subclusterServiceName: 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..6d42be6c7 --- /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: + subclusterServiceName: 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..6d42be6c7 --- /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: + subclusterServiceName: 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..d56701dd4 --- /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.subclusterServiceName="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..1a955b87f --- /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: + subclusterServiceName: 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..ce63c932b --- /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.subclusterServiceName="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 From 0e8c2c6799cca0a85c6f85fed1a4d8fd6d624850 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 1 Apr 2022 11:34:08 -0300 Subject: [PATCH 16/27] Add ability to use existing subcluster as template --- api/v1beta1/verticaautoscaler_types.go | 8 ++- pkg/controllers/subclusterscale_reconcile.go | 61 +++++++++++++++--- .../subclusterscale_reconcile_test.go | 62 +++++++++++++++++++ pkg/events/event.go | 1 + .../55-remove-template-from-vas.yaml | 26 ++++++++ .../autoscale-by-subcluster/60-assert.yaml | 19 ++++++ .../60-scale-new-subcluster.yaml | 17 +++++ 7 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 tests/e2e/autoscale-by-subcluster/55-remove-template-from-vas.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/60-assert.yaml create mode 100644 tests/e2e/autoscale-by-subcluster/60-scale-new-subcluster.yaml diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 966bfaf63..8f2e9cc6b 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -52,9 +52,6 @@ type VerticaAutoscalerSpec struct { // of the VerticaDB, which if omitted is the same name as the subcluster name. SubclusterServiceName string `json:"subclusterServiceName"` - // SPILLY - add logic to pick an existing subcluster as a template - // SPILLY - add logic to handle an empty name in the template - // +operator-sdk:csv:customresourcedefinitions:type=spec // +kubebuilder:validation:Optional // When the scaling granularity is Subcluster, this field defines a template @@ -172,3 +169,8 @@ func MakeVAS() *VerticaAutoscaler { func (v *VerticaAutoscaler) IsScalingAllowed() bool { return v.Spec.TargetSize > 0 || v.Spec.AllowScaleToZero } + +// 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/pkg/controllers/subclusterscale_reconcile.go b/pkg/controllers/subclusterscale_reconcile.go index 067b956d0..ff631dde8 100644 --- a/pkg/controllers/subclusterscale_reconcile.go +++ b/pkg/controllers/subclusterscale_reconcile.go @@ -21,7 +21,9 @@ import ( vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" 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" ) @@ -121,24 +123,29 @@ func (s *SubclusterScaleReconciler) considerRemovingSubclusters(podsToRemove int func (s *SubclusterScaleReconciler) considerAddingSubclusters(newPodsNeeded int32) bool { origSize := len(s.Vdb.Spec.Subclusters) scMap := s.Vdb.GenSubclusterMap() - for newPodsNeeded >= s.Vas.Spec.Template.Size { - s.Vdb.Spec.Subclusters = append(s.Vdb.Spec.Subclusters, s.Vas.Spec.Template) - sc := &s.Vdb.Spec.Subclusters[len(s.Vdb.Spec.Subclusters)-1] - sc.Name = s.genNextSubclusterName(scMap) - scMap[sc.Name] = sc - newPodsNeeded -= sc.Size - s.VRec.Log.Info("Adding subcluster to VerticaDB", "VerticaDB", s.Vdb.Name, "Subcluster", sc.Name, "Size", sc.Size) + 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 origSize != 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 { - // Generate a name by using the docker naming convention. Replacing '_' - // with '-' so that the name is valid. - name := fmt.Sprintf("%s-%d", s.Vas.Spec.Template.Name, i) + name := fmt.Sprintf("%s-%d", baseName, i) _, ok := scMap[name] if !ok { return name @@ -146,3 +153,37 @@ func (s *SubclusterScaleReconciler) genNextSubclusterName(scMap map[string]*vapi 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.SubclusterServiceName) + 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.SubclusterServiceName + newSc.Name = s.genNextSubclusterName(scMap) + return newSc, true +} diff --git a/pkg/controllers/subclusterscale_reconcile_test.go b/pkg/controllers/subclusterscale_reconcile_test.go index 5218c177e..6367e35c2 100644 --- a/pkg/controllers/subclusterscale_reconcile_test.go +++ b/pkg/controllers/subclusterscale_reconcile_test.go @@ -17,6 +17,7 @@ package controllers import ( "context" + "fmt" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -156,4 +157,65 @@ var _ = Describe("subclusterscale_reconcile", func() { 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.SubclusterServiceName = 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.SubclusterServiceName = "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/events/event.go b/pkg/events/event.go index 77e2e6392..696d8bec5 100644 --- a/pkg/events/event.go +++ b/pkg/events/event.go @@ -72,4 +72,5 @@ const ( const ( SubclusterServiceNameNotFound = "SubclusterServiceNameNotFound" VerticaDBNotFound = "VerticaDBNotFound" + NoSubclusterTemplate = "NoSubclusterTemplate" ) 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..2cc7d17ee --- /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 + subclusterServiceName: 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..56888bb0b --- /dev/null +++ b/tests/e2e/autoscale-by-subcluster/60-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-v-autoscale-0 +status: + replicas: 3 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 From 8a80d11737cde301e8146286ad55c69e49c995f1 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 1 Apr 2022 16:01:34 -0300 Subject: [PATCH 17/27] Add currentSize and init targetSize --- api/v1beta1/verticaautoscaler_types.go | 53 ++++++++++-- pkg/controllers/subclusterresize_reconcile.go | 3 +- pkg/controllers/subclusterscale_reconcile.go | 7 +- .../subclusterscale_reconcile_test.go | 1 + .../targetsizeinitializer_reconcile.go | 83 +++++++++++++++++++ .../targetsizeinitializer_reconcile_test.go | 58 +++++++++++++ pkg/controllers/vasstatus_reconciler.go | 44 ++++++++++ .../verticaautoscaler_controller.go | 4 + pkg/vasstatus/status.go | 36 +++++++- pkg/vasstatus/status_test.go | 27 +++++- tests/e2e/autoscale-by-pod/25-assert.yaml | 4 + tests/e2e/autoscale-by-pod/30-assert.yaml | 1 + tests/e2e/autoscale-by-pod/35-assert.yaml | 1 + tests/e2e/autoscale-by-pod/40-assert.yaml | 1 + tests/e2e/autoscale-by-pod/45-assert.yaml | 1 + .../autoscale-by-subcluster/25-assert.yaml | 2 + .../autoscale-by-subcluster/30-assert.yaml | 1 + .../autoscale-by-subcluster/45-assert.yaml | 1 + .../autoscale-by-subcluster/50-assert.yaml | 1 + .../autoscale-by-subcluster/60-assert.yaml | 7 ++ 20 files changed, 320 insertions(+), 16 deletions(-) create mode 100644 pkg/controllers/targetsizeinitializer_reconcile.go create mode 100644 pkg/controllers/targetsizeinitializer_reconcile_test.go create mode 100644 pkg/controllers/vasstatus_reconciler.go diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 8f2e9cc6b..73e2ba6a4 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -18,6 +18,7 @@ limitations under the License. package v1beta1 import ( + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -26,6 +27,7 @@ import ( type VerticaAutoscalerSpec struct { // Important: Run "make" to regenerate code after modifying this file + // SPILLY - maybe rename to VerticaDB // +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 @@ -45,6 +47,7 @@ type VerticaAutoscalerSpec struct { // Sizes of existing subclusters will remain the same. ScalingGranularity ScalingGranularityType `json:"scalingGranularity"` + // SPILLY - maybe rename to ServiceName? // +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. @@ -70,9 +73,9 @@ type VerticaAutoscalerSpec struct { // This is the total pod count for all subclusters that match the // subclusterServiceName. Changing this value may trigger a change in the // VerticaDB that is associated with this object. This value is generally - // left as the default and modified by the horizontal autoscaler through the - // /scale subresource. - TargetSize int32 `json:"targetSize,omitempty"` + // left as zero. It will get initialized in the operator and then modified + // via the /scale subresource by the horizontal autoscaler. + TargetSize int32 `json:"targetSize"` // +operator-sdk:csv:customresourcedefinitions:type=spec // +kubebuilder:validation:Optional @@ -97,19 +100,55 @@ type VerticaAutoscalerStatus struct { // 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 -// SPILLY - statusPath needs to a replica count. It needs to count the number -// of pods in the vdb. We will need to account for missing values. Perhaps we -// always requeue if the count doesn't equal expected. -//+kubebuilder:subresource:scale:specpath=.spec.targetSize,statuspath=.status.scalingCount,selectorpath=.status.selector +//+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,""}} diff --git a/pkg/controllers/subclusterresize_reconcile.go b/pkg/controllers/subclusterresize_reconcile.go index 6a31d854a..989f32357 100644 --- a/pkg/controllers/subclusterresize_reconcile.go +++ b/pkg/controllers/subclusterresize_reconcile.go @@ -109,7 +109,8 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context, req * } if scalingDone { - err = vasstatus.IncrScalingCount(ctx, s.VRec.Client, s.VRec.Log, req) + _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + err = vasstatus.ReportScalingOperation(ctx, s.VRec.Client, s.VRec.Log, req, totSize) } return res, err diff --git a/pkg/controllers/subclusterscale_reconcile.go b/pkg/controllers/subclusterscale_reconcile.go index ff631dde8..8f1d8890c 100644 --- a/pkg/controllers/subclusterscale_reconcile.go +++ b/pkg/controllers/subclusterscale_reconcile.go @@ -93,13 +93,14 @@ func (s *SubclusterScaleReconciler) scaleSubcluster(ctx context.Context, req *ct } if scalingDone { - err = vasstatus.IncrScalingCount(ctx, s.VRec.Client, s.VRec.Log, req) + _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + err = vasstatus.ReportScalingOperation(ctx, s.VRec.Client, s.VRec.Log, req, totSize) } return res, err } -// considerRemovingSubclusters will shrink the Vdb by removing new subclusters. -// Changes are made in-place in s.Vdb +// 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-- { diff --git a/pkg/controllers/subclusterscale_reconcile_test.go b/pkg/controllers/subclusterscale_reconcile_test.go index 6367e35c2..80f66752f 100644 --- a/pkg/controllers/subclusterscale_reconcile_test.go +++ b/pkg/controllers/subclusterscale_reconcile_test.go @@ -148,6 +148,7 @@ var _ = Describe("subclusterscale_reconcile", func() { vasName := vapi.MakeVASName() Expect(k8sClient.Get(ctx, vasName, vas)).Should(Succeed()) vas.Spec.AllowScaleToZero = true + vas.Spec.TargetSize = 0 Expect(k8sClient.Update(ctx, vas)).Should(Succeed()) Expect(vasRec.Reconcile(ctx, req)).Should(Equal(ctrl.Result{})) diff --git a/pkg/controllers/targetsizeinitializer_reconcile.go b/pkg/controllers/targetsizeinitializer_reconcile.go new file mode 100644 index 000000000..21caed933 --- /dev/null +++ b/pkg/controllers/targetsizeinitializer_reconcile.go @@ -0,0 +1,83 @@ +/* + (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 controllers + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + 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) 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.SubclusterServiceName) + + 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/targetsizeinitializer_reconcile_test.go b/pkg/controllers/targetsizeinitializer_reconcile_test.go new file mode 100644 index 000000000..55d708955 --- /dev/null +++ b/pkg/controllers/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 controllers + +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.SubclusterServiceName = 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/vasstatus_reconciler.go b/pkg/controllers/vasstatus_reconciler.go new file mode 100644 index 000000000..925973cbf --- /dev/null +++ b/pkg/controllers/vasstatus_reconciler.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 controllers + +import ( + "context" + + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/vasstatus" + ctrl "sigs.k8s.io/controller-runtime" +) + +type VASStatusReconciler struct { + VRec *VerticaAutoscalerReconciler + Vas *vapi.VerticaAutoscaler +} + +func MakeVASStatusReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { + return &VASStatusReconciler{VRec: v, Vas: vas} +} + +// Reconcile will handle updating the currentSize in the status field +func (v *VASStatusReconciler) 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.SubclusterServiceName) + return ctrl.Result{}, vasstatus.RefreshCurrentSize(ctx, v.VRec.Client, v.VRec.Log, req, totSize) +} diff --git a/pkg/controllers/verticaautoscaler_controller.go b/pkg/controllers/verticaautoscaler_controller.go index 03ed58ac9..145252a23 100644 --- a/pkg/controllers/verticaautoscaler_controller.go +++ b/pkg/controllers/verticaautoscaler_controller.go @@ -70,6 +70,10 @@ func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Re actors := []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 + MakeVASStatusReconciler(r, vas), // Update the status portion of the VerticaAutoscaler MakeSelectorReconciler(r, vas), // If scaling granularity is Pod, this will resize existing subclusters diff --git a/pkg/vasstatus/status.go b/pkg/vasstatus/status.go index 8c9ac89f7..ab55719c4 100644 --- a/pkg/vasstatus/status.go +++ b/pkg/vasstatus/status.go @@ -24,6 +24,7 @@ import ( 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" @@ -35,15 +36,46 @@ func SetSelector(ctx context.Context, c client.Client, log logr.Logger, req *ctr }) } -// IncrScalingCount bumps up the count in the status field about the number of +// 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 IncrScalingCount(ctx context.Context, c client.Client, log logr.Logger, req *ctrl.Request) error { +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 diff --git a/pkg/vasstatus/status_test.go b/pkg/vasstatus/status_test.go index 1c4d047ba..7e643a969 100644 --- a/pkg/vasstatus/status_test.go +++ b/pkg/vasstatus/status_test.go @@ -25,6 +25,7 @@ import ( . "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" @@ -101,21 +102,41 @@ var _ = Describe("status", func() { nm := vapi.MakeVASName() req := ctrl.Request{NamespacedName: nm} - Expect(IncrScalingCount(ctx, k8sClient, logger, &req)).Should(Succeed()) + 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(IncrScalingCount(ctx, k8sClient, logger, &req)).Should(Succeed()) + 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(IncrScalingCount(ctx, k8sClient, logger, &req)).Should(Succeed()) + 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/tests/e2e/autoscale-by-pod/25-assert.yaml b/tests/e2e/autoscale-by-pod/25-assert.yaml index f0a5b3f06..3257979a5 100644 --- a/tests/e2e/autoscale-by-pod/25-assert.yaml +++ b/tests/e2e/autoscale-by-pod/25-assert.yaml @@ -17,6 +17,8 @@ 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 @@ -24,3 +26,5 @@ 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/30-assert.yaml b/tests/e2e/autoscale-by-pod/30-assert.yaml index a0e7dd68c..b3e4546f9 100644 --- a/tests/e2e/autoscale-by-pod/30-assert.yaml +++ b/tests/e2e/autoscale-by-pod/30-assert.yaml @@ -31,3 +31,4 @@ metadata: name: v-autoscale-by-pod-sc1 status: scalingCount: 1 + currentSize: 3 diff --git a/tests/e2e/autoscale-by-pod/35-assert.yaml b/tests/e2e/autoscale-by-pod/35-assert.yaml index 4adfa15ed..6f30c6ebb 100644 --- a/tests/e2e/autoscale-by-pod/35-assert.yaml +++ b/tests/e2e/autoscale-by-pod/35-assert.yaml @@ -31,3 +31,4 @@ metadata: name: v-autoscale-by-pod-sc1 status: scalingCount: 2 + currentSize: 2 diff --git a/tests/e2e/autoscale-by-pod/40-assert.yaml b/tests/e2e/autoscale-by-pod/40-assert.yaml index f625003d7..c1a3a354d 100644 --- a/tests/e2e/autoscale-by-pod/40-assert.yaml +++ b/tests/e2e/autoscale-by-pod/40-assert.yaml @@ -31,3 +31,4 @@ metadata: name: v-autoscale-by-pod-sc2 status: scalingCount: 1 + currentSize: 3 diff --git a/tests/e2e/autoscale-by-pod/45-assert.yaml b/tests/e2e/autoscale-by-pod/45-assert.yaml index 05fa29acd..013a1c85a 100644 --- a/tests/e2e/autoscale-by-pod/45-assert.yaml +++ b/tests/e2e/autoscale-by-pod/45-assert.yaml @@ -31,3 +31,4 @@ metadata: name: v-autoscale-by-pod-sc2 status: scalingCount: 2 + currentSize: 1 diff --git a/tests/e2e/autoscale-by-subcluster/25-assert.yaml b/tests/e2e/autoscale-by-subcluster/25-assert.yaml index 369817eb4..8616d2530 100644 --- a/tests/e2e/autoscale-by-subcluster/25-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/25-assert.yaml @@ -17,3 +17,5 @@ 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/30-assert.yaml b/tests/e2e/autoscale-by-subcluster/30-assert.yaml index 7fc979142..6430e39ba 100644 --- a/tests/e2e/autoscale-by-subcluster/30-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/30-assert.yaml @@ -31,3 +31,4 @@ metadata: name: v-autoscale status: scalingCount: 1 + currentSize: 4 diff --git a/tests/e2e/autoscale-by-subcluster/45-assert.yaml b/tests/e2e/autoscale-by-subcluster/45-assert.yaml index f23060847..e7d14df4f 100644 --- a/tests/e2e/autoscale-by-subcluster/45-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/45-assert.yaml @@ -38,3 +38,4 @@ metadata: name: v-autoscale status: scalingCount: 3 + currentSize: 2 diff --git a/tests/e2e/autoscale-by-subcluster/50-assert.yaml b/tests/e2e/autoscale-by-subcluster/50-assert.yaml index 9691fc2c8..f533d09d9 100644 --- a/tests/e2e/autoscale-by-subcluster/50-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/50-assert.yaml @@ -31,3 +31,4 @@ metadata: name: v-autoscale status: scalingCount: 4 + currentSize: 0 diff --git a/tests/e2e/autoscale-by-subcluster/60-assert.yaml b/tests/e2e/autoscale-by-subcluster/60-assert.yaml index 56888bb0b..db5070851 100644 --- a/tests/e2e/autoscale-by-subcluster/60-assert.yaml +++ b/tests/e2e/autoscale-by-subcluster/60-assert.yaml @@ -17,3 +17,10 @@ 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 From 61e69073a6221dfc5c22ff534760a05c5740782c Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 1 Apr 2022 18:35:10 -0300 Subject: [PATCH 18/27] Code cleanup (rename) --- api/v1beta1/verticaautoscaler_types.go | 35 +++++++------ api/v1beta1/verticaautoscaler_webhook.go | 10 ++-- api/v1beta1/verticaautoscaler_webhook_test.go | 4 +- cmd/operator/main.go | 25 +++------- ...ticadb-operator.clusterserviceversion.yaml | 50 ++++++++++++------- config/samples/v1beta1_verticaautoscaler.yaml | 3 +- pkg/controllers/subclusterresize_reconcile.go | 6 +-- .../subclusterresize_reconcile_test.go | 12 ++--- pkg/controllers/subclusterscale_reconcile.go | 10 ++-- .../subclusterscale_reconcile_test.go | 8 +-- .../targetsizeinitializer_reconcile.go | 2 +- .../targetsizeinitializer_reconcile_test.go | 2 +- pkg/controllers/vasstatus_reconciler.go | 2 +- pkg/vasstatus/status.go | 2 +- pkg/vasstatus/status_test.go | 2 +- .../25-create-autoscale-CR.yaml | 4 +- .../25-create-autoscale-CR.yaml | 2 +- .../55-remove-template-from-vas.yaml | 2 +- tests/e2e/vas-webhook/10-assert.yaml | 2 +- ...0-create-vas-with-default-serviceName.yaml | 2 +- tests/e2e/vas-webhook/15-assert.yaml | 2 +- tests/e2e/vas-webhook/20-assert.yaml | 2 +- .../20-change-serviceName-invalid.yaml | 2 +- tests/e2e/vas-webhook/25-assert.yaml | 2 +- .../25-change-serviceName-valid.yaml | 2 +- 25 files changed, 100 insertions(+), 95 deletions(-) diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 73e2ba6a4..7b58268df 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -27,7 +27,6 @@ import ( type VerticaAutoscalerSpec struct { // Important: Run "make" to regenerate code after modifying this file - // SPILLY - maybe rename to VerticaDB // +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 @@ -40,38 +39,38 @@ type VerticaAutoscalerSpec struct { // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:select:Create","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: // - Pod: Only increase or decrease the size of an existing subcluster. - // This cannot be used if more than one subcluster is selected with - // subclusterServiceName. + // If multiple subclusters are selected by the serviceName, this will grow + // the last subcluster only. // - Subcluster: Scaling will be achieved by creating or deleting entire subclusters. - // New subclusters are created using subclusterTemplate as a template. - // Sizes of existing subclusters will remain the same. + // The template for new subclusters are either the template if filled out + // or an existing subcluster that matches the service name. ScalingGranularity ScalingGranularityType `json:"scalingGranularity"` - // SPILLY - maybe rename to ServiceName? // +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. - // The name refers to the service name as defined in the subcluster section - // of the VerticaDB, which if omitted is the same name as the subcluster name. - SubclusterServiceName string `json:"subclusterServiceName"` + // 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 subclusterServiceName - // 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. + // 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 - // subclusterServiceName. Changing this value may trigger a change in 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 by the horizontal autoscaler. @@ -197,9 +196,9 @@ func MakeVAS() *VerticaAutoscaler { Annotations: make(map[string]string), }, Spec: VerticaAutoscalerSpec{ - VerticaDBName: vdbNm.Name, - ScalingGranularity: "Pod", - SubclusterServiceName: "sc1", + VerticaDBName: vdbNm.Name, + ScalingGranularity: "Pod", + ServiceName: "sc1", }, } } diff --git a/api/v1beta1/verticaautoscaler_webhook.go b/api/v1beta1/verticaautoscaler_webhook.go index 6c07a538c..9f9323ca4 100644 --- a/api/v1beta1/verticaautoscaler_webhook.go +++ b/api/v1beta1/verticaautoscaler_webhook.go @@ -46,7 +46,7 @@ func (v *VerticaAutoscaler) Default() { verticaautoscalerlog.Info("default", "name", v.Name) if v.Spec.Template.ServiceName == "" { - v.Spec.Template.ServiceName = v.Spec.SubclusterServiceName + v.Spec.Template.ServiceName = v.Spec.ServiceName } } @@ -109,13 +109,13 @@ func (v *VerticaAutoscaler) validateScalingGranularity(allErrs field.ErrorList) 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.subclusterServiceName. So we only need to check for differences if - // this is an update or a create but we set something. + // 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.SubclusterServiceName { + 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.subclusterServiceName") + "The serviceName in the subcluster template must match spec.serviceName") allErrs = append(allErrs, err) } diff --git a/api/v1beta1/verticaautoscaler_webhook_test.go b/api/v1beta1/verticaautoscaler_webhook_test.go index 8d8c4e5b8..185eab7e8 100644 --- a/api/v1beta1/verticaautoscaler_webhook_test.go +++ b/api/v1beta1/verticaautoscaler_webhook_test.go @@ -36,7 +36,7 @@ var _ = Describe("verticaautoscaler_webhook", func() { vas := MakeVAS() vas.Spec.Template.ServiceName = "" vas.Default() - Expect(vas.Spec.Template.ServiceName).Should(Equal(vas.Spec.SubclusterServiceName)) + Expect(vas.Spec.Template.ServiceName).Should(Equal(vas.Spec.ServiceName)) }) It("should fail if the service name differs", func() { @@ -46,7 +46,7 @@ var _ = Describe("verticaautoscaler_webhook", func() { vas.Spec.Template.ServiceName = "" Expect(vas.ValidateCreate()).Should(Succeed()) Expect(vas.ValidateUpdate(MakeVAS())).ShouldNot(Succeed()) - vas.Spec.Template.ServiceName = vas.Spec.SubclusterServiceName + vas.Spec.Template.ServiceName = vas.Spec.ServiceName Expect(vas.ValidateUpdate(MakeVAS())).Should(Succeed()) }) }) diff --git a/cmd/operator/main.go b/cmd/operator/main.go index ca3260582..1100b2d8b 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -221,28 +221,19 @@ func getLogger(logArgs Logging) *zap.Logger { return zap.New(core, opts...) } -// SPILLY - address this -// nolint:funlen 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) @@ -262,10 +253,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, }) @@ -280,7 +271,7 @@ func main() { Scheme: mgr.GetScheme(), Cfg: restCfg, EVRec: mgr.GetEventRecorderFor(builder.OperatorName), - ServiceAccountName: saName, + ServiceAccountName: flagArgs.ServiceAccountName, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "VerticaDB") os.Exit(1) diff --git a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml index 3ef42acde..6db953253 100644 --- a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml @@ -35,11 +35,11 @@ spec: - urn:alm:descriptor:com.tectonic.ui:hidden - description: 'This defines how the scaling will happen. This can be one of the following: - Pod: Only increase or decrease the size of an existing - subcluster. This cannot be used if more than one subcluster is selected - with subclusterServiceName. - Subcluster: Scaling will be achieved by - creating or deleting entire subclusters. New subclusters are created using - subclusterTemplate as a template. Sizes of existing subclusters will remain - the same.' + subcluster. If multiple subclusters are selected by the serviceName, this + will grow the last subcluster only. - 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.' displayName: Scaling Granularity path: scalingGranularity x-descriptors: @@ -47,18 +47,18 @@ spec: - 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. The name refers to the service name as defined in the subcluster - section of the VerticaDB, which if omitted is the same name as the subcluster - name. - displayName: Subcluster Service Name - path: subclusterServiceName + 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 - subclusterServiceName. Changing this value may trigger a change in the - VerticaDB that is associated with this object. This value is generally - left as the default and modified by the horizontal autoscaler through the - /scale subresource. + 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 + by the horizontal autoscaler. displayName: Target Size path: targetSize x-descriptors: @@ -66,10 +66,10 @@ spec: - 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 subclusterServiceName parameter. The + 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. + 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 @@ -200,6 +200,22 @@ spec: 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 diff --git a/config/samples/v1beta1_verticaautoscaler.yaml b/config/samples/v1beta1_verticaautoscaler.yaml index 34a0f8f93..429ed4280 100644 --- a/config/samples/v1beta1_verticaautoscaler.yaml +++ b/config/samples/v1beta1_verticaautoscaler.yaml @@ -4,5 +4,4 @@ metadata: name: verticaautoscaler-sample spec: verticaDBName: verticadb-sample - subclusterServiceName: defaultsubcluster - scalingGranularity: Pod + serviceName: defaultsubcluster diff --git a/pkg/controllers/subclusterresize_reconcile.go b/pkg/controllers/subclusterresize_reconcile.go index 989f32357..6ab038252 100644 --- a/pkg/controllers/subclusterresize_reconcile.go +++ b/pkg/controllers/subclusterresize_reconcile.go @@ -65,10 +65,10 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context, req * return e } - subclusters, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + subclusters, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) if len(subclusters) == 0 { s.VRec.EVRec.Eventf(s.Vas, corev1.EventTypeWarning, events.VerticaDBNotFound, - "Could not find any subclusters with service name '%s'", s.Vas.Spec.SubclusterServiceName) + "Could not find any subclusters with service name '%s'", s.Vas.Spec.ServiceName) res.Requeue = true return nil } @@ -109,7 +109,7 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context, req * } if scalingDone { - _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) err = vasstatus.ReportScalingOperation(ctx, s.VRec.Client, s.VRec.Log, req, totSize) } diff --git a/pkg/controllers/subclusterresize_reconcile_test.go b/pkg/controllers/subclusterresize_reconcile_test.go index 2aca44bef..6b18c469d 100644 --- a/pkg/controllers/subclusterresize_reconcile_test.go +++ b/pkg/controllers/subclusterresize_reconcile_test.go @@ -43,7 +43,7 @@ var _ = Describe("subclusterresize_reconcile", func() { defer test.DeleteVDB(ctx, k8sClient, vdb) vas := vapi.MakeVAS() - vas.Spec.SubclusterServiceName = "not-there" + vas.Spec.ServiceName = "not-there" vas.Spec.TargetSize = 5 test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) @@ -64,7 +64,7 @@ var _ = Describe("subclusterresize_reconcile", func() { vas := vapi.MakeVAS() vas.Spec.TargetSize = TargetSize - vas.Spec.SubclusterServiceName = ScName + vas.Spec.ServiceName = ScName test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) @@ -84,7 +84,7 @@ var _ = Describe("subclusterresize_reconcile", func() { vas := vapi.MakeVAS() vas.Spec.TargetSize = 0 - vas.Spec.SubclusterServiceName = vdb.Spec.Subclusters[0].GetServiceName() + vas.Spec.ServiceName = vdb.Spec.Subclusters[0].GetServiceName() test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) @@ -104,7 +104,7 @@ var _ = Describe("subclusterresize_reconcile", func() { vas := vapi.MakeVAS() vas.Spec.TargetSize = vdb.Spec.Subclusters[0].Size - vas.Spec.SubclusterServiceName = vdb.Spec.Subclusters[0].GetServiceName() + vas.Spec.ServiceName = vdb.Spec.Subclusters[0].GetServiceName() test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) @@ -131,7 +131,7 @@ var _ = Describe("subclusterresize_reconcile", func() { vas := vapi.MakeVAS() const NumPodsToAdd = 5 vas.Spec.TargetSize = vdb.Spec.Subclusters[0].Size + vdb.Spec.Subclusters[1].Size + NumPodsToAdd - vas.Spec.SubclusterServiceName = TargetSvcName + vas.Spec.ServiceName = TargetSvcName test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) @@ -160,7 +160,7 @@ var _ = Describe("subclusterresize_reconcile", func() { vas := vapi.MakeVAS() const NumPodsToRemove = 3 vas.Spec.TargetSize = vdb.Spec.Subclusters[0].Size + vdb.Spec.Subclusters[2].Size - NumPodsToRemove - vas.Spec.SubclusterServiceName = TargetSvcName + vas.Spec.ServiceName = TargetSvcName test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) diff --git a/pkg/controllers/subclusterscale_reconcile.go b/pkg/controllers/subclusterscale_reconcile.go index 8f1d8890c..ecb281216 100644 --- a/pkg/controllers/subclusterscale_reconcile.go +++ b/pkg/controllers/subclusterscale_reconcile.go @@ -66,7 +66,7 @@ func (s *SubclusterScaleReconciler) scaleSubcluster(ctx context.Context, req *ct return e } - _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) delta := s.Vas.Spec.TargetSize - totSize switch { case delta < 0: @@ -93,7 +93,7 @@ func (s *SubclusterScaleReconciler) scaleSubcluster(ctx context.Context, req *ct } if scalingDone { - _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + _, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) err = vasstatus.ReportScalingOperation(ctx, s.VRec.Client, s.VRec.Log, req, totSize) } return res, err @@ -105,7 +105,7 @@ func (s *SubclusterScaleReconciler) considerRemovingSubclusters(podsToRemove int 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.SubclusterServiceName { + 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) @@ -175,7 +175,7 @@ func (s *SubclusterScaleReconciler) calcNextSubcluster(scMap map[string]*vapi.Su sc.Name = s.genNextSubclusterName(scMap) return sc, true } - scs, _ := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.SubclusterServiceName) + 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" @@ -184,7 +184,7 @@ func (s *SubclusterScaleReconciler) calcNextSubcluster(scMap map[string]*vapi.Su return nil, false } newSc := scs[len(scs)-1].DeepCopy() - newSc.ServiceName = s.Vas.Spec.SubclusterServiceName + newSc.ServiceName = s.Vas.Spec.ServiceName newSc.Name = s.genNextSubclusterName(scMap) return newSc, true } diff --git a/pkg/controllers/subclusterscale_reconcile_test.go b/pkg/controllers/subclusterscale_reconcile_test.go index 80f66752f..36afe0516 100644 --- a/pkg/controllers/subclusterscale_reconcile_test.go +++ b/pkg/controllers/subclusterscale_reconcile_test.go @@ -75,7 +75,7 @@ var _ = Describe("subclusterscale_reconcile", func() { vas := vapi.MakeVAS() vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity - vas.Spec.SubclusterServiceName = ServiceName + vas.Spec.ServiceName = ServiceName vas.Spec.Template = vapi.Subcluster{ Name: "blah", ServiceName: ServiceName, @@ -126,7 +126,7 @@ var _ = Describe("subclusterscale_reconcile", func() { vas := vapi.MakeVAS() vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity - vas.Spec.SubclusterServiceName = ServiceName + vas.Spec.ServiceName = ServiceName vas.Spec.Template = vapi.Subcluster{ Name: "blah", ServiceName: ServiceName, @@ -170,7 +170,7 @@ var _ = Describe("subclusterscale_reconcile", func() { vas := vapi.MakeVAS() vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity - vas.Spec.SubclusterServiceName = ServiceName + vas.Spec.ServiceName = ServiceName vas.Spec.Template.Size = 0 vas.Spec.TargetSize = 8 test.CreateVAS(ctx, k8sClient, vas) @@ -205,7 +205,7 @@ var _ = Describe("subclusterscale_reconcile", func() { vas := vapi.MakeVAS() vas.Spec.ScalingGranularity = vapi.SubclusterScalingGranularity - vas.Spec.SubclusterServiceName = "BrandNewServiceName" + vas.Spec.ServiceName = "BrandNewServiceName" vas.Spec.Template.Size = 0 vas.Spec.TargetSize = 50 test.CreateVAS(ctx, k8sClient, vas) diff --git a/pkg/controllers/targetsizeinitializer_reconcile.go b/pkg/controllers/targetsizeinitializer_reconcile.go index 21caed933..25fd3a742 100644 --- a/pkg/controllers/targetsizeinitializer_reconcile.go +++ b/pkg/controllers/targetsizeinitializer_reconcile.go @@ -61,7 +61,7 @@ func (v *TargetSizeInitializerReconciler) initTargetSize(ctx context.Context) (c if res, e = fetchVDB(ctx, v.VRec, v.Vas, vdb); verrors.IsReconcileAborted(res, e) { return e } - _, totSize := vdb.FindSubclusterForServiceName(v.Vas.Spec.SubclusterServiceName) + _, totSize := vdb.FindSubclusterForServiceName(v.Vas.Spec.ServiceName) if v.Vas.Spec.TargetSize != totSize { v.VRec.Log.Info("Updating targetSize in vas", "targetSize", totSize) diff --git a/pkg/controllers/targetsizeinitializer_reconcile_test.go b/pkg/controllers/targetsizeinitializer_reconcile_test.go index 55d708955..9b0eb5654 100644 --- a/pkg/controllers/targetsizeinitializer_reconcile_test.go +++ b/pkg/controllers/targetsizeinitializer_reconcile_test.go @@ -40,7 +40,7 @@ var _ = Describe("targetsizeinitializer_reconcile", func() { defer test.DeleteVDB(ctx, k8sClient, vdb) vas := vapi.MakeVAS() - vas.Spec.SubclusterServiceName = ServiceName + vas.Spec.ServiceName = ServiceName vas.Spec.TargetSize = 0 test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) diff --git a/pkg/controllers/vasstatus_reconciler.go b/pkg/controllers/vasstatus_reconciler.go index 925973cbf..76697178c 100644 --- a/pkg/controllers/vasstatus_reconciler.go +++ b/pkg/controllers/vasstatus_reconciler.go @@ -39,6 +39,6 @@ func (v *VASStatusReconciler) Reconcile(ctx context.Context, req *ctrl.Request) if res, err := fetchVDB(ctx, v.VRec, v.Vas, vdb); verrors.IsReconcileAborted(res, err) { return res, err } - _, totSize := vdb.FindSubclusterForServiceName(v.Vas.Spec.SubclusterServiceName) + _, 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/vasstatus/status.go b/pkg/vasstatus/status.go index ab55719c4..1d1488795 100644 --- a/pkg/vasstatus/status.go +++ b/pkg/vasstatus/status.go @@ -111,7 +111,7 @@ func vasStatusUpdater(ctx context.Context, c client.Client, log logr.Logger, func getLabelSelector(vas *vapi.VerticaAutoscaler) string { return fmt.Sprintf("%s=%s,%s=%s,%s=%s", builder.SubclusterSvcNameLabel, - vas.Spec.SubclusterServiceName, + vas.Spec.ServiceName, builder.VDBInstanceLabel, vas.Spec.VerticaDBName, builder.ManagedByLabel, diff --git a/pkg/vasstatus/status_test.go b/pkg/vasstatus/status_test.go index 7e643a969..6ae7ad19d 100644 --- a/pkg/vasstatus/status_test.go +++ b/pkg/vasstatus/status_test.go @@ -80,7 +80,7 @@ var _ = Describe("status", func() { It("should set the selector in the status field", func() { vas := vapi.MakeVAS() - vas.Spec.SubclusterServiceName = "my-svc" + vas.Spec.ServiceName = "my-svc" test.CreateVAS(ctx, k8sClient, vas) defer test.DeleteVAS(ctx, k8sClient, vas) diff --git a/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml b/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml index 924413f75..9b8f774e7 100644 --- a/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml +++ b/tests/e2e/autoscale-by-pod/25-create-autoscale-CR.yaml @@ -17,7 +17,7 @@ metadata: name: v-autoscale-by-pod-sc1 spec: verticaDBName: v-autoscale-by-pod - subclusterServiceName: sc1 + serviceName: sc1 scalingGranularity: Pod --- apiVersion: vertica.com/v1beta1 @@ -26,5 +26,5 @@ metadata: name: v-autoscale-by-pod-sc2 spec: verticaDBName: v-autoscale-by-pod - subclusterServiceName: sc2 + serviceName: sc2 scalingGranularity: Pod diff --git a/tests/e2e/autoscale-by-subcluster/25-create-autoscale-CR.yaml b/tests/e2e/autoscale-by-subcluster/25-create-autoscale-CR.yaml index b86394dd7..d37374f0b 100644 --- a/tests/e2e/autoscale-by-subcluster/25-create-autoscale-CR.yaml +++ b/tests/e2e/autoscale-by-subcluster/25-create-autoscale-CR.yaml @@ -17,7 +17,7 @@ metadata: name: v-autoscale spec: verticaDBName: v-autoscale-by-subcluster - subclusterServiceName: as + serviceName: as scalingGranularity: Subcluster template: name: as 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 index 2cc7d17ee..dc92fd23c 100644 --- a/tests/e2e/autoscale-by-subcluster/55-remove-template-from-vas.yaml +++ b/tests/e2e/autoscale-by-subcluster/55-remove-template-from-vas.yaml @@ -17,7 +17,7 @@ metadata: name: v-autoscale spec: verticaDBName: v-autoscale-by-subcluster - subclusterServiceName: pri + serviceName: pri scalingGranularity: Subcluster template: name: "" diff --git a/tests/e2e/vas-webhook/10-assert.yaml b/tests/e2e/vas-webhook/10-assert.yaml index 6d42be6c7..2b40ebce4 100644 --- a/tests/e2e/vas-webhook/10-assert.yaml +++ b/tests/e2e/vas-webhook/10-assert.yaml @@ -16,7 +16,7 @@ kind: VerticaAutoscaler metadata: name: vas-webhook spec: - subclusterServiceName: sc1 + 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 index 771221223..1d7d7ed3f 100644 --- a/tests/e2e/vas-webhook/10-create-vas-with-default-serviceName.yaml +++ b/tests/e2e/vas-webhook/10-create-vas-with-default-serviceName.yaml @@ -16,4 +16,4 @@ kind: VerticaAutoscaler metadata: name: vas-webhook spec: - subclusterServiceName: sc1 + serviceName: sc1 diff --git a/tests/e2e/vas-webhook/15-assert.yaml b/tests/e2e/vas-webhook/15-assert.yaml index 6d42be6c7..2b40ebce4 100644 --- a/tests/e2e/vas-webhook/15-assert.yaml +++ b/tests/e2e/vas-webhook/15-assert.yaml @@ -16,7 +16,7 @@ kind: VerticaAutoscaler metadata: name: vas-webhook spec: - subclusterServiceName: sc1 + serviceName: sc1 scalingGranularity: Subcluster template: serviceName: sc1 diff --git a/tests/e2e/vas-webhook/20-assert.yaml b/tests/e2e/vas-webhook/20-assert.yaml index 6d42be6c7..2b40ebce4 100644 --- a/tests/e2e/vas-webhook/20-assert.yaml +++ b/tests/e2e/vas-webhook/20-assert.yaml @@ -16,7 +16,7 @@ kind: VerticaAutoscaler metadata: name: vas-webhook spec: - subclusterServiceName: sc1 + 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 index d56701dd4..55e960287 100644 --- a/tests/e2e/vas-webhook/20-change-serviceName-invalid.yaml +++ b/tests/e2e/vas-webhook/20-change-serviceName-invalid.yaml @@ -14,5 +14,5 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: - - script: kubectl -n $NAMESPACE get vas vas-webhook -o json | jq '.spec.subclusterServiceName="NewValue"' | kubectl -n $NAMESPACE replace -f - + - 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 index 1a955b87f..0096340be 100644 --- a/tests/e2e/vas-webhook/25-assert.yaml +++ b/tests/e2e/vas-webhook/25-assert.yaml @@ -16,7 +16,7 @@ kind: VerticaAutoscaler metadata: name: vas-webhook spec: - subclusterServiceName: NewValue2 + 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 index ce63c932b..6adf4ec25 100644 --- a/tests/e2e/vas-webhook/25-change-serviceName-valid.yaml +++ b/tests/e2e/vas-webhook/25-change-serviceName-valid.yaml @@ -14,4 +14,4 @@ apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: - - script: kubectl -n $NAMESPACE get vas vas-webhook -o json | jq '.spec.subclusterServiceName="NewValue2"' | jq '.spec.template.serviceName="NewValue2"' | kubectl -n $NAMESPACE replace -f - + - script: kubectl -n $NAMESPACE get vas vas-webhook -o json | jq '.spec.serviceName="NewValue2"' | jq '.spec.template.serviceName="NewValue2"' | kubectl -n $NAMESPACE replace -f - From 3e2382b450e7dc59dcc048acf956c4d636195831 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Mon, 4 Apr 2022 08:50:11 -0300 Subject: [PATCH 19/27] Revert changes for pending pod handling I need to rethink these as it ended up breaking online upgrade. --- pkg/controllers/podfacts.go | 16 ++++++++++++++-- pkg/controllers/restart_reconcile.go | 15 +++++++++++++-- pkg/controllers/restart_reconciler_test.go | 4 ++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/pkg/controllers/podfacts.go b/pkg/controllers/podfacts.go index 7f6a29e1f..bf61991b4 100644 --- a/pkg/controllers/podfacts.go +++ b/pkg/controllers/podfacts.go @@ -629,8 +629,8 @@ func (p *PodFacts) findInstalledPods() []*PodFact { // An empty list implies there are no pods that match the criteria. func (p *PodFacts) findReIPPods(onlyPodsWithoutDBs bool) []*PodFact { return p.filterPods(func(pod *PodFact) bool { - // Only consider running pods that have an installation - if !pod.exists || !pod.isPodRunning || pod.isInstalled.IsFalse() { + // Only consider pods that exist and have an installation + if !pod.exists || pod.isInstalled.IsFalse() { return false } // If requested don't return pods that have a DB @@ -684,6 +684,18 @@ func (p *PodFacts) countRunningAndInstalled() int { }) } +// countNotRunning returns number of pods that aren't running yet +func (p *PodFacts) countNotRunning() int { + return p.countPods(func(v *PodFact) int { + // We don't count non-running pods that aren't yet managed by the parent + // sts. The sts needs to be created or sized first. + if !v.isPodRunning && v.managedByParent { + return 1 + } + return 0 + }) +} + // countUpPrimaryNodes returns the number of primary nodes that are UP func (p *PodFacts) countUpPrimaryNodes() int { return p.countPods(func(v *PodFact) int { diff --git a/pkg/controllers/restart_reconcile.go b/pkg/controllers/restart_reconcile.go index 6bffc9ec8..e8a438b74 100644 --- a/pkg/controllers/restart_reconcile.go +++ b/pkg/controllers/restart_reconcile.go @@ -182,7 +182,7 @@ func (r *RestartReconciler) reconcileNodes(ctx context.Context) (ctrl.Result, er // didn't originate the install. So we will skip the rest if running in // that mode. if r.Vdb.Spec.InitPolicy == vapi.CommunalInitPolicyScheduleOnly { - return ctrl.Result{}, nil + return ctrl.Result{Requeue: r.shouldRequeueIfPodsNotRunning()}, nil } // Find any pods that need to have their IP updated. These are nodes that @@ -198,7 +198,7 @@ func (r *RestartReconciler) reconcileNodes(ctx context.Context) (ctrl.Result, er } } - return ctrl.Result{}, nil + return ctrl.Result{Requeue: r.shouldRequeueIfPodsNotRunning()}, nil } // restartPods restart the down pods using admintools @@ -601,3 +601,14 @@ func (r *RestartReconciler) setATPod(findFunc func() (*PodFact, bool)) bool { } return true } + +// shouldRequeueIfPodsNotRunning is a helper function that will determine +// whether a requeue of the reconcile is necessary because some pods are not yet +// running. +func (r *RestartReconciler) shouldRequeueIfPodsNotRunning() bool { + if r.PFacts.countNotRunning() > 0 { + r.Log.Info("Requeue. Some pods are not yet running.") + return true + } + return false +} diff --git a/pkg/controllers/restart_reconciler_test.go b/pkg/controllers/restart_reconciler_test.go index ea748c635..a35ddd409 100644 --- a/pkg/controllers/restart_reconciler_test.go +++ b/pkg/controllers/restart_reconciler_test.go @@ -500,7 +500,7 @@ var _ = Describe("restart_reconciler", func() { Expect(len(reip)).Should(Equal(1)) }) - It("should not requeue if one pod is not running", func() { + It("should requeue if one pod is not running", func() { vdb := vapi.MakeVDB() vdb.Spec.InitPolicy = vapi.CommunalInitPolicyScheduleOnly sc := &vdb.Spec.Subclusters[0] @@ -519,7 +519,7 @@ var _ = Describe("restart_reconciler", func() { pfacts := createPodFactsWithRestartNeeded(ctx, vdb, sc, fpr, []int32{DownPodIndex}, PodNotReadOnly) r := MakeRestartReconciler(vdbRec, logger, vdb, fpr, pfacts, RestartProcessReadOnly) - Expect(r.Reconcile(ctx, &ctrl.Request{})).Should(Equal(ctrl.Result{})) + Expect(r.Reconcile(ctx, &ctrl.Request{})).Should(Equal(ctrl.Result{Requeue: true})) }) It("should avoid restart_node of read-only nodes when that setting is used", func() { From dec030068b94f559b6ce2e70fbff142fed7d7db1 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 8 Apr 2022 10:28:38 -0300 Subject: [PATCH 20/27] Seperate autoscaler controller into separate package --- cmd/operator/main.go | 3 +- pkg/controllers/k8s.go | 17 ---- pkg/controllers/restart_reconcile.go | 1 + pkg/controllers/suite_test.go | 8 -- pkg/vascontroller/actor.go | 28 ++++++ pkg/vascontroller/k8s.go | 44 +++++++++ .../subclusterresize_reconcile.go | 2 +- .../subclusterresize_reconcile_test.go | 2 +- .../subclusterscale_reconcile.go | 2 +- .../subclusterscale_reconcile_test.go | 2 +- pkg/vascontroller/suite_test.go | 90 +++++++++++++++++++ .../targetsizeinitializer_reconcile.go | 2 +- .../targetsizeinitializer_reconcile_test.go | 2 +- .../vasselector_reconciler.go | 2 +- .../vasstatus_reconciler.go | 2 +- .../vdbverify_reconcile.go | 2 +- .../verticaautoscaler_controller.go | 2 +- 17 files changed, 175 insertions(+), 36 deletions(-) create mode 100644 pkg/vascontroller/actor.go create mode 100644 pkg/vascontroller/k8s.go rename pkg/{controllers => vascontroller}/subclusterresize_reconcile.go (99%) rename pkg/{controllers => vascontroller}/subclusterresize_reconcile_test.go (99%) rename pkg/{controllers => vascontroller}/subclusterscale_reconcile.go (99%) rename pkg/{controllers => vascontroller}/subclusterscale_reconcile_test.go (99%) create mode 100644 pkg/vascontroller/suite_test.go rename pkg/{controllers => vascontroller}/targetsizeinitializer_reconcile.go (99%) rename pkg/{controllers => vascontroller}/targetsizeinitializer_reconcile_test.go (98%) rename pkg/{controllers => vascontroller}/vasselector_reconciler.go (98%) rename pkg/{controllers => vascontroller}/vasstatus_reconciler.go (98%) rename pkg/{controllers => vascontroller}/vdbverify_reconcile.go (98%) rename pkg/{controllers => vascontroller}/verticaautoscaler_controller.go (99%) diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 1100b2d8b..5e76fd44d 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -42,6 +42,7 @@ import ( 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/vascontroller" //+kubebuilder:scaffold:imports ) @@ -277,7 +278,7 @@ func main() { os.Exit(1) } - if err = (&controllers.VerticaAutoscalerReconciler{ + if err = (&vascontroller.VerticaAutoscalerReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), EVRec: mgr.GetEventRecorderFor(builder.OperatorName), diff --git a/pkg/controllers/k8s.go b/pkg/controllers/k8s.go index 1fd1a353f..6c015ba9b 100644 --- a/pkg/controllers/k8s.go +++ b/pkg/controllers/k8s.go @@ -72,20 +72,3 @@ func getConfigMapOrSecret(ctx context.Context, vrec *VerticaDBReconciler, vdb *v } return ctrl.Result{}, nil } - -// 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/restart_reconcile.go b/pkg/controllers/restart_reconcile.go index e8a438b74..ad33c83d7 100644 --- a/pkg/controllers/restart_reconcile.go +++ b/pkg/controllers/restart_reconcile.go @@ -70,6 +70,7 @@ 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 { + // SPILLY - rename vdbstatus back to status? err := vdbstatus.UpdateCondition(ctx, r.VRec.Client, r.Vdb, vapi.VerticaDBCondition{Type: vapi.AutoRestartVertica, Status: corev1.ConditionFalse}, ) diff --git a/pkg/controllers/suite_test.go b/pkg/controllers/suite_test.go index 52fe60324..6e14cff65 100644 --- a/pkg/controllers/suite_test.go +++ b/pkg/controllers/suite_test.go @@ -45,7 +45,6 @@ var testEnv *envtest.Environment var logger logr.Logger var restCfg *rest.Config var vdbRec *VerticaDBReconciler -var vasRec *VerticaAutoscalerReconciler var _ = BeforeSuite(func() { logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)) @@ -82,13 +81,6 @@ var _ = BeforeSuite(func() { EVRec: mgr.GetEventRecorderFor(builder.OperatorName), ServiceAccountName: builder.DefaultServiceAccountName, } - - vasRec = &VerticaAutoscalerReconciler{ - Client: k8sClient, - Log: logger, - Scheme: scheme.Scheme, - EVRec: mgr.GetEventRecorderFor(builder.OperatorName), - } }, 60) var _ = AfterSuite(func() { diff --git a/pkg/vascontroller/actor.go b/pkg/vascontroller/actor.go new file mode 100644 index 000000000..37f2fc80a --- /dev/null +++ b/pkg/vascontroller/actor.go @@ -0,0 +1,28 @@ +/* + (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 vascontroller + +import ( + "context" + + ctrl "sigs.k8s.io/controller-runtime" +) + +// ReconcileActor is an interface that handles one part of the entire +// reconciliation process. +type ReconcileActor interface { + Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) +} diff --git a/pkg/vascontroller/k8s.go b/pkg/vascontroller/k8s.go new file mode 100644 index 000000000..a4cfb9813 --- /dev/null +++ b/pkg/vascontroller/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 vascontroller + +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/subclusterresize_reconcile.go b/pkg/vascontroller/subclusterresize_reconcile.go similarity index 99% rename from pkg/controllers/subclusterresize_reconcile.go rename to pkg/vascontroller/subclusterresize_reconcile.go index 6ab038252..e60966612 100644 --- a/pkg/controllers/subclusterresize_reconcile.go +++ b/pkg/vascontroller/subclusterresize_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/controllers/subclusterresize_reconcile_test.go b/pkg/vascontroller/subclusterresize_reconcile_test.go similarity index 99% rename from pkg/controllers/subclusterresize_reconcile_test.go rename to pkg/vascontroller/subclusterresize_reconcile_test.go index 6b18c469d..e2606dd93 100644 --- a/pkg/controllers/subclusterresize_reconcile_test.go +++ b/pkg/vascontroller/subclusterresize_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/controllers/subclusterscale_reconcile.go b/pkg/vascontroller/subclusterscale_reconcile.go similarity index 99% rename from pkg/controllers/subclusterscale_reconcile.go rename to pkg/vascontroller/subclusterscale_reconcile.go index ecb281216..d5f54f552 100644 --- a/pkg/controllers/subclusterscale_reconcile.go +++ b/pkg/vascontroller/subclusterscale_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/controllers/subclusterscale_reconcile_test.go b/pkg/vascontroller/subclusterscale_reconcile_test.go similarity index 99% rename from pkg/controllers/subclusterscale_reconcile_test.go rename to pkg/vascontroller/subclusterscale_reconcile_test.go index 36afe0516..f82fe3c80 100644 --- a/pkg/controllers/subclusterscale_reconcile_test.go +++ b/pkg/vascontroller/subclusterscale_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/vascontroller/suite_test.go b/pkg/vascontroller/suite_test.go new file mode 100644 index 000000000..912e7c371 --- /dev/null +++ b/pkg/vascontroller/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 vascontroller + +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, + "vascontroller Suite", + []Reporter{printer.NewlineReporter{}}) +} diff --git a/pkg/controllers/targetsizeinitializer_reconcile.go b/pkg/vascontroller/targetsizeinitializer_reconcile.go similarity index 99% rename from pkg/controllers/targetsizeinitializer_reconcile.go rename to pkg/vascontroller/targetsizeinitializer_reconcile.go index 25fd3a742..2a3e4a6c7 100644 --- a/pkg/controllers/targetsizeinitializer_reconcile.go +++ b/pkg/vascontroller/targetsizeinitializer_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/controllers/targetsizeinitializer_reconcile_test.go b/pkg/vascontroller/targetsizeinitializer_reconcile_test.go similarity index 98% rename from pkg/controllers/targetsizeinitializer_reconcile_test.go rename to pkg/vascontroller/targetsizeinitializer_reconcile_test.go index 9b0eb5654..7cb9b8c5f 100644 --- a/pkg/controllers/targetsizeinitializer_reconcile_test.go +++ b/pkg/vascontroller/targetsizeinitializer_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/controllers/vasselector_reconciler.go b/pkg/vascontroller/vasselector_reconciler.go similarity index 98% rename from pkg/controllers/vasselector_reconciler.go rename to pkg/vascontroller/vasselector_reconciler.go index e4a37cfb4..08e11d848 100644 --- a/pkg/controllers/vasselector_reconciler.go +++ b/pkg/vascontroller/vasselector_reconciler.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/controllers/vasstatus_reconciler.go b/pkg/vascontroller/vasstatus_reconciler.go similarity index 98% rename from pkg/controllers/vasstatus_reconciler.go rename to pkg/vascontroller/vasstatus_reconciler.go index 76697178c..dcbfa7e4a 100644 --- a/pkg/controllers/vasstatus_reconciler.go +++ b/pkg/vascontroller/vasstatus_reconciler.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/controllers/vdbverify_reconcile.go b/pkg/vascontroller/vdbverify_reconcile.go similarity index 98% rename from pkg/controllers/vdbverify_reconcile.go rename to pkg/vascontroller/vdbverify_reconcile.go index 32a66348f..f61e94fdc 100644 --- a/pkg/controllers/vdbverify_reconcile.go +++ b/pkg/vascontroller/vdbverify_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vascontroller import ( "context" diff --git a/pkg/controllers/verticaautoscaler_controller.go b/pkg/vascontroller/verticaautoscaler_controller.go similarity index 99% rename from pkg/controllers/verticaautoscaler_controller.go rename to pkg/vascontroller/verticaautoscaler_controller.go index 145252a23..6d2c924d1 100644 --- a/pkg/controllers/verticaautoscaler_controller.go +++ b/pkg/vascontroller/verticaautoscaler_controller.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package controllers +package vascontroller import ( "context" From 1f8e5aefa27ef39e4c31ba4c039e529b5932d320 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 8 Apr 2022 10:29:50 -0300 Subject: [PATCH 21/27] Code cleanup --- pkg/controllers/restart_reconcile.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/controllers/restart_reconcile.go b/pkg/controllers/restart_reconcile.go index ad33c83d7..e8a438b74 100644 --- a/pkg/controllers/restart_reconcile.go +++ b/pkg/controllers/restart_reconcile.go @@ -70,7 +70,6 @@ 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 { - // SPILLY - rename vdbstatus back to status? err := vdbstatus.UpdateCondition(ctx, r.VRec.Client, r.Vdb, vapi.VerticaDBCondition{Type: vapi.AutoRestartVertica, Status: corev1.ConditionFalse}, ) From a686ec09cf21fdbb8573e7c1d7592d3e7ad8f172 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Fri, 8 Apr 2022 11:02:44 -0300 Subject: [PATCH 22/27] Code cleanup --- api/v1beta1/verticaautoscaler_types.go | 10 +++++----- api/v1beta1/verticadb_webhook.go | 12 ++++++++++++ api/v1beta1/verticadb_webhook_test.go | 7 +++++++ ...verticadb-operator.clusterserviceversion.yaml | 16 +++++++--------- config/samples/v1beta1_verticadb.yaml | 6 +++--- pkg/vascontroller/subclusterresize_reconcile.go | 2 +- 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 7b58268df..1c79eac43 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -36,14 +36,14 @@ type VerticaAutoscalerSpec struct { // +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:Create","urn:alm:descriptor:com.tectonic.ui:select:Pod","urn:alm:descriptor:com.tectonic.ui:select:Subcluster"} + // +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: - // - 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. // - 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 @@ -73,7 +73,7 @@ type VerticaAutoscalerSpec struct { // 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 by the horizontal autoscaler. + // via the /scale subresource. TargetSize int32 `json:"targetSize"` // +operator-sdk:csv:customresourcedefinitions:type=spec diff --git a/api/v1beta1/verticadb_webhook.go b/api/v1beta1/verticadb_webhook.go index 97480d06b..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 @@ -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/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml index 6db953253..74e1677ff 100644 --- a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml @@ -34,16 +34,15 @@ spec: x-descriptors: - urn:alm:descriptor:com.tectonic.ui:hidden - description: 'This defines how the scaling will happen. This can be one of - the following: - 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. - 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.' + 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:Create - 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 @@ -57,8 +56,7 @@ spec: - 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 - by the horizontal autoscaler. + will get initialized in the operator and then modified via the /scale subresource. displayName: Target Size path: targetSize x-descriptors: diff --git a/config/samples/v1beta1_verticadb.yaml b/config/samples/v1beta1_verticadb.yaml index c52a76868..014775b8b 100644 --- a/config/samples/v1beta1_verticadb.yaml +++ b/config/samples/v1beta1_verticadb.yaml @@ -23,9 +23,9 @@ spec: credentialSecret: s3-auth subclusters: - name: defaultsubcluster - # The CPU resource setting is here as a sample so that will work with the - # sample VerticaAutoscaler resource. The actual amount should be sized - # according to: + # 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: diff --git a/pkg/vascontroller/subclusterresize_reconcile.go b/pkg/vascontroller/subclusterresize_reconcile.go index e60966612..4065e2826 100644 --- a/pkg/vascontroller/subclusterresize_reconcile.go +++ b/pkg/vascontroller/subclusterresize_reconcile.go @@ -67,7 +67,7 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context, req * subclusters, totSize := s.Vdb.FindSubclusterForServiceName(s.Vas.Spec.ServiceName) if len(subclusters) == 0 { - s.VRec.EVRec.Eventf(s.Vas, corev1.EventTypeWarning, events.VerticaDBNotFound, + 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 From ecc542663d126ab0eafe816ebb2fe3764e8f30e3 Mon Sep 17 00:00:00 2001 From: spilchen Date: Fri, 8 Apr 2022 19:45:27 -0300 Subject: [PATCH 23/27] Minor e2e fixes (#196) A few minor changes to the e2e tests: - in online-upgrade-kill-transient, we occasionally see a test failure at step 45. We run a pod to check access to the subcluster. This can fail due to timing, so we will change it to use a job so that it restarts if access fails. Only if the access fails continuously will it fail the test - moved revivedb-1-node to the extra tests --- scripts/setup-kustomize.sh | 9 +++++ .../revivedb-1-node/00-assert.yaml | 0 .../revivedb-1-node/00-deploy-operator.yaml | 0 .../revivedb-1-node/01-assert.yaml | 0 .../revivedb-1-node/01-password-secret.yaml | 0 .../05-create-communal-creds.yaml | 0 .../revivedb-1-node/15-assert.yaml | 0 .../revivedb-1-node/15-create-db.yaml | 0 .../revivedb-1-node/20-delete-crd.yaml | 0 .../revivedb-1-node/20-errors.yaml | 0 .../revivedb-1-node/25-assert.yaml | 0 .../revivedb-1-node/25-revive.yaml | 0 .../revivedb-1-node/95-assert.yaml | 0 .../revivedb-1-node/95-delete-crd.yaml | 0 .../revivedb-1-node/95-errors.yaml | 0 .../revivedb-1-node/99-errors.yaml | 0 .../99-uninstall-operator.yaml | 0 .../revivedb-1-node/README.txt | 0 .../vdb-to-create/base/kustomization.yaml | 0 .../vdb-to-create/base/setup-vdb.yaml | 0 .../vdb-to-revive/base/kustomization.yaml | 0 .../vdb-to-revive/base/setup-vdb.yaml | 0 .../45-assert.yaml | 11 ++---- .../base/verify-vsql-access.yaml | 36 ++++++++++--------- 24 files changed, 31 insertions(+), 25 deletions(-) rename tests/{e2e => e2e-extra}/revivedb-1-node/00-assert.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/00-deploy-operator.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/01-assert.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/01-password-secret.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/05-create-communal-creds.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/15-assert.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/15-create-db.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/20-delete-crd.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/20-errors.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/25-assert.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/25-revive.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/95-assert.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/95-delete-crd.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/95-errors.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/99-errors.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/99-uninstall-operator.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/README.txt (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/vdb-to-create/base/kustomization.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/vdb-to-create/base/setup-vdb.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/vdb-to-revive/base/kustomization.yaml (100%) rename tests/{e2e => e2e-extra}/revivedb-1-node/vdb-to-revive/base/setup-vdb.yaml (100%) 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 From 1103d54340f269b6eb34f2a3993a786b1a3f0bd9 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Mon, 11 Apr 2022 10:27:46 -0300 Subject: [PATCH 24/27] Apply review comments --- api/v1beta1/verticaautoscaler_types.go | 14 --- cmd/operator/main.go | 93 +++++++++++-------- ...ler.go => refreshcurrentsize_reconcile.go} | 8 +- ...nciler.go => refreshselector_reconcile.go} | 9 +- .../subclusterresize_reconcile.go | 6 -- .../subclusterscale_reconcile.go | 6 -- .../subclusterscale_reconcile_test.go | 1 - .../verticaautoscaler_controller.go | 8 +- .../50-remove-last-scaled-subcluster.yaml | 7 -- 9 files changed, 65 insertions(+), 87 deletions(-) rename pkg/vascontroller/{vasstatus_reconciler.go => refreshcurrentsize_reconcile.go} (79%) rename pkg/vascontroller/{vasselector_reconciler.go => refreshselector_reconcile.go} (73%) diff --git a/api/v1beta1/verticaautoscaler_types.go b/api/v1beta1/verticaautoscaler_types.go index 1c79eac43..e1a36985d 100644 --- a/api/v1beta1/verticaautoscaler_types.go +++ b/api/v1beta1/verticaautoscaler_types.go @@ -75,15 +75,6 @@ type VerticaAutoscalerSpec struct { // left as zero. It will get initialized in the operator and then modified // via the /scale subresource. TargetSize int32 `json:"targetSize"` - - // +operator-sdk:csv:customresourcedefinitions:type=spec - // +kubebuilder:validation:Optional - // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:hidden" - // 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. - AllowScaleToZero bool `json:"allowScaleToZero,omitempty"` } type ScalingGranularityType string @@ -203,11 +194,6 @@ func MakeVAS() *VerticaAutoscaler { } } -// IsScalingAllowed returns true if scaling should proceed based on the targetSize -func (v *VerticaAutoscaler) IsScalingAllowed() bool { - return v.Spec.TargetSize > 0 || v.Spec.AllowScaleToZero -} - // 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/cmd/operator/main.go b/cmd/operator/main.go index 5e76fd44d..751881775 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -36,8 +36,10 @@ 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" @@ -222,6 +224,55 @@ 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 := (&controllers.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 := (&vascontroller.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) + } + //+kubebuilder:scaffold:builder +} + +// addWebhooktsToManager 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() @@ -266,47 +317,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: flagArgs.ServiceAccountName, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "VerticaDB") - os.Exit(1) - } - - if err = (&vascontroller.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) - } - //+kubebuilder:scaffold:builder - + 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) - } - if err = (&verticacomv1beta1.VerticaAutoscaler{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "VerticaAutoscaler") - os.Exit(1) - } + addWebhooksToManager(mgr) } if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/pkg/vascontroller/vasstatus_reconciler.go b/pkg/vascontroller/refreshcurrentsize_reconcile.go similarity index 79% rename from pkg/vascontroller/vasstatus_reconciler.go rename to pkg/vascontroller/refreshcurrentsize_reconcile.go index dcbfa7e4a..6c5ff81cc 100644 --- a/pkg/vascontroller/vasstatus_reconciler.go +++ b/pkg/vascontroller/refreshcurrentsize_reconcile.go @@ -24,17 +24,17 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ) -type VASStatusReconciler struct { +type RefreshCurrentSizeReconciler struct { VRec *VerticaAutoscalerReconciler Vas *vapi.VerticaAutoscaler } -func MakeVASStatusReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { - return &VASStatusReconciler{VRec: v, Vas: vas} +func MakeRefreshCurrentSizeReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { + return &RefreshCurrentSizeReconciler{VRec: v, Vas: vas} } // Reconcile will handle updating the currentSize in the status field -func (v *VASStatusReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { +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 diff --git a/pkg/vascontroller/vasselector_reconciler.go b/pkg/vascontroller/refreshselector_reconcile.go similarity index 73% rename from pkg/vascontroller/vasselector_reconciler.go rename to pkg/vascontroller/refreshselector_reconcile.go index 08e11d848..9187ddd17 100644 --- a/pkg/vascontroller/vasselector_reconciler.go +++ b/pkg/vascontroller/refreshselector_reconcile.go @@ -23,17 +23,16 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ) -type SelectorReconciler struct { +type RefreshSelectorReconciler struct { VRec *VerticaAutoscalerReconciler Vas *vapi.VerticaAutoscaler } -// MakeSelectorReconciler will create a SelectorReconciler object and return it -func MakeSelectorReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { - return &SelectorReconciler{VRec: v, Vas: vas} +func MakeRefreshSelectorReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { + return &RefreshSelectorReconciler{VRec: v, Vas: vas} } // Reconcile will handle updating the selector in the status portion of a VerticaAutoscaler -func (v *SelectorReconciler) Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) { +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/vascontroller/subclusterresize_reconcile.go b/pkg/vascontroller/subclusterresize_reconcile.go index 4065e2826..5f910a9fd 100644 --- a/pkg/vascontroller/subclusterresize_reconcile.go +++ b/pkg/vascontroller/subclusterresize_reconcile.go @@ -45,12 +45,6 @@ func (s *SubclusterResizeReconciler) Reconcile(ctx context.Context, req *ctrl.Re return ctrl.Result{}, nil } - if !s.Vas.IsScalingAllowed() { - s.VRec.Log.Info("Scaling isn't allowed yet", "targetSize", s.Vas.Spec.TargetSize, - "allowScaleToZero", s.Vas.Spec.AllowScaleToZero) - return ctrl.Result{}, nil - } - return s.resizeSubcluster(ctx, req) } diff --git a/pkg/vascontroller/subclusterscale_reconcile.go b/pkg/vascontroller/subclusterscale_reconcile.go index d5f54f552..86ea33c64 100644 --- a/pkg/vascontroller/subclusterscale_reconcile.go +++ b/pkg/vascontroller/subclusterscale_reconcile.go @@ -45,12 +45,6 @@ func (s *SubclusterScaleReconciler) Reconcile(ctx context.Context, req *ctrl.Req return ctrl.Result{}, nil } - if !s.Vas.IsScalingAllowed() { - s.VRec.Log.Info("Scaling isn't allowed yet", "targetSize", s.Vas.Spec.TargetSize, - "allowScaleToZero", s.Vas.Spec.AllowScaleToZero) - return ctrl.Result{}, nil - } - return s.scaleSubcluster(ctx, req) } diff --git a/pkg/vascontroller/subclusterscale_reconcile_test.go b/pkg/vascontroller/subclusterscale_reconcile_test.go index f82fe3c80..29219129d 100644 --- a/pkg/vascontroller/subclusterscale_reconcile_test.go +++ b/pkg/vascontroller/subclusterscale_reconcile_test.go @@ -147,7 +147,6 @@ var _ = Describe("subclusterscale_reconcile", func() { vasName := vapi.MakeVASName() Expect(k8sClient.Get(ctx, vasName, vas)).Should(Succeed()) - vas.Spec.AllowScaleToZero = true vas.Spec.TargetSize = 0 Expect(k8sClient.Update(ctx, vas)).Should(Succeed()) diff --git a/pkg/vascontroller/verticaautoscaler_controller.go b/pkg/vascontroller/verticaautoscaler_controller.go index 6d2c924d1..293806e47 100644 --- a/pkg/vascontroller/verticaautoscaler_controller.go +++ b/pkg/vascontroller/verticaautoscaler_controller.go @@ -73,13 +73,13 @@ func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Re // Initialize targetSize in new VerticaAutoscaler objects MakeTargetSizeInitializerReconciler(r, vas), // Update the currentSize in the status - MakeVASStatusReconciler(r, vas), - // Update the status portion of the VerticaAutoscaler - MakeSelectorReconciler(r, vas), + 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 granulariyt is Subcluster, this will create or delete + // If scaling granularity is Subcluster, this will create or delete // entire subcluster to match the targetSize. MakeSubclusterScaleReconciler(r, vas), } 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 index c48801ddd..3a0503cc8 100644 --- a/tests/e2e/autoscale-by-subcluster/50-remove-last-scaled-subcluster.yaml +++ b/tests/e2e/autoscale-by-subcluster/50-remove-last-scaled-subcluster.yaml @@ -11,13 +11,6 @@ # 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: - allowScaleToZero: true ---- apiVersion: kuttl.dev/v1beta1 kind: TestStep commands: From 56d77cb2dc12730ba2eb91d88917b0a56a4f8c29 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Mon, 11 Apr 2022 10:43:22 -0300 Subject: [PATCH 25/27] Move vas to its own subdir under controllers --- cmd/operator/main.go | 4 ++-- pkg/{vascontroller => controllers/vas}/actor.go | 0 pkg/{vascontroller => controllers/vas}/k8s.go | 0 .../vas}/refreshcurrentsize_reconcile.go | 0 .../vas}/refreshselector_reconcile.go | 0 .../vas}/subclusterresize_reconcile.go | 0 .../vas}/subclusterresize_reconcile_test.go | 0 .../vas}/subclusterscale_reconcile.go | 0 .../vas}/subclusterscale_reconcile_test.go | 0 pkg/{vascontroller => controllers/vas}/suite_test.go | 2 +- .../vas}/targetsizeinitializer_reconcile.go | 0 .../vas}/targetsizeinitializer_reconcile_test.go | 0 pkg/{vascontroller => controllers/vas}/vdbverify_reconcile.go | 0 .../vas}/verticaautoscaler_controller.go | 0 14 files changed, 3 insertions(+), 3 deletions(-) rename pkg/{vascontroller => controllers/vas}/actor.go (100%) rename pkg/{vascontroller => controllers/vas}/k8s.go (100%) rename pkg/{vascontroller => controllers/vas}/refreshcurrentsize_reconcile.go (100%) rename pkg/{vascontroller => controllers/vas}/refreshselector_reconcile.go (100%) rename pkg/{vascontroller => controllers/vas}/subclusterresize_reconcile.go (100%) rename pkg/{vascontroller => controllers/vas}/subclusterresize_reconcile_test.go (100%) rename pkg/{vascontroller => controllers/vas}/subclusterscale_reconcile.go (100%) rename pkg/{vascontroller => controllers/vas}/subclusterscale_reconcile_test.go (100%) rename pkg/{vascontroller => controllers/vas}/suite_test.go (96%) rename pkg/{vascontroller => controllers/vas}/targetsizeinitializer_reconcile.go (100%) rename pkg/{vascontroller => controllers/vas}/targetsizeinitializer_reconcile_test.go (100%) rename pkg/{vascontroller => controllers/vas}/vdbverify_reconcile.go (100%) rename pkg/{vascontroller => controllers/vas}/verticaautoscaler_controller.go (100%) diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 751881775..bcbdea807 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -44,7 +44,7 @@ import ( 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/vascontroller" + vas "github.com/vertica/vertica-kubernetes/pkg/controllers/vas" //+kubebuilder:scaffold:imports ) @@ -239,7 +239,7 @@ func addReconcilersToManager(mgr manager.Manager, restCfg *rest.Config, flagArgs os.Exit(1) } - if err := (&vascontroller.VerticaAutoscalerReconciler{ + if err := (&vas.VerticaAutoscalerReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), EVRec: mgr.GetEventRecorderFor(builder.OperatorName), diff --git a/pkg/vascontroller/actor.go b/pkg/controllers/vas/actor.go similarity index 100% rename from pkg/vascontroller/actor.go rename to pkg/controllers/vas/actor.go diff --git a/pkg/vascontroller/k8s.go b/pkg/controllers/vas/k8s.go similarity index 100% rename from pkg/vascontroller/k8s.go rename to pkg/controllers/vas/k8s.go diff --git a/pkg/vascontroller/refreshcurrentsize_reconcile.go b/pkg/controllers/vas/refreshcurrentsize_reconcile.go similarity index 100% rename from pkg/vascontroller/refreshcurrentsize_reconcile.go rename to pkg/controllers/vas/refreshcurrentsize_reconcile.go diff --git a/pkg/vascontroller/refreshselector_reconcile.go b/pkg/controllers/vas/refreshselector_reconcile.go similarity index 100% rename from pkg/vascontroller/refreshselector_reconcile.go rename to pkg/controllers/vas/refreshselector_reconcile.go diff --git a/pkg/vascontroller/subclusterresize_reconcile.go b/pkg/controllers/vas/subclusterresize_reconcile.go similarity index 100% rename from pkg/vascontroller/subclusterresize_reconcile.go rename to pkg/controllers/vas/subclusterresize_reconcile.go diff --git a/pkg/vascontroller/subclusterresize_reconcile_test.go b/pkg/controllers/vas/subclusterresize_reconcile_test.go similarity index 100% rename from pkg/vascontroller/subclusterresize_reconcile_test.go rename to pkg/controllers/vas/subclusterresize_reconcile_test.go diff --git a/pkg/vascontroller/subclusterscale_reconcile.go b/pkg/controllers/vas/subclusterscale_reconcile.go similarity index 100% rename from pkg/vascontroller/subclusterscale_reconcile.go rename to pkg/controllers/vas/subclusterscale_reconcile.go diff --git a/pkg/vascontroller/subclusterscale_reconcile_test.go b/pkg/controllers/vas/subclusterscale_reconcile_test.go similarity index 100% rename from pkg/vascontroller/subclusterscale_reconcile_test.go rename to pkg/controllers/vas/subclusterscale_reconcile_test.go diff --git a/pkg/vascontroller/suite_test.go b/pkg/controllers/vas/suite_test.go similarity index 96% rename from pkg/vascontroller/suite_test.go rename to pkg/controllers/vas/suite_test.go index 912e7c371..631bc3120 100644 --- a/pkg/vascontroller/suite_test.go +++ b/pkg/controllers/vas/suite_test.go @@ -46,7 +46,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, } diff --git a/pkg/vascontroller/targetsizeinitializer_reconcile.go b/pkg/controllers/vas/targetsizeinitializer_reconcile.go similarity index 100% rename from pkg/vascontroller/targetsizeinitializer_reconcile.go rename to pkg/controllers/vas/targetsizeinitializer_reconcile.go diff --git a/pkg/vascontroller/targetsizeinitializer_reconcile_test.go b/pkg/controllers/vas/targetsizeinitializer_reconcile_test.go similarity index 100% rename from pkg/vascontroller/targetsizeinitializer_reconcile_test.go rename to pkg/controllers/vas/targetsizeinitializer_reconcile_test.go diff --git a/pkg/vascontroller/vdbverify_reconcile.go b/pkg/controllers/vas/vdbverify_reconcile.go similarity index 100% rename from pkg/vascontroller/vdbverify_reconcile.go rename to pkg/controllers/vas/vdbverify_reconcile.go diff --git a/pkg/vascontroller/verticaautoscaler_controller.go b/pkg/controllers/vas/verticaautoscaler_controller.go similarity index 100% rename from pkg/vascontroller/verticaautoscaler_controller.go rename to pkg/controllers/vas/verticaautoscaler_controller.go From a230daa4e9dbd3750ba4f82baee2ae4bd6b30478 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Mon, 11 Apr 2022 11:04:50 -0300 Subject: [PATCH 26/27] Move VerticaDB reconciler to controllers/vdb --- cmd/operator/main.go | 4 +- pkg/controllers/actor.go | 50 ------------- pkg/controllers/vas/actor.go | 28 -------- .../vas/refreshcurrentsize_reconcile.go | 3 +- .../vas/refreshselector_reconcile.go | 3 +- .../vas/subclusterresize_reconcile.go | 3 +- .../vas/subclusterscale_reconcile.go | 3 +- pkg/controllers/vas/suite_test.go | 2 +- .../vas/targetsizeinitializer_reconcile.go | 3 +- pkg/controllers/vas/vdbverify_reconcile.go | 3 +- .../vas/verticaautoscaler_controller.go | 3 +- pkg/controllers/vdb/actor.go | 72 +++++++++++++++++++ pkg/controllers/{ => vdb}/at.go | 2 +- pkg/controllers/{ => vdb}/at_test.go | 2 +- .../{ => vdb}/clientroutinglabel_reconcile.go | 5 +- .../clientroutinglabel_reconcile_test.go | 2 +- .../{ => vdb}/createdb_reconcile.go | 5 +- .../{ => vdb}/createdb_reconcile_test.go | 2 +- .../{ => vdb}/dbaddnode_reconcile.go | 5 +- .../{ => vdb}/dbaddnode_reconcile_test.go | 2 +- .../{ => vdb}/dbaddsubcluster_reconcile.go | 5 +- .../dbaddsubcluster_reconcile_test.go | 2 +- .../{ => vdb}/dbremovenode_reconcile.go | 5 +- .../{ => vdb}/dbremovenode_reconcile_test.go | 2 +- .../{ => vdb}/dbremovesubcluster_reconcile.go | 5 +- .../dbremovesubcluster_reconcile_test.go | 2 +- .../{ => vdb}/drainnode_reconcile.go | 5 +- .../{ => vdb}/drainnode_reconcile_test.go | 2 +- pkg/controllers/{ => vdb}/init_db.go | 2 +- pkg/controllers/{ => vdb}/init_db_test.go | 2 +- .../{ => vdb}/install_reconcile.go | 5 +- .../{ => vdb}/install_reconcile_test.go | 2 +- pkg/controllers/{ => vdb}/k8s.go | 2 +- pkg/controllers/{ => vdb}/k8s_test.go | 2 +- pkg/controllers/{ => vdb}/obj_reconcile.go | 5 +- .../{ => vdb}/obj_reconcile_test.go | 2 +- .../{ => vdb}/offlineupgrade_reconcile.go | 5 +- .../offlineupgrade_reconcile_test.go | 2 +- .../{ => vdb}/onlineupgrade_reconcile_test.go | 2 +- .../{ => vdb}/onlineupgrade_reconciler.go | 7 +- pkg/controllers/{ => vdb}/paths.go | 2 +- pkg/controllers/{ => vdb}/podfacts.go | 2 +- pkg/controllers/{ => vdb}/podfacts_test.go | 2 +- .../{ => vdb}/rebalanceshards_reconcile.go | 5 +- .../rebalanceshards_reconciler_test.go | 2 +- .../{ => vdb}/restart_reconcile.go | 5 +- .../{ => vdb}/restart_reconciler_test.go | 2 +- .../{ => vdb}/revivedb_reconcile.go | 5 +- .../{ => vdb}/revivedb_reconcile_test.go | 2 +- pkg/controllers/{ => vdb}/status_reconcile.go | 5 +- .../{ => vdb}/status_reconcile_test.go | 2 +- pkg/controllers/{ => vdb}/suite_test.go | 6 +- .../{ => vdb}/uninstall_reconcile.go | 5 +- .../{ => vdb}/uninstall_reconcile_test.go | 2 +- pkg/controllers/{ => vdb}/upgrade.go | 2 +- pkg/controllers/{ => vdb}/upgrade_test.go | 2 +- .../upgradeoperator120_reconciler.go | 5 +- .../upgradeoperator120_reconciler_test.go | 2 +- .../{ => vdb}/version_reconciler.go | 5 +- .../{ => vdb}/version_reconciler_test.go | 2 +- .../{ => vdb}/verticadb_controller.go | 7 +- 61 files changed, 180 insertions(+), 160 deletions(-) delete mode 100644 pkg/controllers/vas/actor.go create mode 100644 pkg/controllers/vdb/actor.go rename pkg/controllers/{ => vdb}/at.go (99%) rename pkg/controllers/{ => vdb}/at_test.go (98%) rename pkg/controllers/{ => vdb}/clientroutinglabel_reconcile.go (97%) rename pkg/controllers/{ => vdb}/clientroutinglabel_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/createdb_reconcile.go (98%) rename pkg/controllers/{ => vdb}/createdb_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/dbaddnode_reconcile.go (98%) rename pkg/controllers/{ => vdb}/dbaddnode_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/dbaddsubcluster_reconcile.go (98%) rename pkg/controllers/{ => vdb}/dbaddsubcluster_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/dbremovenode_reconcile.go (98%) rename pkg/controllers/{ => vdb}/dbremovenode_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/dbremovesubcluster_reconcile.go (98%) rename pkg/controllers/{ => vdb}/dbremovesubcluster_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/drainnode_reconcile.go (96%) rename pkg/controllers/{ => vdb}/drainnode_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/init_db.go (99%) rename pkg/controllers/{ => vdb}/init_db_test.go (99%) rename pkg/controllers/{ => vdb}/install_reconcile.go (99%) rename pkg/controllers/{ => vdb}/install_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/k8s.go (99%) rename pkg/controllers/{ => vdb}/k8s_test.go (99%) rename pkg/controllers/{ => vdb}/obj_reconcile.go (99%) rename pkg/controllers/{ => vdb}/obj_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/offlineupgrade_reconcile.go (99%) rename pkg/controllers/{ => vdb}/offlineupgrade_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/onlineupgrade_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/onlineupgrade_reconciler.go (99%) rename pkg/controllers/{ => vdb}/paths.go (99%) rename pkg/controllers/{ => vdb}/podfacts.go (99%) rename pkg/controllers/{ => vdb}/podfacts_test.go (99%) rename pkg/controllers/{ => vdb}/rebalanceshards_reconcile.go (97%) rename pkg/controllers/{ => vdb}/rebalanceshards_reconciler_test.go (99%) rename pkg/controllers/{ => vdb}/restart_reconcile.go (99%) rename pkg/controllers/{ => vdb}/restart_reconciler_test.go (99%) rename pkg/controllers/{ => vdb}/revivedb_reconcile.go (98%) rename pkg/controllers/{ => vdb}/revivedb_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/status_reconcile.go (97%) rename pkg/controllers/{ => vdb}/status_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/suite_test.go (98%) rename pkg/controllers/{ => vdb}/uninstall_reconcile.go (98%) rename pkg/controllers/{ => vdb}/uninstall_reconcile_test.go (99%) rename pkg/controllers/{ => vdb}/upgrade.go (99%) rename pkg/controllers/{ => vdb}/upgrade_test.go (99%) rename pkg/controllers/{ => vdb}/upgradeoperator120_reconciler.go (95%) rename pkg/controllers/{ => vdb}/upgradeoperator120_reconciler_test.go (99%) rename pkg/controllers/{ => vdb}/version_reconciler.go (97%) rename pkg/controllers/{ => vdb}/version_reconciler_test.go (99%) rename pkg/controllers/{ => vdb}/verticadb_controller.go (98%) diff --git a/cmd/operator/main.go b/cmd/operator/main.go index bcbdea807..1f23ef1cf 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -43,8 +43,8 @@ import ( verticacomv1beta1 "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" - "github.com/vertica/vertica-kubernetes/pkg/controllers" vas "github.com/vertica/vertica-kubernetes/pkg/controllers/vas" + vdb "github.com/vertica/vertica-kubernetes/pkg/controllers/vdb" //+kubebuilder:scaffold:imports ) @@ -227,7 +227,7 @@ func getLogger(logArgs Logging) *zap.Logger { // 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 := (&controllers.VerticaDBReconciler{ + if err := (&vdb.VerticaDBReconciler{ Client: mgr.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("VerticaDB"), Scheme: mgr.GetScheme(), 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/vas/actor.go b/pkg/controllers/vas/actor.go deleted file mode 100644 index 37f2fc80a..000000000 --- a/pkg/controllers/vas/actor.go +++ /dev/null @@ -1,28 +0,0 @@ -/* - (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 vascontroller - -import ( - "context" - - ctrl "sigs.k8s.io/controller-runtime" -) - -// ReconcileActor is an interface that handles one part of the entire -// reconciliation process. -type ReconcileActor interface { - Reconcile(ctx context.Context, req *ctrl.Request) (ctrl.Result, error) -} diff --git a/pkg/controllers/vas/refreshcurrentsize_reconcile.go b/pkg/controllers/vas/refreshcurrentsize_reconcile.go index 6c5ff81cc..0f1307047 100644 --- a/pkg/controllers/vas/refreshcurrentsize_reconcile.go +++ b/pkg/controllers/vas/refreshcurrentsize_reconcile.go @@ -19,6 +19,7 @@ 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" @@ -29,7 +30,7 @@ type RefreshCurrentSizeReconciler struct { Vas *vapi.VerticaAutoscaler } -func MakeRefreshCurrentSizeReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { +func MakeRefreshCurrentSizeReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { return &RefreshCurrentSizeReconciler{VRec: v, Vas: vas} } diff --git a/pkg/controllers/vas/refreshselector_reconcile.go b/pkg/controllers/vas/refreshselector_reconcile.go index 9187ddd17..3981870fd 100644 --- a/pkg/controllers/vas/refreshselector_reconcile.go +++ b/pkg/controllers/vas/refreshselector_reconcile.go @@ -19,6 +19,7 @@ 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" ) @@ -28,7 +29,7 @@ type RefreshSelectorReconciler struct { Vas *vapi.VerticaAutoscaler } -func MakeRefreshSelectorReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { +func MakeRefreshSelectorReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { return &RefreshSelectorReconciler{VRec: v, Vas: vas} } diff --git a/pkg/controllers/vas/subclusterresize_reconcile.go b/pkg/controllers/vas/subclusterresize_reconcile.go index 5f910a9fd..dfeffa71e 100644 --- a/pkg/controllers/vas/subclusterresize_reconcile.go +++ b/pkg/controllers/vas/subclusterresize_reconcile.go @@ -19,6 +19,7 @@ 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" @@ -35,7 +36,7 @@ type SubclusterResizeReconciler struct { Vdb *vapi.VerticaDB } -func MakeSubclusterResizeReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { +func MakeSubclusterResizeReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { return &SubclusterResizeReconciler{VRec: r, Vas: vas, Vdb: &vapi.VerticaDB{}} } diff --git a/pkg/controllers/vas/subclusterscale_reconcile.go b/pkg/controllers/vas/subclusterscale_reconcile.go index 86ea33c64..45af3a6ea 100644 --- a/pkg/controllers/vas/subclusterscale_reconcile.go +++ b/pkg/controllers/vas/subclusterscale_reconcile.go @@ -20,6 +20,7 @@ import ( "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" @@ -35,7 +36,7 @@ type SubclusterScaleReconciler struct { Vdb *vapi.VerticaDB } -func MakeSubclusterScaleReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { +func MakeSubclusterScaleReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { return &SubclusterScaleReconciler{VRec: r, Vas: vas, Vdb: &vapi.VerticaDB{}} } diff --git a/pkg/controllers/vas/suite_test.go b/pkg/controllers/vas/suite_test.go index 631bc3120..817457ba4 100644 --- a/pkg/controllers/vas/suite_test.go +++ b/pkg/controllers/vas/suite_test.go @@ -85,6 +85,6 @@ func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) RunSpecsWithDefaultAndCustomReporters(t, - "vascontroller Suite", + "vas Suite", []Reporter{printer.NewlineReporter{}}) } diff --git a/pkg/controllers/vas/targetsizeinitializer_reconcile.go b/pkg/controllers/vas/targetsizeinitializer_reconcile.go index 2a3e4a6c7..67907db0c 100644 --- a/pkg/controllers/vas/targetsizeinitializer_reconcile.go +++ b/pkg/controllers/vas/targetsizeinitializer_reconcile.go @@ -19,6 +19,7 @@ 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" @@ -31,7 +32,7 @@ type TargetSizeInitializerReconciler struct { Vas *vapi.VerticaAutoscaler } -func MakeTargetSizeInitializerReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { +func MakeTargetSizeInitializerReconciler(v *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { return &TargetSizeInitializerReconciler{VRec: v, Vas: vas} } diff --git a/pkg/controllers/vas/vdbverify_reconcile.go b/pkg/controllers/vas/vdbverify_reconcile.go index f61e94fdc..e1b0f6f0f 100644 --- a/pkg/controllers/vas/vdbverify_reconcile.go +++ b/pkg/controllers/vas/vdbverify_reconcile.go @@ -19,6 +19,7 @@ import ( "context" vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" ctrl "sigs.k8s.io/controller-runtime" ) @@ -29,7 +30,7 @@ type VDBVerifyReconciler struct { Vdb *vapi.VerticaDB } -func MakeVDBVerifyReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) ReconcileActor { +func MakeVDBVerifyReconciler(r *VerticaAutoscalerReconciler, vas *vapi.VerticaAutoscaler) controllers.ReconcileActor { return &VDBVerifyReconciler{VRec: r, Vas: vas, Vdb: &vapi.VerticaDB{}} } diff --git a/pkg/controllers/vas/verticaautoscaler_controller.go b/pkg/controllers/vas/verticaautoscaler_controller.go index 293806e47..2a8dbe71e 100644 --- a/pkg/controllers/vas/verticaautoscaler_controller.go +++ b/pkg/controllers/vas/verticaautoscaler_controller.go @@ -28,6 +28,7 @@ import ( "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" ) @@ -67,7 +68,7 @@ func (r *VerticaAutoscalerReconciler) Reconcile(ctx context.Context, req ctrl.Re } // The actors that will be applied, in sequence, to reconcile a vas. - actors := []ReconcileActor{ + actors := []controllers.ReconcileActor{ // Sanity check to make sure the VerticaDB referenced in vas actually exists. MakeVDBVerifyReconciler(r, vas), // Initialize targetSize in new VerticaAutoscaler objects 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 f3406ad6d..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" 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/k8s.go b/pkg/controllers/vdb/k8s.go similarity index 99% rename from pkg/controllers/k8s.go rename to pkg/controllers/vdb/k8s.go index 6c015ba9b..d781a7416 100644 --- a/pkg/controllers/k8s.go +++ b/pkg/controllers/vdb/k8s.go @@ -13,7 +13,7 @@ limitations under the License. */ -package controllers +package vdb import ( "context" 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 99% rename from pkg/controllers/restart_reconcile.go rename to pkg/controllers/vdb/restart_reconcile.go index e8a438b74..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,6 +25,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" @@ -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} } 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 97% rename from pkg/controllers/status_reconcile.go rename to pkg/controllers/vdb/status_reconcile.go index 36ec15b94..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,6 +21,7 @@ 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/vdbstatus" @@ -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} } 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 99% rename from pkg/controllers/upgrade.go rename to pkg/controllers/vdb/upgrade.go index c8030e1d7..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" 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 From 30b2b65a4cf3a000fa704e9ec0d7e4b255abdced Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Mon, 11 Apr 2022 16:50:18 -0300 Subject: [PATCH 27/27] Address review comments --- cmd/operator/main.go | 4 ++-- pkg/controllers/vas/k8s.go | 2 +- pkg/controllers/vas/refreshcurrentsize_reconcile.go | 3 ++- pkg/controllers/vas/refreshselector_reconcile.go | 4 +++- pkg/controllers/vas/subclusterresize_reconcile.go | 3 ++- pkg/controllers/vas/subclusterresize_reconcile_test.go | 2 +- pkg/controllers/vas/subclusterscale_reconcile.go | 7 ++++--- pkg/controllers/vas/subclusterscale_reconcile_test.go | 2 +- pkg/controllers/vas/suite_test.go | 2 +- pkg/controllers/vas/targetsizeinitializer_reconcile.go | 2 +- .../vas/targetsizeinitializer_reconcile_test.go | 2 +- pkg/controllers/vas/vdbverify_reconcile.go | 2 +- pkg/controllers/vas/verticaautoscaler_controller.go | 2 +- 13 files changed, 21 insertions(+), 16 deletions(-) diff --git a/cmd/operator/main.go b/cmd/operator/main.go index 1f23ef1cf..746d90cb6 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -43,8 +43,8 @@ import ( verticacomv1beta1 "github.com/vertica/vertica-kubernetes/api/v1beta1" "github.com/vertica/vertica-kubernetes/pkg/builder" - vas "github.com/vertica/vertica-kubernetes/pkg/controllers/vas" - vdb "github.com/vertica/vertica-kubernetes/pkg/controllers/vdb" + "github.com/vertica/vertica-kubernetes/pkg/controllers/vas" + "github.com/vertica/vertica-kubernetes/pkg/controllers/vdb" //+kubebuilder:scaffold:imports ) diff --git a/pkg/controllers/vas/k8s.go b/pkg/controllers/vas/k8s.go index a4cfb9813..d81e76da2 100644 --- a/pkg/controllers/vas/k8s.go +++ b/pkg/controllers/vas/k8s.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" diff --git a/pkg/controllers/vas/refreshcurrentsize_reconcile.go b/pkg/controllers/vas/refreshcurrentsize_reconcile.go index 0f1307047..475f07d90 100644 --- a/pkg/controllers/vas/refreshcurrentsize_reconcile.go +++ b/pkg/controllers/vas/refreshcurrentsize_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" @@ -25,6 +25,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ) +// RefreshCurrentSizeReconciler will refresh the currentSize status field in the CR. type RefreshCurrentSizeReconciler struct { VRec *VerticaAutoscalerReconciler Vas *vapi.VerticaAutoscaler diff --git a/pkg/controllers/vas/refreshselector_reconcile.go b/pkg/controllers/vas/refreshselector_reconcile.go index 3981870fd..0b663e1ed 100644 --- a/pkg/controllers/vas/refreshselector_reconcile.go +++ b/pkg/controllers/vas/refreshselector_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" @@ -24,6 +24,8 @@ import ( 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 diff --git a/pkg/controllers/vas/subclusterresize_reconcile.go b/pkg/controllers/vas/subclusterresize_reconcile.go index dfeffa71e..c6a0ee066 100644 --- a/pkg/controllers/vas/subclusterresize_reconcile.go +++ b/pkg/controllers/vas/subclusterresize_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" @@ -54,6 +54,7 @@ func (s *SubclusterResizeReconciler) resizeSubcluster(ctx context.Context, req * 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 diff --git a/pkg/controllers/vas/subclusterresize_reconcile_test.go b/pkg/controllers/vas/subclusterresize_reconcile_test.go index e2606dd93..a02e61024 100644 --- a/pkg/controllers/vas/subclusterresize_reconcile_test.go +++ b/pkg/controllers/vas/subclusterresize_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" diff --git a/pkg/controllers/vas/subclusterscale_reconcile.go b/pkg/controllers/vas/subclusterscale_reconcile.go index 45af3a6ea..22cf9e7ae 100644 --- a/pkg/controllers/vas/subclusterscale_reconcile.go +++ b/pkg/controllers/vas/subclusterscale_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" @@ -55,6 +55,7 @@ func (s *SubclusterScaleReconciler) scaleSubcluster(ctx context.Context, req *ct 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 @@ -117,7 +118,7 @@ func (s *SubclusterScaleReconciler) considerRemovingSubclusters(podsToRemove int // considerAddingSubclusters will grow the Vdb by adding new subclusters. // Changes are made in-place in s.Vdb func (s *SubclusterScaleReconciler) considerAddingSubclusters(newPodsNeeded int32) bool { - origSize := len(s.Vdb.Spec.Subclusters) + origNumSubclusters := len(s.Vdb.Spec.Subclusters) scMap := s.Vdb.GenSubclusterMap() newScSize, ok := s.calcNextSubclusterSize(scMap) if !ok { @@ -130,7 +131,7 @@ func (s *SubclusterScaleReconciler) considerAddingSubclusters(newPodsNeeded int3 newPodsNeeded -= newSc.Size s.VRec.Log.Info("Adding subcluster to VerticaDB", "VerticaDB", s.Vdb.Name, "Subcluster", newSc.Name, "Size", newSc.Size) } - return origSize != len(s.Vdb.Spec.Subclusters) + return origNumSubclusters != len(s.Vdb.Spec.Subclusters) } // genNextSubclusterName will come up with a unique name to give a new subcluster diff --git a/pkg/controllers/vas/subclusterscale_reconcile_test.go b/pkg/controllers/vas/subclusterscale_reconcile_test.go index 29219129d..c20f5c17c 100644 --- a/pkg/controllers/vas/subclusterscale_reconcile_test.go +++ b/pkg/controllers/vas/subclusterscale_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" diff --git a/pkg/controllers/vas/suite_test.go b/pkg/controllers/vas/suite_test.go index 817457ba4..727a3147f 100644 --- a/pkg/controllers/vas/suite_test.go +++ b/pkg/controllers/vas/suite_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "path/filepath" diff --git a/pkg/controllers/vas/targetsizeinitializer_reconcile.go b/pkg/controllers/vas/targetsizeinitializer_reconcile.go index 67907db0c..53d2c3592 100644 --- a/pkg/controllers/vas/targetsizeinitializer_reconcile.go +++ b/pkg/controllers/vas/targetsizeinitializer_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" diff --git a/pkg/controllers/vas/targetsizeinitializer_reconcile_test.go b/pkg/controllers/vas/targetsizeinitializer_reconcile_test.go index 7cb9b8c5f..a37a725bb 100644 --- a/pkg/controllers/vas/targetsizeinitializer_reconcile_test.go +++ b/pkg/controllers/vas/targetsizeinitializer_reconcile_test.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" diff --git a/pkg/controllers/vas/vdbverify_reconcile.go b/pkg/controllers/vas/vdbverify_reconcile.go index e1b0f6f0f..15d445a83 100644 --- a/pkg/controllers/vas/vdbverify_reconcile.go +++ b/pkg/controllers/vas/vdbverify_reconcile.go @@ -13,7 +13,7 @@ limitations under the License. */ -package vascontroller +package vas import ( "context" diff --git a/pkg/controllers/vas/verticaautoscaler_controller.go b/pkg/controllers/vas/verticaautoscaler_controller.go index 2a8dbe71e..414fc5343 100644 --- a/pkg/controllers/vas/verticaautoscaler_controller.go +++ b/pkg/controllers/vas/verticaautoscaler_controller.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package vascontroller +package vas import ( "context"