From 2abd8f18ee91b30efbda68f9162fd58a101d5288 Mon Sep 17 00:00:00 2001 From: chinhtranvan <47764275+chinhtranvan@users.noreply.github.com> Date: Wed, 20 Dec 2023 13:03:23 -0600 Subject: [PATCH] Add empty controller and API for VerticaRestorePoints (#643) This PR build out the stub for an empty controller to handle the VerticaRestorePointsQuery API. It does not include a webhook, as there are no defined rules for transitioning the Custom Resource (CR), given that the spec portion contains only two fields. The operator can observe the new API, initiate a reconciliation iteration, and take no action, as we have set nil for the actors during this implementation phase --------- Co-authored-by: Matt Spilchen --- PROJECT | 11 +- api/v1beta1/groupversion_info.go | 14 ++- .../verticarestorepointsquery_types.go | 111 ++++++++++++++++++ cmd/operator/main.go | 16 ++- config/crd/kustomization.yaml | 2 + ...ection_in_verticarestorepointsqueries.yaml | 7 ++ ...ebhook_in_verticarestorepointsqueries.yaml | 8 ++ config/default/manager_auth_proxy_patch.yaml | 1 + ...ticadb-operator.clusterserviceversion.yaml | 83 ++++++++----- ...verticarestorepointsquery_editor_role.yaml | 31 +++++ ...verticarestorepointsquery_viewer_role.yaml | 27 +++++ config/samples/kustomization.yaml | 1 + .../v1beta1_verticarestorepointsquery.yaml | 13 ++ helm-charts/verticadb-operator/README.md | 1 + .../tests/kind-concurrency_test.yaml | 6 + helm-charts/verticadb-operator/values.yaml | 1 + pkg/controllers/vrpq/suite_test.go | 98 ++++++++++++++++ .../verticarestorepointsquery_controller.go | 110 +++++++++++++++++ ...rticarestorepointsquery_controller_test.go | 44 +++++++ pkg/opcfg/config.go | 34 +++--- scripts/config-transformer.sh | 1 + scripts/template-helm-chart.sh | 1 + .../e2e-leg-5/metrics-disabled/05-assert.yaml | 1 + .../e2e-leg-5/metrics-no-auth/05-assert.yaml | 1 + .../prometheus-service-monitor/10-assert.yaml | 1 + .../prometheus-service-monitor/20-assert.yaml | 1 + 26 files changed, 570 insertions(+), 55 deletions(-) create mode 100644 api/v1beta1/verticarestorepointsquery_types.go create mode 100644 config/crd/patches/cainjection_in_verticarestorepointsqueries.yaml create mode 100644 config/crd/patches/webhook_in_verticarestorepointsqueries.yaml create mode 100644 config/rbac/verticarestorepointsquery_editor_role.yaml create mode 100644 config/rbac/verticarestorepointsquery_viewer_role.yaml create mode 100644 config/samples/v1beta1_verticarestorepointsquery.yaml create mode 100644 pkg/controllers/vrpq/suite_test.go create mode 100644 pkg/controllers/vrpq/verticarestorepointsquery_controller.go create mode 100644 pkg/controllers/vrpq/verticarestorepointsquery_controller_test.go diff --git a/PROJECT b/PROJECT index 9a88bd70d..91bd6e8f1 100644 --- a/PROJECT +++ b/PROJECT @@ -13,7 +13,6 @@ repo: github.com/vertica/vertica-kubernetes resources: - api: crdVersion: v1 - namespaced: false controller: true domain: vertica.com kind: VerticaDB @@ -25,7 +24,6 @@ resources: webhookVersion: v1 - api: crdVersion: v1 - namespaced: false controller: true domain: vertica.com kind: VerticaAutoscaler @@ -37,7 +35,6 @@ resources: webhookVersion: v1 - api: crdVersion: v1 - namespaced: false controller: true domain: vertica.com kind: EventTrigger @@ -54,4 +51,12 @@ resources: kind: VerticaDB path: github.com/vertica/vertica-kubernetes/api/v1 version: v1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: vertica.com + kind: VerticaRestorePointsQuery + path: github.com/vertica/vertica-kubernetes/api/v1beta1 + version: v1beta1 version: "3" diff --git a/api/v1beta1/groupversion_info.go b/api/v1beta1/groupversion_info.go index 351bc4ee7..cb4abeb0f 100644 --- a/api/v1beta1/groupversion_info.go +++ b/api/v1beta1/groupversion_info.go @@ -27,9 +27,10 @@ const ( Group = "vertica.com" Version = "v1beta1" - VerticaDBKind = "VerticaDB" - VerticaAutoscalerKind = "VerticaAutoscaler" - EventTriggerKind = "EventTrigger" + VerticaDBKind = "VerticaDB" + VerticaAutoscalerKind = "VerticaAutoscaler" + EventTriggerKind = "EventTrigger" + RestorePointsQueryKind = "VerticaRestorePointsQuery" ) var ( @@ -43,7 +44,8 @@ var ( AddToScheme = SchemeBuilder.AddToScheme // All supported group/kind by this operator - GkVDB = schema.GroupKind{Group: Group, Kind: VerticaDBKind} - GkVAS = schema.GroupKind{Group: Group, Kind: VerticaAutoscalerKind} - GkET = schema.GroupKind{Group: Group, Kind: EventTriggerKind} + GkVDB = schema.GroupKind{Group: Group, Kind: VerticaDBKind} + GkVAS = schema.GroupKind{Group: Group, Kind: VerticaAutoscalerKind} + GkET = schema.GroupKind{Group: Group, Kind: EventTriggerKind} + GkVRPQ = schema.GroupKind{Group: Group, Kind: RestorePointsQueryKind} ) diff --git a/api/v1beta1/verticarestorepointsquery_types.go b/api/v1beta1/verticarestorepointsquery_types.go new file mode 100644 index 000000000..57de5b269 --- /dev/null +++ b/api/v1beta1/verticarestorepointsquery_types.go @@ -0,0 +1,111 @@ +/* +Copyright [2021-2023] Open Text. + +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" + "k8s.io/apimachinery/pkg/types" +) + +// VerticaRestorePointsQuerySpec defines the desired state of VerticaRestorePointsQuery +type VerticaRestorePointsQuerySpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // +kubebuilder:validation:Required + // +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 VerticaRestorePointsQuery is defined for. The + // VerticaDB object must exist in the same namespace as this object. + VerticaDBName string `json:"verticaDBName"` + + // +operator-sdk:csv:customresourcedefinitions:type=spec + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:text" + // Optional parameter that will limit the query to only restore points + // from this archvie + ArchiveName string `json:"archiveName"` +} + +const ( + archiveNm = "backup" // constants for test purposes +) + +// VerticaRestorePointsQueryStatus defines the observed state of VerticaRestorePointsQuery +type VerticaRestorePointsQueryStatus struct { + // +operator-sdk:csv:customresourcedefinitions:type=status + // RestorePoints used to list out the available restore points. + RestorePoints string `json:"restorePoints"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=vertica,shortName=vrpq +// +kubebuilder:subresource:status +// +operator-sdk:csv:customresourcedefinitions:resources={{Job,batch/v1,""}} + +// VerticaRestorePointsQuery is the Schema for the verticarestorepointsqueries API +type VerticaRestorePointsQuery struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VerticaRestorePointsQuerySpec `json:"spec,omitempty"` + Status VerticaRestorePointsQueryStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// VerticaRestorePointsQueryList contains a list of VerticaRestorePointsQuery +type VerticaRestorePointsQueryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VerticaRestorePointsQuery `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VerticaRestorePointsQuery{}, &VerticaRestorePointsQueryList{}) +} + +func (vrpq *VerticaRestorePointsQuery) ExtractNamespacedName() types.NamespacedName { + return types.NamespacedName{ + Name: vrpq.ObjectMeta.Name, + Namespace: vrpq.ObjectMeta.Namespace, + } +} + +func MakeSampleVrpqName() types.NamespacedName { + return types.NamespacedName{Name: "vrpq-sample", Namespace: "default"} +} + +// MakeVrpq will make an VerticaRestorePointsQuery for test purposes +func MakeVrpq() *VerticaRestorePointsQuery { + VDBNm := MakeVDBName() + nm := MakeSampleVrpqName() + return &VerticaRestorePointsQuery{ + TypeMeta: metav1.TypeMeta{ + APIVersion: GroupVersion.String(), + Kind: RestorePointsQueryKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: nm.Name, + Namespace: nm.Namespace, + UID: "zxcvbn-ghi-lkm", + }, + Spec: VerticaRestorePointsQuerySpec{ + VerticaDBName: VDBNm.Name, + ArchiveName: archiveNm, + }, + } +} diff --git a/cmd/operator/main.go b/cmd/operator/main.go index f694ecd1f..178232918 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -44,9 +44,11 @@ import ( vapiV1 "github.com/vertica/vertica-kubernetes/api/v1" vapiB1 "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers/et" "github.com/vertica/vertica-kubernetes/pkg/controllers/vas" "github.com/vertica/vertica-kubernetes/pkg/controllers/vdb" + "github.com/vertica/vertica-kubernetes/pkg/controllers/vrpq" vmeta "github.com/vertica/vertica-kubernetes/pkg/meta" "github.com/vertica/vertica-kubernetes/pkg/opcfg" "github.com/vertica/vertica-kubernetes/pkg/security" @@ -129,6 +131,13 @@ func addReconcilersToManager(mgr manager.Manager, restCfg *rest.Config, oc *opcf setupLog.Error(err, "unable to create controller", "controller", "EventTrigger") os.Exit(1) } + if err := (&vrpq.VerticaRestorePointsQueryReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VerticaRestorePointsQuery") + os.Exit(1) + } //+kubebuilder:scaffold:builder } @@ -257,9 +266,10 @@ func main() { CertDir: CertDir, Controller: v1alpha1.ControllerConfigurationSpec{ GroupKindConcurrency: map[string]int{ - vapiB1.GkVDB.String(): oc.VerticaDBConcurrency, - vapiB1.GkVAS.String(): oc.VerticaAutoscalerConcurrency, - vapiB1.GkET.String(): oc.EventTriggerConcurrency, + vapiB1.GkVDB.String(): oc.VerticaDBConcurrency, + vapiB1.GkVAS.String(): oc.VerticaAutoscalerConcurrency, + vapiB1.GkET.String(): oc.EventTriggerConcurrency, + vapiB1.GkVRPQ.String(): oc.VerticaRestorePointsQueryConcurrency, }, }, }) diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 5b21bb6e2..8ce9a661d 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -5,6 +5,7 @@ resources: - bases/vertica.com_verticadbs.yaml - bases/vertica.com_verticaautoscalers.yaml - bases/vertica.com_eventtriggers.yaml + - bases/vertica.com_verticarestorepointsqueries.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -12,6 +13,7 @@ patchesStrategicMerge: - patches/webhook_in_verticadbs.yaml - patches/webhook_in_verticaautoscalers.yaml - patches/webhook_in_eventtriggers.yaml + - patches/webhook_in_verticarestorepointsqueries.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] there was an optional patch to include an annotation that diff --git a/config/crd/patches/cainjection_in_verticarestorepointsqueries.yaml b/config/crd/patches/cainjection_in_verticarestorepointsqueries.yaml new file mode 100644 index 000000000..4a206626c --- /dev/null +++ b/config/crd/patches/cainjection_in_verticarestorepointsqueries.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: verticarestorepointsqueries.vertica.com diff --git a/config/crd/patches/webhook_in_verticarestorepointsqueries.yaml b/config/crd/patches/webhook_in_verticarestorepointsqueries.yaml new file mode 100644 index 000000000..b7835b0d7 --- /dev/null +++ b/config/crd/patches/webhook_in_verticarestorepointsqueries.yaml @@ -0,0 +1,8 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: verticarestorepointsqueries.vertica.com +spec: + conversion: + strategy: None diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml index 2e422f145..1add98df1 100644 --- a/config/default/manager_auth_proxy_patch.yaml +++ b/config/default/manager_auth_proxy_patch.yaml @@ -51,3 +51,4 @@ spec: - "--verticadb-concurrency=5" - "--verticaautoscaler-concurrency=1" - "--eventtrigger-concurrency=1" + - "--verticarestorepointsquery-concurrency=1" diff --git a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml index 47ff72b4b..b76d48277 100644 --- a/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/verticadb-operator.clusterserviceversion.yaml @@ -401,21 +401,16 @@ spec: a path to one of the certSecrets. displayName: Ca File path: communal.caFile - - description: "The name of a secret that contains the credentials to connect - to the communal endpoint (only applies to s3://, gs:// or azb://). Certain - keys need to be set, depending on the endpoint type: - s3:// or gs:// - - If storing credentials in a secret, the secret must have the following keys - set: accesskey and secretkey. When using Google Cloud Storage, the IDs - set in the secret are taken from the hash-based message authentication code - (HMAC) keys. - azb:// - It must have the following keys set: accountName - - Name of the Azure account blobEndpoint - (Optional) Set this to the location - of the endpoint. If using an emulator like Azurite, it can be set to something - like 'http://:' accountKey - If accessing with an account - key set it here sharedAccessSignature - If accessing with a shared access - signature, set it here \n This field is optional. For AWS, authentication - to communal storage can be provided through an attached IAM profile: attached - to the EC2 instance or to a ServiceAccount with IRSA (see https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html). - IRSA requires a Vertica server running at least with version >= 12.0.3." + - description: 'The name of an optional secret that contains the credentials + to connect to the communal endpoint. This can be omitted if the communal + storage uses some other form of authentication such as an attached IAM profile + in AWS. Certain keys need to be set, depending on the endpoint type. If + the communal storage starts with s3:// or gs://, the secret must have the + following keys set: accesskey and secretkey. If the communal storage starts + with azb://, the secret can have the following keys: accountName, blobEndpoint, + accountKey, or sharedAccessSignature. To store this secret outside of Kubernetes, + you can use a secret path reference prefix, such as gsm://. Everything after + the prefix is the name of the secret in the service you are storing.' displayName: Credential Secret path: communal.credentialSecret x-descriptors: @@ -596,11 +591,12 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:StorageClass - description: 'A secret that contains the TLS credentials to use for Vertica''s - node management agent (NMA). If this is empty, the operator will create + node management agent (NMA). If this is empty, the operator will create a secret to use and add the name of the generate secret in this field. When - set, the secret must have the following keys defined: - tls.key: The private - key to be used by the HTTP server - tls.crt: The signed certificate chain - for the private key - ca.crt: The CA certificate' + set, the secret must have the following keys defined: tls.key, tls.crt and + ca.crt. To store this secret outside of Kubernetes, you can use a secret + path reference prefix, such as gsm://. Everything after the prefix is the + name of the secret in the service you are storing.' displayName: NMATLSSecret path: nmaTLSSecret x-descriptors: @@ -608,7 +604,10 @@ spec: - description: An optional name for a secret that contains the password for the database's superuser. If this is not set, then we assume no such password is set for the database. If this is set, it is up the user to create this - secret before deployment. The secret must have a key named password. + secret before deployment. The secret must have a key named password. To + store this secret outside of Kubernetes, you can use a secret path reference + prefix, such as gsm://. Everything after the prefix is the name of the secret + in the service you are storing. displayName: Password Secret path: passwordSecret x-descriptors: @@ -824,10 +823,10 @@ spec: x-descriptors: - urn:alm:descriptor:com.tectonic.ui:select:primary - urn:alm:descriptor:com.tectonic.ui:select:secondary - - description: 'Like the nodePort parameter, except this controls the node port - to use for the http endpoint in the Vertica server. The same rules apply: - it must be defined within the range allocated by the control plane, if omitted - Kubernetes will choose the port automatically.' + - description: 'Like the clientNodePort parameter, except this controls the + node port to use for the http endpoint in the Vertica server. The same + rules apply: it must be defined within the range allocated by the control + plane, if omitted Kubernetes will choose the port automatically.' displayName: Vertica HTTPNode Port path: subclusters[0].verticaHTTPNodePort x-descriptors: @@ -982,10 +981,10 @@ spec: x-descriptors: - urn:alm:descriptor:com.tectonic.ui:select:primary - urn:alm:descriptor:com.tectonic.ui:select:secondary - - description: 'Like the nodePort parameter, except this controls the node port - to use for the http endpoint in the Vertica server. The same rules apply: - it must be defined within the range allocated by the control plane, if omitted - Kubernetes will choose the port automatically.' + - description: 'Like the clientNodePort parameter, except this controls the + node port to use for the http endpoint in the Vertica server. The same + rules apply: it must be defined within the range allocated by the control + plane, if omitted Kubernetes will choose the port automatically.' displayName: Vertica HTTPNode Port path: temporarySubclusterRouting.template.verticaHTTPNodePort x-descriptors: @@ -1926,6 +1925,34 @@ spec: displayName: Upgrade Status path: upgradeStatus version: v1beta1 + - description: VerticaRestorePointsQuery is the Schema for the verticarestorepointsqueries + API + displayName: Vertica Restore Points Query + kind: VerticaRestorePointsQuery + name: verticarestorepointsqueries.vertica.com + resources: + - kind: Job + name: "" + version: batch/v1 + specDescriptors: + - description: Optional parameter that will limit the query to only restore + points from this archvie + displayName: Archive Name + path: archiveName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:text + - description: The name of the VerticaDB CR that this VerticaRestorePointsQuery + is defined for. The VerticaDB object must exist in the same namespace as + this object. + displayName: Vertica DBName + path: verticaDBName + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:text + statusDescriptors: + - description: RestorePoints used to list out the available restore points. + displayName: Restore Points + path: restorePoints + version: v1beta1 description: |- ### What is Vertica? Vertica is a unified analytics platform, based on a massively scalable architecture with the broadest set of analytical functions spanning event and time series, pattern matching, geospatial and end-to-end in-database machine learning. Vertica enables you to easily apply these powerful functions to the largest and most demanding analytical workloads, arming you and your customers with predictive business insights faster than any analytics data warehouse in the market. Vertica provides a unified analytics platform across major public clouds and on-premises data centers and integrates data in cloud object storage and HDFS without forcing you to move any of your data. diff --git a/config/rbac/verticarestorepointsquery_editor_role.yaml b/config/rbac/verticarestorepointsquery_editor_role.yaml new file mode 100644 index 000000000..86f7d32e7 --- /dev/null +++ b/config/rbac/verticarestorepointsquery_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit verticarestorepointsqueries. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: verticarestorepointsquery-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: verticadb-operator + app.kubernetes.io/part-of: verticadb-operator + app.kubernetes.io/managed-by: kustomize + name: verticarestorepointsquery-editor-role +rules: +- apiGroups: + - vertica.com + resources: + - verticarestorepointsqueries + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - vertica.com + resources: + - verticarestorepointsqueries/status + verbs: + - get diff --git a/config/rbac/verticarestorepointsquery_viewer_role.yaml b/config/rbac/verticarestorepointsquery_viewer_role.yaml new file mode 100644 index 000000000..0fc8bd218 --- /dev/null +++ b/config/rbac/verticarestorepointsquery_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view verticarestorepointsqueries. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: verticarestorepointsquery-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: verticadb-operator + app.kubernetes.io/part-of: verticadb-operator + app.kubernetes.io/managed-by: kustomize + name: verticarestorepointsquery-viewer-role +rules: +- apiGroups: + - vertica.com + resources: + - verticarestorepointsqueries + verbs: + - get + - list + - watch +- apiGroups: + - vertica.com + resources: + - verticarestorepointsqueries/status + verbs: + - get diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index a3338b853..a864d018a 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -4,4 +4,5 @@ resources: - v1beta1_verticaautoscaler.yaml - v1beta1_eventtrigger.yaml - v1_verticadb.yaml +- v1beta1_verticarestorepointsquery.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/v1beta1_verticarestorepointsquery.yaml b/config/samples/v1beta1_verticarestorepointsquery.yaml new file mode 100644 index 000000000..f08708bed --- /dev/null +++ b/config/samples/v1beta1_verticarestorepointsquery.yaml @@ -0,0 +1,13 @@ +apiVersion: vertica.com/v1beta1 +kind: VerticaRestorePointsQuery +metadata: + labels: + app.kubernetes.io/name: verticarestorepointsquery + app.kubernetes.io/instance: verticarestorepointsquery-sample + app.kubernetes.io/part-of: verticadb-operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: verticadb-operator + name: verticarestorepointsquery-sample +spec: + verticaDBName: verticadb-sample + archiveName: archiveNm-sample diff --git a/helm-charts/verticadb-operator/README.md b/helm-charts/verticadb-operator/README.md index c0950a3ba..0f82df788 100644 --- a/helm-charts/verticadb-operator/README.md +++ b/helm-charts/verticadb-operator/README.md @@ -23,6 +23,7 @@ This helm chart will install the operator and an admission controller webhook. | reconcileConcurrency.eventtrigger | Set this to control the concurrency of reconciliations of EventTrigger CRs | 1 | | reconcileConcurrency.verticaautoscaler | Set this to control the concurrency of reconciliations of VerticaAutoscaler CRs | 1 | | reconcileConcurrency.verticadb | Set this to control the concurrency of reconciliations of VerticaDB CRs | 5 | +| reconcileConcurrency.verticarestorepointsquery | Set this to control the concurrency of reconciliations of VerticaRestorePointsQuery CRs | 1 | | rbac_proxy_image.name | Image name of Kubernetes RBAC proxy. | kubebuilder/kube-rbac-proxy:v0.13.1 | | rbac_proxy_image.repo | Repo server hosting rbac_proxy_image.name | gcr.io | | resources.\* | The resource requirements for the operator pod. |
limits:
cpu: 100m
memory: 750Mi
requests:
cpu: 100m
memory: 20Mi
| diff --git a/helm-charts/verticadb-operator/tests/kind-concurrency_test.yaml b/helm-charts/verticadb-operator/tests/kind-concurrency_test.yaml index 978f7a86f..41b56f4f5 100644 --- a/helm-charts/verticadb-operator/tests/kind-concurrency_test.yaml +++ b/helm-charts/verticadb-operator/tests/kind-concurrency_test.yaml @@ -8,6 +8,7 @@ tests: verticadb: 8 verticaautoscaler: 2 eventtrigger: 3 + verticarestorepointsquery: 2 asserts: - contains: path: spec.template.spec.containers[0].args @@ -21,3 +22,8 @@ tests: path: spec.template.spec.containers[0].args content: --eventtrigger-concurrency=3 + - contains: + path: spec.template.spec.containers[0].args + content: + --verticarestorepointsquery-concurrency=2 + diff --git a/helm-charts/verticadb-operator/values.yaml b/helm-charts/verticadb-operator/values.yaml index d0e0789d0..904b923ea 100644 --- a/helm-charts/verticadb-operator/values.yaml +++ b/helm-charts/verticadb-operator/values.yaml @@ -99,6 +99,7 @@ reconcileConcurrency: verticadb: 5 verticaautoscaler: 1 eventtrigger: 1 + verticarestorepointsquery: 1 # The resource requirements for the operator pod. See this for more info: # https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ diff --git a/pkg/controllers/vrpq/suite_test.go b/pkg/controllers/vrpq/suite_test.go new file mode 100644 index 000000000..13ab00650 --- /dev/null +++ b/pkg/controllers/vrpq/suite_test.go @@ -0,0 +1,98 @@ +/* +Copyright [2021-2023] Open Text. + +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 vrpq + +import ( + "path/filepath" + "testing" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + vmeta "github.com/vertica/vertica-kubernetes/pkg/meta" + "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" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + v1vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment +var vrpqRec *VerticaRestorePointsQueryReconciler +var logger logr.Logger + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "VerticaRestorePointsQuery Suite") +} + +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, + } + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + err = v1vapi.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + //+kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) + + mgr, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme.Scheme, + MetricsBindAddress: "0", // Disable metrics for the test + }) + + vrpqRec = &VerticaRestorePointsQueryReconciler{ + Client: k8sClient, + Scheme: scheme.Scheme, + Log: logger, + EVRec: mgr.GetEventRecorderFor(vmeta.OperatorName), + } + Expect(err).NotTo(HaveOccurred()) +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/pkg/controllers/vrpq/verticarestorepointsquery_controller.go b/pkg/controllers/vrpq/verticarestorepointsquery_controller.go new file mode 100644 index 000000000..a9e0c9dd4 --- /dev/null +++ b/pkg/controllers/vrpq/verticarestorepointsquery_controller.go @@ -0,0 +1,110 @@ +/* +Copyright [2021-2023] Open Text. + +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 vrpq + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/go-logr/logr" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/controllers" + verrors "github.com/vertica/vertica-kubernetes/pkg/errors" + "github.com/vertica/vertica-kubernetes/pkg/meta" +) + +// VerticaRestorePointsQueryReconciler reconciles a VerticaRestorePointsQuery object +type VerticaRestorePointsQueryReconciler struct { + client.Client + Scheme *runtime.Scheme + Log logr.Logger + EVRec record.EventRecorder +} + +//+kubebuilder:rbac:groups=vertica.com,resources=verticarestorepointsqueries,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=vertica.com,resources=verticarestorepointsqueries/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=vertica.com,resources=verticarestorepointsqueries/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 VerticaRestorePointsQuery 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.14.1/pkg/reconcile +func (r *VerticaRestorePointsQueryReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := r.Log.WithValues("vrpq", req.NamespacedName) + log.Info("starting reconcile of vertica restore point query") + + vrpq := &vapi.VerticaRestorePointsQuery{} + err := r.Get(ctx, req.NamespacedName, vrpq) + if err != nil { + if errors.IsNotFound(err) { + // Request object not found, cound have been deleted after reconcile request. + log.Info("VerticaRestorePointsQuery resource not found. Ignoring since object must be deleted") + return ctrl.Result{}, nil + } + log.Error(err, "failed to get VerticaRestorePointsQuery") + return ctrl.Result{}, err + } + + if meta.IsPauseAnnotationSet(vrpq.Annotations) { + log.Info(fmt.Sprintf("The pause annotation %s is set. Suspending the iteration", meta.PauseOperatorAnnotation), + "result", ctrl.Result{}, "err", nil) + return ctrl.Result{}, nil + } + + // Iterate over each actor + actors := r.constructActors(vrpq, log) + var res ctrl.Result + 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 VerticaRestorePointsQuery", "result", res, "err", err) + return res, err + } + } + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *VerticaRestorePointsQueryReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&vapi.VerticaRestorePointsQuery{}). + Complete(r) +} + +// constructActors will a list of actors that should be run for the reconcile. +// Order matters in that some actors depend on the successeful execution of +// earlier ones. +func (r *VerticaRestorePointsQueryReconciler) constructActors(_ *vapi.VerticaRestorePointsQuery, + _ logr.Logger) []controllers.ReconcileActor { + // The actors that will be applied, in sequence, to reconcile a vrpq. + // Temporarily, we set nil value for constructActors + return nil +} diff --git a/pkg/controllers/vrpq/verticarestorepointsquery_controller_test.go b/pkg/controllers/vrpq/verticarestorepointsquery_controller_test.go new file mode 100644 index 000000000..6f1449076 --- /dev/null +++ b/pkg/controllers/vrpq/verticarestorepointsquery_controller_test.go @@ -0,0 +1,44 @@ +/* +Copyright [2021-2023] Open Text. + +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 vrpq + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + vapi "github.com/vertica/vertica-kubernetes/api/v1beta1" + "github.com/vertica/vertica-kubernetes/pkg/meta" + ctrl "sigs.k8s.io/controller-runtime" +) + +var _ = Describe("verticarestorepointsquery_controller", func() { + ctx := context.Background() + + It("should reconcile an Vertica Restore Points Query with no errors if vrpq doesn't exist", func() { + vrpq := vapi.MakeVrpq() + Expect(vrpqRec.Reconcile(ctx, ctrl.Request{NamespacedName: vrpq.ExtractNamespacedName()})).Should(Equal(ctrl.Result{})) + }) + + It("should suspend the reconcile if pause annotation is set", func() { + vrpq := vapi.MakeVrpq() + vrpq.Annotations = map[string]string{meta.PauseOperatorAnnotation: "1"} + Expect(k8sClient.Create(ctx, vrpq)).Should(Succeed()) + defer func() { Expect(k8sClient.Delete(ctx, vrpq)).Should(Succeed()) }() + Expect(vrpqRec.Reconcile(ctx, ctrl.Request{NamespacedName: vrpq.ExtractNamespacedName()})).Should(Equal(ctrl.Result{})) + }) +}) diff --git a/pkg/opcfg/config.go b/pkg/opcfg/config.go index e2c099908..3db22c156 100644 --- a/pkg/opcfg/config.go +++ b/pkg/opcfg/config.go @@ -29,17 +29,18 @@ import ( ) const ( - DefaultZapcoreLevel = zapcore.InfoLevel - First = 100 - ThereAfter = 100 - DefaultMaxFileSize = 500 - DefaultMaxFileAge = 7 - DefaultMaxFileRotation = 3 - DefaultLevel = "info" - DefaultDevMode = true - DefaultVerticaDBConcurrency = 5 - DefaultVerticaAutoscalerDBConcurrency = 1 - DefaultEventTriggerDBConcurrency = 1 + DefaultZapcoreLevel = zapcore.InfoLevel + First = 100 + ThereAfter = 100 + DefaultMaxFileSize = 500 + DefaultMaxFileAge = 7 + DefaultMaxFileRotation = 3 + DefaultLevel = "info" + DefaultDevMode = true + DefaultVerticaDBConcurrency = 5 + DefaultVerticaAutoscalerDBConcurrency = 1 + DefaultEventTriggerDBConcurrency = 1 + DefaultVerticaRestorePointsQueryConcurrency = 1 ) type OperatorConfig struct { @@ -57,9 +58,10 @@ type OperatorConfig struct { // The *Currency parms control the concurrency of go routines handling each // CR. For instance, VerticaDBConcurrency is the number of go routines to // handle reconciliation of VerticaDB CRs. - VerticaDBConcurrency int - VerticaAutoscalerConcurrency int - EventTriggerConcurrency int + VerticaDBConcurrency int + VerticaAutoscalerConcurrency int + EventTriggerConcurrency int + VerticaRestorePointsQueryConcurrency int Logging } @@ -107,8 +109,10 @@ func (o *OperatorConfig) SetFlagArgs() { flag.IntVar(&o.VerticaAutoscalerConcurrency, "verticaautoscaler-concurrency", DefaultVerticaAutoscalerDBConcurrency, "The amount of concurrency to reconcile VerticaAutoscaler CRs") - flag.IntVar(&o.EventTriggerConcurrency, "eventtrigger-concurrency", DefaultVerticaDBConcurrency, + flag.IntVar(&o.EventTriggerConcurrency, "eventtrigger-concurrency", DefaultEventTriggerDBConcurrency, "The amount of concurrency to reconcile EventTrigger CRs") + flag.IntVar(&o.VerticaRestorePointsQueryConcurrency, "verticarestorepointsquery-concurrency", DefaultVerticaRestorePointsQueryConcurrency, + "The amount of concurrency to reconcile VerticaRestorePointsQuery CRs") } // getEncoderConfig returns a concrete encoders configuration diff --git a/scripts/config-transformer.sh b/scripts/config-transformer.sh index 6d5bde7a3..995ba6626 100755 --- a/scripts/config-transformer.sh +++ b/scripts/config-transformer.sh @@ -32,6 +32,7 @@ $KUSTOMIZE build $REPO_DIR/config/default | $KUBERNETES_SPLIT_YAML --outdir $TEM mv $TEMPLATE_DIR/verticadbs.vertica.com-crd.yaml $CRD_DIR mv $TEMPLATE_DIR/verticaautoscalers.vertica.com-crd.yaml $CRD_DIR mv $TEMPLATE_DIR/eventtriggers.vertica.com-crd.yaml $CRD_DIR +mv $TEMPLATE_DIR/verticarestorepointsqueries.vertica.com-crd.yaml $CRD_DIR # Delete openshift clusterRole and clusterRoleBinding files rm $TEMPLATE_DIR/verticadb-operator-openshift-cluster-role-cr.yaml diff --git a/scripts/template-helm-chart.sh b/scripts/template-helm-chart.sh index a05cd6dd0..b15fc1dcc 100755 --- a/scripts/template-helm-chart.sh +++ b/scripts/template-helm-chart.sh @@ -188,4 +188,5 @@ do perl -i -0777 -pe 's/(--verticadb-concurrency=)[0-9]+/$1\{\{ .Values.reconcileConcurrency.verticadb \}\}/g' $f perl -i -0777 -pe 's/(--verticaautoscaler-concurrency=)[0-9]+/$1\{\{ .Values.reconcileConcurrency.verticaautoscaler \}\}/g' $f perl -i -0777 -pe 's/(--eventtrigger-concurrency=)[0-9]+/$1\{\{ .Values.reconcileConcurrency.eventtrigger \}\}/g' $f + perl -i -0777 -pe 's/(--verticarestorepointsquery-concurrency=)[0-9]+/$1\{\{ .Values.reconcileConcurrency.verticarestorepointsquery \}\}/g' $f done diff --git a/tests/e2e-leg-5/metrics-disabled/05-assert.yaml b/tests/e2e-leg-5/metrics-disabled/05-assert.yaml index 2bdd1cf2d..9ee81bf7c 100644 --- a/tests/e2e-leg-5/metrics-disabled/05-assert.yaml +++ b/tests/e2e-leg-5/metrics-disabled/05-assert.yaml @@ -34,6 +34,7 @@ spec: - --verticadb-concurrency=5 - --verticaautoscaler-concurrency=1 - --eventtrigger-concurrency=1 + - --verticarestorepointsquery-concurrency=1 status: phase: Running --- diff --git a/tests/e2e-leg-5/metrics-no-auth/05-assert.yaml b/tests/e2e-leg-5/metrics-no-auth/05-assert.yaml index a75205893..81d5a5079 100644 --- a/tests/e2e-leg-5/metrics-no-auth/05-assert.yaml +++ b/tests/e2e-leg-5/metrics-no-auth/05-assert.yaml @@ -35,6 +35,7 @@ spec: - --verticadb-concurrency=5 - --verticaautoscaler-concurrency=1 - --eventtrigger-concurrency=1 + - --verticarestorepointsquery-concurrency=1 status: phase: Running --- diff --git a/tests/e2e-leg-5/prometheus-service-monitor/10-assert.yaml b/tests/e2e-leg-5/prometheus-service-monitor/10-assert.yaml index a5cd0ed4a..4a84e8696 100644 --- a/tests/e2e-leg-5/prometheus-service-monitor/10-assert.yaml +++ b/tests/e2e-leg-5/prometheus-service-monitor/10-assert.yaml @@ -35,6 +35,7 @@ spec: - --verticadb-concurrency=5 - --verticaautoscaler-concurrency=1 - --eventtrigger-concurrency=1 + - --verticarestorepointsquery-concurrency=1 - name: kube-rbac-proxy status: phase: Running diff --git a/tests/e2e-leg-5/prometheus-service-monitor/20-assert.yaml b/tests/e2e-leg-5/prometheus-service-monitor/20-assert.yaml index 140452e4d..518ddbac4 100644 --- a/tests/e2e-leg-5/prometheus-service-monitor/20-assert.yaml +++ b/tests/e2e-leg-5/prometheus-service-monitor/20-assert.yaml @@ -35,6 +35,7 @@ spec: - --verticadb-concurrency=5 - --verticaautoscaler-concurrency=1 - --eventtrigger-concurrency=1 + - --verticarestorepointsquery-concurrency=1 status: phase: Running ---