From 6e8aea6e2e514e0c5194c6996455409029de3dac Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Thu, 23 Nov 2023 22:02:19 +0600 Subject: [PATCH] EVEREST-496 Multi namespace support (#169) --- Makefile | 2 +- PROJECT | 2 + api/v1alpha1/backupstorage_types.go | 44 +++- api/v1alpha1/monitoringconfig_types.go | 44 +++- api/v1alpha1/zz_generated.deepcopy.go | 32 ++- ...verest-operator.clusterserviceversion.yaml | 44 +++- .../everest.percona.com_backupstorages.yaml | 13 ++ ...everest.percona.com_monitoringconfigs.yaml | 13 ++ .../everest.percona.com_backupstorages.yaml | 13 ++ ...everest.percona.com_monitoringconfigs.yaml | 13 ++ config/manager/kustomization.yaml | 2 +- config/manager/manager.yaml | 2 +- ...verest-operator.clusterserviceversion.yaml | 4 +- config/rbac/role.yaml | 28 +++ controllers/backupstorage_controller.go | 187 +++++++++++++++++ controllers/databasecluster_controller.go | 189 +++++++++++++----- controllers/databaseengine_controller.go | 42 ++-- controllers/monitoringconfig_controller.go | 185 +++++++++++++++++ controllers/secrets.go | 179 +++++++++++++++++ deploy/bundle.yaml | 56 +++++- .../tests/core/dbengine/00-install-dbaas.yaml | 2 +- e2e-tests/tests/core/pg/01-deploy-dbaas.yaml | 2 +- .../tests/core/psmdb/01-deploy-dbaas.yaml | 2 +- e2e-tests/tests/core/pxc/01-deploy-dbaas.yaml | 2 +- .../features/dbbackup_pg/01-deploy-dbaas.yaml | 2 +- .../dbbackup_pg/90-delete-clusters.yaml | 2 + .../dbbackup_psmdb/01-deploy-dbaas.yaml | 2 +- .../dbbackup_psmdb/90-delete-cluster.yaml | 2 + .../dbbackup_pxc/01-deploy-dbaas.yaml | 2 +- .../dbbackup_pxc/90-delete-cluster.yaml | 2 + .../00-deploy-operators.yaml | 2 +- .../96-delete-clusters.yaml | 2 + .../00-deploy-operators.yaml | 2 +- .../96-delete-clusters.yaml | 2 + .../00-deploy-operators.yaml | 2 +- .../96-delete-clusters.yaml | 2 + .../00-deploy-operators.yaml | 7 + .../features/multinamespace_pg/01-assert.yaml | 65 ++++++ .../multinamespace_pg/01-deploy-dbaas.yaml | 7 + .../features/multinamespace_pg/10-assert.yaml | 97 +++++++++ .../10-pg-cluster-with-schedule.yaml | 69 +++++++ .../features/multinamespace_pg/20-assert.yaml | 77 +++++++ .../20-pg-cluster-with-schedule.yaml | 31 +++ .../multinamespace_pg/90-delete-clusters.yaml | 13 ++ .../multinamespace_pg/98-drop-pvc.yaml | 9 + .../00-deploy-operators.yaml | 7 + .../multinamespace_psmdb/01-assert.yaml | 67 +++++++ .../multinamespace_psmdb/01-deploy-dbaas.yaml | 7 + .../multinamespace_psmdb/10-assert.yaml | 80 ++++++++ .../10-psmdb-cluster-with-schedule.yaml | 68 +++++++ .../multinamespace_psmdb/20-assert.yaml | 61 ++++++ .../20-psmdb-cluster-with-schedule.yaml | 31 +++ .../90-delete-cluster.yaml | 13 ++ .../multinamespace_psmdb/98-drop-pvc.yaml | 5 + .../00-deploy-operators.yaml | 6 + .../multinamespace_pxc/01-assert.yaml | 68 +++++++ .../multinamespace_pxc/01-deploy-dbaas.yaml | 6 + .../multinamespace_pxc/10-assert.yaml | 74 +++++++ .../10-pxc-cluster-with-schedule.yaml | 69 +++++++ .../multinamespace_pxc/20-assert.yaml | 55 +++++ .../20-pxc-cluster-with-schedule.yaml | 32 +++ .../multinamespace_pxc/90-delete-cluster.yaml | 13 ++ .../multinamespace_pxc/98-drop-pvc.yaml | 5 + .../scheduled_backups/01-manager.yaml | 2 +- .../features/templates/01-deploy-dbaas.yaml | 2 +- .../tests/upgrade/pg/01-deploy-dbaas.yaml | 2 +- .../tests/upgrade/psmdb/01-deploy-dbaas.yaml | 2 +- .../tests/upgrade/pxc/01-deploy-dbaas.yaml | 2 +- main.go | 70 ++++++- 69 files changed, 2137 insertions(+), 111 deletions(-) create mode 100644 controllers/backupstorage_controller.go create mode 100644 controllers/monitoringconfig_controller.go create mode 100644 controllers/secrets.go create mode 100644 e2e-tests/tests/features/multinamespace_pg/00-deploy-operators.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pg/01-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pg/01-deploy-dbaas.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pg/10-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pg/10-pg-cluster-with-schedule.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pg/20-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pg/20-pg-cluster-with-schedule.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pg/90-delete-clusters.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pg/98-drop-pvc.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/00-deploy-operators.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/01-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/01-deploy-dbaas.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/10-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/10-psmdb-cluster-with-schedule.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/20-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/20-psmdb-cluster-with-schedule.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/90-delete-cluster.yaml create mode 100644 e2e-tests/tests/features/multinamespace_psmdb/98-drop-pvc.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/00-deploy-operators.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/01-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/01-deploy-dbaas.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/10-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/10-pxc-cluster-with-schedule.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/20-assert.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/20-pxc-cluster-with-schedule.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/90-delete-cluster.yaml create mode 100644 e2e-tests/tests/features/multinamespace_pxc/98-drop-pvc.yaml diff --git a/Makefile b/Makefile index 29b5ed0b..a7376311 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # To re-generate a bundle for another specific version without changing the standard setup, you can: # - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) # - use environment variables to overwrite this value (e.g export VERSION=0.0.2) -VERSION ?= 0.5.0-dev2 +VERSION ?= 0.6.0-dev1 # CHANNELS define the bundle channels used in the bundle. # Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") diff --git a/PROJECT b/PROJECT index 56fa18c7..cdc69fb3 100644 --- a/PROJECT +++ b/PROJECT @@ -50,6 +50,7 @@ resources: - api: crdVersion: v1 namespaced: true + controller: true domain: percona.com group: everest kind: BackupStorage @@ -58,6 +59,7 @@ resources: - api: crdVersion: v1 namespaced: true + controller: true domain: percona.com group: everest kind: MonitoringConfig diff --git a/api/v1alpha1/backupstorage_types.go b/api/v1alpha1/backupstorage_types.go index 853209bc..12cc68aa 100644 --- a/api/v1alpha1/backupstorage_types.go +++ b/api/v1alpha1/backupstorage_types.go @@ -45,10 +45,14 @@ type BackupStorageSpec struct { Description string `json:"description,omitempty"` // CredentialsSecretName is the name of the secret with credentials. CredentialsSecretName string `json:"credentialsSecretName"` + // TargetNamespaces is the list of namespaces where the operator will copy secrets provided in the CredentialsSecretsName. + TargetNamespaces []string `json:"targetNamespaces,omitempty"` } // BackupStorageStatus defines the observed state of BackupStorage. -type BackupStorageStatus struct{} +type BackupStorageStatus struct { + UsedNamespaces map[string]bool `json:"usedNamespaces"` +} //+kubebuilder:object:root=true //+kubebuilder:subresource:status @@ -74,3 +78,41 @@ type BackupStorageList struct { func init() { SchemeBuilder.Register(&BackupStorage{}, &BackupStorageList{}) } + +// UpdateNamespacesList updates the list of namespaces that use the backupStorage. +func (b *BackupStorage) UpdateNamespacesList(namespace string) bool { + if b.Status.UsedNamespaces == nil { + b.Status.UsedNamespaces = make(map[string]bool) + } + if _, ok := b.Status.UsedNamespaces[namespace]; ok { + return false + } + b.Status.UsedNamespaces[namespace] = true + return true +} + +// DeleteUsedNamespace deletes the namespace from the usedNamespaces list. +func (b *BackupStorage) DeleteUsedNamespace(namespace string) bool { + if b.Status.UsedNamespaces == nil { + return false + } + if _, ok := b.Status.UsedNamespaces[namespace]; ok { + delete(b.Status.UsedNamespaces, namespace) + return true + } + return false +} + +// IsNamespaceAllowed checks the namespace against targetNamespaces and returns if it's allowed to use. +func (b *BackupStorage) IsNamespaceAllowed(namespace string) bool { + if len(b.Spec.TargetNamespaces) == 0 { + return true + } + for _, ns := range b.Spec.TargetNamespaces { + ns := ns + if ns == namespace { + return true + } + } + return false +} diff --git a/api/v1alpha1/monitoringconfig_types.go b/api/v1alpha1/monitoringconfig_types.go index 0ec06b59..33dcc876 100644 --- a/api/v1alpha1/monitoringconfig_types.go +++ b/api/v1alpha1/monitoringconfig_types.go @@ -34,6 +34,8 @@ type MonitoringConfigSpec struct { Type MonitoringType `json:"type"` // CredentialsSecretName is the name of the secret with credentials. CredentialsSecretName string `json:"credentialsSecretName"` + // TargetNamespaces is the list of namespaces where the operator will copy secrets provided in the CredentialsSecretsName. + TargetNamespaces []string `json:"targetNamespaces,omitempty"` // PMM is configuration for the PMM monitoring type. PMM PMMConfig `json:"pmm,omitempty"` } @@ -47,7 +49,9 @@ type PMMConfig struct { } // MonitoringConfigStatus defines the observed state of MonitoringConfig. -type MonitoringConfigStatus struct{} +type MonitoringConfigStatus struct { + UsedNamespaces map[string]bool `json:"usedNamespaces"` +} //+kubebuilder:object:root=true //+kubebuilder:subresource:status @@ -74,3 +78,41 @@ type MonitoringConfigList struct { func init() { SchemeBuilder.Register(&MonitoringConfig{}, &MonitoringConfigList{}) } + +// UpdateNamespacesList updates the list of namespaces that use the monitoring config. +func (m *MonitoringConfig) UpdateNamespacesList(namespace string) bool { + if m.Status.UsedNamespaces == nil { + m.Status.UsedNamespaces = make(map[string]bool) + } + if _, ok := m.Status.UsedNamespaces[namespace]; ok { + return false + } + m.Status.UsedNamespaces[namespace] = true + return true +} + +// DeleteUsedNamespace deletes the namespace from the usedNamespaces list. +func (m *MonitoringConfig) DeleteUsedNamespace(namespace string) bool { + if m.Status.UsedNamespaces == nil { + return false + } + if _, ok := m.Status.UsedNamespaces[namespace]; ok { + delete(m.Status.UsedNamespaces, namespace) + return true + } + return false +} + +// IsNamespaceAllowed checks the namespace against targetNamespaces and returns if it's allowed to use. +func (m *MonitoringConfig) IsNamespaceAllowed(namespace string) bool { + if len(m.Spec.TargetNamespaces) == 0 { + return true + } + for _, ns := range m.Spec.TargetNamespaces { + ns := ns + if ns == namespace { + return true + } + } + return false +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 2fae956b..f7686bf8 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -80,8 +80,8 @@ func (in *BackupStorage) DeepCopyInto(out *BackupStorage) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupStorage. @@ -152,6 +152,11 @@ func (in *BackupStorageProviderSpec) DeepCopy() *BackupStorageProviderSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BackupStorageSpec) DeepCopyInto(out *BackupStorageSpec) { *out = *in + if in.TargetNamespaces != nil { + in, out := &in.TargetNamespaces, &out.TargetNamespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupStorageSpec. @@ -167,6 +172,13 @@ func (in *BackupStorageSpec) DeepCopy() *BackupStorageSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BackupStorageStatus) DeepCopyInto(out *BackupStorageStatus) { *out = *in + if in.UsedNamespaces != nil { + in, out := &in.UsedNamespaces, &out.UsedNamespaces + *out = make(map[string]bool, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupStorageStatus. @@ -699,8 +711,8 @@ func (in *MonitoringConfig) DeepCopyInto(out *MonitoringConfig) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonitoringConfig. @@ -756,6 +768,11 @@ func (in *MonitoringConfigList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MonitoringConfigSpec) DeepCopyInto(out *MonitoringConfigSpec) { *out = *in + if in.TargetNamespaces != nil { + in, out := &in.TargetNamespaces, &out.TargetNamespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } out.PMM = in.PMM } @@ -772,6 +789,13 @@ func (in *MonitoringConfigSpec) DeepCopy() *MonitoringConfigSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MonitoringConfigStatus) DeepCopyInto(out *MonitoringConfigStatus) { *out = *in + if in.UsedNamespaces != nil { + in, out := &in.UsedNamespaces, &out.UsedNamespaces + *out = make(map[string]bool, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonitoringConfigStatus. diff --git a/bundle/manifests/everest-operator.clusterserviceversion.yaml b/bundle/manifests/everest-operator.clusterserviceversion.yaml index bc83b15a..0cb7839c 100644 --- a/bundle/manifests/everest-operator.clusterserviceversion.yaml +++ b/bundle/manifests/everest-operator.clusterserviceversion.yaml @@ -103,10 +103,10 @@ metadata: } ] capabilities: Basic Install - createdAt: "2023-11-22T14:28:14Z" + createdAt: "2023-11-23T12:27:38Z" operators.operatorframework.io/builder: operator-sdk-v1.32.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 - name: everest-operator.v0.5.0-dev2 + name: everest-operator.v0.6.0-dev1 namespace: placeholder spec: apiservicedefinitions: {} @@ -193,6 +193,20 @@ spec: - patch - update - watch + - apiGroups: + - everest.percona.com + resources: + - backupstorages/finalizers + verbs: + - update + - apiGroups: + - everest.percona.com + resources: + - backupstorages/status + verbs: + - get + - patch + - update - apiGroups: - everest.percona.com resources: @@ -309,6 +323,20 @@ spec: - patch - update - watch + - apiGroups: + - everest.percona.com + resources: + - monitoringconfigs/finalizers + verbs: + - update + - apiGroups: + - everest.percona.com + resources: + - monitoringconfigs/status + verbs: + - get + - patch + - update - apiGroups: - pgv2.percona.com resources: @@ -512,11 +540,11 @@ spec: command: - /manager env: - - name: WATCH_NAMESPACE + - name: DEFAULT_NAMESPACE valueFrom: fieldRef: - fieldPath: metadata.annotations['olm.targetNamespaces'] - image: docker.io/perconalab/everest-operator:0.5.0-dev2 + fieldPath: metadata.namespace + image: docker.io/perconalab/everest-operator:0.6.0-dev1 livenessProbe: httpGet: path: /healthz @@ -586,9 +614,9 @@ spec: type: OwnNamespace - supported: true type: SingleNamespace - - supported: false - type: MultiNamespace - supported: true + type: MultiNamespace + - supported: false type: AllNamespaces keywords: - everest @@ -610,4 +638,4 @@ spec: provider: name: Percona url: https://percona.com - version: 0.5.0-dev2 + version: 0.6.0-dev1 diff --git a/bundle/manifests/everest.percona.com_backupstorages.yaml b/bundle/manifests/everest.percona.com_backupstorages.yaml index 9b3c03b7..9a18ecba 100644 --- a/bundle/manifests/everest.percona.com_backupstorages.yaml +++ b/bundle/manifests/everest.percona.com_backupstorages.yaml @@ -50,6 +50,12 @@ spec: region: description: Region is a region where the bucket is located. type: string + targetNamespaces: + description: TargetNamespaces is the list of namespaces where the + operator will copy secrets provided in the CredentialsSecretsName. + items: + type: string + type: array type: description: Type is a type of backup storage. enum: @@ -63,6 +69,13 @@ spec: type: object status: description: BackupStorageStatus defines the observed state of BackupStorage. + properties: + usedNamespaces: + additionalProperties: + type: boolean + type: object + required: + - usedNamespaces type: object type: object served: true diff --git a/bundle/manifests/everest.percona.com_monitoringconfigs.yaml b/bundle/manifests/everest.percona.com_monitoringconfigs.yaml index 100f50e0..af429a3f 100644 --- a/bundle/manifests/everest.percona.com_monitoringconfigs.yaml +++ b/bundle/manifests/everest.percona.com_monitoringconfigs.yaml @@ -57,6 +57,12 @@ spec: - image - url type: object + targetNamespaces: + description: TargetNamespaces is the list of namespaces where the + operator will copy secrets provided in the CredentialsSecretsName. + items: + type: string + type: array type: description: Type is type of monitoring. enum: @@ -68,6 +74,13 @@ spec: type: object status: description: MonitoringConfigStatus defines the observed state of MonitoringConfig. + properties: + usedNamespaces: + additionalProperties: + type: boolean + type: object + required: + - usedNamespaces type: object type: object served: true diff --git a/config/crd/bases/everest.percona.com_backupstorages.yaml b/config/crd/bases/everest.percona.com_backupstorages.yaml index b2827e77..036849b5 100644 --- a/config/crd/bases/everest.percona.com_backupstorages.yaml +++ b/config/crd/bases/everest.percona.com_backupstorages.yaml @@ -51,6 +51,12 @@ spec: region: description: Region is a region where the bucket is located. type: string + targetNamespaces: + description: TargetNamespaces is the list of namespaces where the + operator will copy secrets provided in the CredentialsSecretsName. + items: + type: string + type: array type: description: Type is a type of backup storage. enum: @@ -64,6 +70,13 @@ spec: type: object status: description: BackupStorageStatus defines the observed state of BackupStorage. + properties: + usedNamespaces: + additionalProperties: + type: boolean + type: object + required: + - usedNamespaces type: object type: object served: true diff --git a/config/crd/bases/everest.percona.com_monitoringconfigs.yaml b/config/crd/bases/everest.percona.com_monitoringconfigs.yaml index f6a4f25f..5287cccd 100644 --- a/config/crd/bases/everest.percona.com_monitoringconfigs.yaml +++ b/config/crd/bases/everest.percona.com_monitoringconfigs.yaml @@ -58,6 +58,12 @@ spec: - image - url type: object + targetNamespaces: + description: TargetNamespaces is the list of namespaces where the + operator will copy secrets provided in the CredentialsSecretsName. + items: + type: string + type: array type: description: Type is type of monitoring. enum: @@ -69,6 +75,13 @@ spec: type: object status: description: MonitoringConfigStatus defines the observed state of MonitoringConfig. + properties: + usedNamespaces: + additionalProperties: + type: boolean + type: object + required: + - usedNamespaces type: object type: object served: true diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 2d554c76..7a70afdc 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -5,4 +5,4 @@ kind: Kustomization images: - name: controller newName: docker.io/perconalab/everest-operator - newTag: 0.5.0-dev2 + newTag: 0.6.0-dev1 diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 8bf07c64..ecdbd4e7 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -103,7 +103,7 @@ spec: cpu: 10m memory: 64Mi env: - - name: WATCH_NAMESPACE + - name: DEFAULT_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace diff --git a/config/manifests/bases/everest-operator.clusterserviceversion.yaml b/config/manifests/bases/everest-operator.clusterserviceversion.yaml index f1bad76c..35b58304 100644 --- a/config/manifests/bases/everest-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/everest-operator.clusterserviceversion.yaml @@ -56,9 +56,9 @@ spec: type: OwnNamespace - supported: true type: SingleNamespace - - supported: false - type: MultiNamespace - supported: true + type: MultiNamespace + - supported: false type: AllNamespaces keywords: - everest diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 5dbdc58d..3181af29 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -45,6 +45,20 @@ rules: - patch - update - watch +- apiGroups: + - everest.percona.com + resources: + - backupstorages/finalizers + verbs: + - update +- apiGroups: + - everest.percona.com + resources: + - backupstorages/status + verbs: + - get + - patch + - update - apiGroups: - everest.percona.com resources: @@ -161,6 +175,20 @@ rules: - patch - update - watch +- apiGroups: + - everest.percona.com + resources: + - monitoringconfigs/finalizers + verbs: + - update +- apiGroups: + - everest.percona.com + resources: + - monitoringconfigs/status + verbs: + - get + - patch + - update - apiGroups: - pgv2.percona.com resources: diff --git a/controllers/backupstorage_controller.go b/controllers/backupstorage_controller.go new file mode 100644 index 00000000..7256d476 --- /dev/null +++ b/controllers/backupstorage_controller.go @@ -0,0 +1,187 @@ +// everest-operator +// Copyright (C) 2022 Percona LLC +// +// 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" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" +) + +const ( + cleanupSecretsFinalizer = "percona.com/cleanup-secrets" //nolint:gosec + labelBackupStorageName = "percona.com/backup-storage-name" +) + +// BackupStorageReconciler reconciles a BackupStorage object. +type BackupStorageReconciler struct { + client.Client + Scheme *runtime.Scheme + defaultNamespace string +} + +//+kubebuilder:rbac:groups=everest.percona.com,resources=backupstorages,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=everest.percona.com,resources=backupstorages/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=everest.percona.com,resources=backupstorages/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. +// Modify the Reconcile function to compare the state specified by +// the DatabaseClusterBackup 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 *BackupStorageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { //nolint:dupl + bs := &everestv1alpha1.BackupStorage{} + logger := log.FromContext(ctx) + backupStorageNamespace := req.NamespacedName.Namespace + if req.NamespacedName.Namespace != r.defaultNamespace { + backupStorageNamespace = r.defaultNamespace + } + + err := r.Get(ctx, types.NamespacedName{Name: req.NamespacedName.Name, Namespace: backupStorageNamespace}, bs) + if err != nil { + // NotFound cannot be fixed by requeuing so ignore it. During background + // deletion, we receive delete events from cluster's dependents after + // cluster is deleted. + if err = client.IgnoreNotFound(err); err != nil { + logger.Error(err, "unable to fetch BackupStorage") + } + return reconcile.Result{}, err + } + if bs.DeletionTimestamp != nil { + logger.Info("cleaning up the secrets across namespaces") + if err := r.handleDelete(ctx, bs); err != nil { + return ctrl.Result{}, err + } + logger.Info("all secrets were removed") + controllerutil.RemoveFinalizer(bs, cleanupSecretsFinalizer) + if err := r.Update(ctx, bs); err != nil { + return ctrl.Result{}, err + } + } + defaultSecret := &corev1.Secret{} + err = r.Get(ctx, types.NamespacedName{Name: req.NamespacedName.Name, Namespace: r.defaultNamespace}, defaultSecret) + if err != nil { + if err = client.IgnoreNotFound(err); err != nil { + logger.Error(err, "unable to fetch Secret") + } + return ctrl.Result{}, err + } + var needsUpdate bool + if req.NamespacedName.Namespace == r.defaultNamespace { + logger.Info("setting controller references for the secret") + needsUpdate, err = r.reconcileBackupStorage(ctx, bs, defaultSecret) + if err != nil { + return ctrl.Result{}, err + } + if !controllerutil.ContainsFinalizer(bs, cleanupSecretsFinalizer) { + controllerutil.AddFinalizer(bs, cleanupSecretsFinalizer) + if err := r.Update(ctx, bs); err != nil { + return ctrl.Result{}, err + } + } + } + + logger.Info("updating secrets in used namespaces") + if err := r.handleSecretUpdate(ctx, bs, defaultSecret); err != nil { + return ctrl.Result{}, err + } + if needsUpdate { + err := r.Status().Update(ctx, bs) + if err != nil { + return ctrl.Result{}, err + } + } + + return ctrl.Result{}, nil +} + +func (r *BackupStorageReconciler) handleDelete(ctx context.Context, bs *everestv1alpha1.BackupStorage) error { + for namespace := range bs.Status.UsedNamespaces { + if namespace == r.defaultNamespace { + continue + } + secret := &corev1.Secret{} + err := r.Get(ctx, types.NamespacedName{Name: bs.Name, Namespace: namespace}, secret) + if err != nil { + return err + } + err = r.Delete(ctx, secret) + if err != nil { + return err + } + } + return nil +} + +func (r *BackupStorageReconciler) handleSecretUpdate(ctx context.Context, bs *everestv1alpha1.BackupStorage, defaultSecret *corev1.Secret) error { + for namespace := range bs.Status.UsedNamespaces { + if namespace == r.defaultNamespace { + continue + } + secret := &corev1.Secret{} + err := r.Get(ctx, types.NamespacedName{Name: bs.Name, Namespace: namespace}, secret) + if err != nil { + return err + } + secret.Data = defaultSecret.Data + secret.Type = defaultSecret.Type + secret.StringData = defaultSecret.StringData + err = r.Update(ctx, secret) + if err != nil { + return err + } + } + return nil +} + +func (r *BackupStorageReconciler) reconcileBackupStorage(ctx context.Context, bs *everestv1alpha1.BackupStorage, defaultSecret *corev1.Secret) (bool, error) { + err := controllerutil.SetControllerReference(bs, defaultSecret, r.Client.Scheme()) + if err != nil { + return false, err + } + if err = r.Update(ctx, defaultSecret); err != nil { + return false, err + } + + if bs.UpdateNamespacesList(defaultSecret.Namespace) { + if err := r.Status().Update(ctx, bs); err != nil { + return false, err + } + } + return true, err +} + +// SetupWithManager sets up the controller with the Manager. +func (r *BackupStorageReconciler) SetupWithManager(mgr ctrl.Manager, defaultNamespace string) error { + r.defaultNamespace = defaultNamespace + return ctrl.NewControllerManagedBy(mgr). + For(&everestv1alpha1.BackupStorage{}). + Owns(&corev1.Secret{}). + Complete(r) +} diff --git a/controllers/databasecluster_controller.go b/controllers/databasecluster_controller.go index 7c20480b..6b468931 100644 --- a/controllers/databasecluster_controller.go +++ b/controllers/databasecluster_controller.go @@ -25,7 +25,6 @@ import ( "errors" "fmt" "net/url" - "os" "path/filepath" "reflect" "regexp" @@ -34,7 +33,6 @@ import ( "github.com/AlekSi/pointer" "github.com/go-ini/ini" - goversion "github.com/hashicorp/go-version" pgv2 "github.com/percona/percona-postgresql-operator/pkg/apis/pgv2.percona.com/v2" crunchyv1beta1 "github.com/percona/percona-postgresql-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1" psmdbv1 "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" @@ -140,7 +138,8 @@ var ( // DatabaseClusterReconciler reconciles a DatabaseCluster object. type DatabaseClusterReconciler struct { client.Client - Scheme *runtime.Scheme + Scheme *runtime.Scheme + defaultNamespace string } //+kubebuilder:rbac:groups=everest.percona.com,resources=databaseclusters,verbs=get;list;watch;create;update;patch;delete @@ -278,8 +277,8 @@ func (r *DatabaseClusterReconciler) reconcileDBRestoreFromDataSource(ctx context return err } -//nolint:gocognit,maintidx -func (r *DatabaseClusterReconciler) genPSMDBBackupSpec( +//nolint:gocognit +func (r *DatabaseClusterReconciler) genPSMDBBackupSpec( //nolint:gocyclo,cyclop,maintidx ctx context.Context, database *everestv1alpha1.DatabaseCluster, engine *everestv1alpha1.DatabaseEngine, @@ -324,10 +323,15 @@ func (r *DatabaseClusterReconciler) genPSMDBBackupSpec( } backupStorage := &everestv1alpha1.BackupStorage{} - err := r.Get(ctx, types.NamespacedName{Name: backup.Spec.BackupStorageName, Namespace: database.Namespace}, backupStorage) + err := r.Get(ctx, types.NamespacedName{Name: backup.Spec.BackupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return psmdbv1.BackupSpec{Enabled: false}, errors.Join(err, fmt.Errorf("failed to get backup storage %s", backup.Spec.BackupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return psmdbv1.BackupSpec{Enabled: false}, err + } + } switch backupStorage.Spec.Type { case everestv1alpha1.BackupStorageTypeS3: @@ -393,10 +397,15 @@ func (r *DatabaseClusterReconciler) genPSMDBBackupSpec( } backupStorage := &everestv1alpha1.BackupStorage{} - err = r.Get(ctx, types.NamespacedName{Name: backup.Spec.BackupStorageName, Namespace: database.Namespace}, backupStorage) + err = r.Get(ctx, types.NamespacedName{Name: backup.Spec.BackupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return psmdbv1.BackupSpec{Enabled: false}, errors.Join(err, fmt.Errorf("failed to get backup storage %s", backup.Spec.BackupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return psmdbv1.BackupSpec{Enabled: false}, err + } + } switch backupStorage.Spec.Type { case everestv1alpha1.BackupStorageTypeS3: @@ -438,10 +447,15 @@ func (r *DatabaseClusterReconciler) genPSMDBBackupSpec( } backupStorage := &everestv1alpha1.BackupStorage{} - err := r.Get(ctx, types.NamespacedName{Name: schedule.BackupStorageName, Namespace: database.Namespace}, backupStorage) + err := r.Get(ctx, types.NamespacedName{Name: schedule.BackupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return psmdbv1.BackupSpec{Enabled: false}, errors.Join(err, fmt.Errorf("failed to get backup storage %s", schedule.BackupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return psmdbv1.BackupSpec{Enabled: false}, err + } + } switch backupStorage.Spec.Type { case everestv1alpha1.BackupStorageTypeS3: @@ -623,12 +637,17 @@ func (r *DatabaseClusterReconciler) reconcilePSMDB(ctx context.Context, req ctrl monitoring := &everestv1alpha1.MonitoringConfig{} if database.Spec.Monitoring != nil && database.Spec.Monitoring.MonitoringConfigName != "" { err := r.Get(ctx, types.NamespacedName{ - Namespace: req.NamespacedName.Namespace, + Namespace: r.defaultNamespace, Name: database.Spec.Monitoring.MonitoringConfigName, }, monitoring) if err != nil { return err } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileMonitoringConfigSecret(ctx, monitoring, database); err != nil { + return err + } + } } if monitoring.Spec.Type == everestv1alpha1.PMMMonitoringType { //nolint:dupl @@ -901,7 +920,7 @@ func (r *DatabaseClusterReconciler) genPXCProxySQLSpec(database *everestv1alpha1 return proxySQL, nil } -func (r *DatabaseClusterReconciler) genPXCBackupSpec( +func (r *DatabaseClusterReconciler) genPXCBackupSpec( //nolint:gocognit ctx context.Context, database *everestv1alpha1.DatabaseCluster, engine *everestv1alpha1.DatabaseEngine, @@ -936,10 +955,15 @@ func (r *DatabaseClusterReconciler) genPXCBackupSpec( } backupStorage := &everestv1alpha1.BackupStorage{} - err := r.Get(ctx, types.NamespacedName{Name: backup.Spec.BackupStorageName, Namespace: database.Namespace}, backupStorage) + err := r.Get(ctx, types.NamespacedName{Name: backup.Spec.BackupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return nil, errors.Join(err, fmt.Errorf("failed to get backup storage %s", backup.Spec.BackupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return nil, err + } + } storages[backup.Spec.BackupStorageName] = &pxcv1.BackupStorageSpec{ Type: pxcv1.BackupStorageType(backupStorage.Spec.Type), @@ -994,10 +1018,15 @@ func (r *DatabaseClusterReconciler) genPXCBackupSpec( // Add the storages used by the schedule backups if _, ok := storages[schedule.BackupStorageName]; !ok { backupStorage := &everestv1alpha1.BackupStorage{} - err := r.Get(ctx, types.NamespacedName{Name: schedule.BackupStorageName, Namespace: database.Namespace}, backupStorage) + err := r.Get(ctx, types.NamespacedName{Name: schedule.BackupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return nil, errors.Join(err, fmt.Errorf("failed to get backup storage %s", schedule.BackupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return nil, err + } + } storages[schedule.BackupStorageName] = &pxcv1.BackupStorageSpec{ Type: pxcv1.BackupStorageType(backupStorage.Spec.Type), @@ -1248,12 +1277,17 @@ func (r *DatabaseClusterReconciler) reconcilePXC(ctx context.Context, req ctrl.R monitoring := &everestv1alpha1.MonitoringConfig{} if database.Spec.Monitoring != nil && database.Spec.Monitoring.MonitoringConfigName != "" { err := r.Get(ctx, types.NamespacedName{ - Namespace: req.NamespacedName.Namespace, + Namespace: r.defaultNamespace, Name: database.Spec.Monitoring.MonitoringConfigName, }, monitoring) if err != nil { return err } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileMonitoringConfigSecret(ctx, monitoring, database); err != nil { + return err + } + } } if monitoring.Spec.Type == everestv1alpha1.PMMMonitoringType { @@ -1810,7 +1844,7 @@ func reconcilePGBackRestRepos( } //nolint:gocognit -func (r *DatabaseClusterReconciler) reconcilePGBackupsSpec( //nolint:maintidx +func (r *DatabaseClusterReconciler) reconcilePGBackupsSpec( //nolint:maintidx,gocyclo,cyclop ctx context.Context, oldBackups crunchyv1beta1.Backups, database *everestv1alpha1.DatabaseCluster, @@ -1861,10 +1895,15 @@ func (r *DatabaseClusterReconciler) reconcilePGBackupsSpec( //nolint:maintidx } backupStorage := &everestv1alpha1.BackupStorage{} - err := r.Get(ctx, types.NamespacedName{Name: backup.Spec.BackupStorageName, Namespace: database.Namespace}, backupStorage) + err := r.Get(ctx, types.NamespacedName{Name: backup.Spec.BackupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return crunchyv1beta1.Backups{}, errors.Join(err, fmt.Errorf("failed to get backup storage %s", backup.Spec.BackupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return crunchyv1beta1.Backups{}, err + } + } backupStorageSecret := &corev1.Secret{} err = r.Get(ctx, types.NamespacedName{Name: backupStorage.Spec.CredentialsSecretName, Namespace: backupStorage.Namespace}, backupStorageSecret) @@ -1915,10 +1954,15 @@ func (r *DatabaseClusterReconciler) reconcilePGBackupsSpec( //nolint:maintidx } backupStorage := &everestv1alpha1.BackupStorage{} - err := r.Get(ctx, types.NamespacedName{Name: backupStorageName, Namespace: database.Namespace}, backupStorage) + err := r.Get(ctx, types.NamespacedName{Name: backupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return crunchyv1beta1.Backups{}, errors.Join(err, fmt.Errorf("failed to get backup storage %s", backupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return crunchyv1beta1.Backups{}, err + } + } backupStorageSecret := &corev1.Secret{} err = r.Get(ctx, types.NamespacedName{Name: backupStorage.Spec.CredentialsSecretName, Namespace: backupStorage.Namespace}, backupStorageSecret) @@ -1964,10 +2008,15 @@ func (r *DatabaseClusterReconciler) reconcilePGBackupsSpec( //nolint:maintidx } backupStorage := &everestv1alpha1.BackupStorage{} - err := r.Get(ctx, types.NamespacedName{Name: schedule.BackupStorageName, Namespace: database.Namespace}, backupStorage) + err := r.Get(ctx, types.NamespacedName{Name: schedule.BackupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return crunchyv1beta1.Backups{}, errors.Join(err, fmt.Errorf("failed to get backup storage %s", schedule.BackupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return crunchyv1beta1.Backups{}, err + } + } backupStorageSecret := &corev1.Secret{} err = r.Get(ctx, types.NamespacedName{Name: backupStorage.Spec.CredentialsSecretName, Namespace: backupStorage.Namespace}, backupStorageSecret) @@ -2069,10 +2118,15 @@ func (r *DatabaseClusterReconciler) genPGDataSourceSpec(ctx context.Context, dat } backupStorage := &everestv1alpha1.BackupStorage{} - err := r.Get(ctx, types.NamespacedName{Name: backupStorageName, Namespace: database.Namespace}, backupStorage) + err := r.Get(ctx, types.NamespacedName{Name: backupStorageName, Namespace: r.defaultNamespace}, backupStorage) if err != nil { return nil, errors.Join(err, fmt.Errorf("failed to get backup storage %s", backupStorageName)) } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileBackupStorageSecret(ctx, backupStorage, database); err != nil { + return nil, err + } + } switch backupStorage.Spec.Type { case everestv1alpha1.BackupStorageTypeS3: @@ -2365,12 +2419,17 @@ func (r *DatabaseClusterReconciler) reconcilePG(ctx context.Context, req ctrl.Re monitoring := &everestv1alpha1.MonitoringConfig{} if database.Spec.Monitoring != nil && database.Spec.Monitoring.MonitoringConfigName != "" { err := r.Get(ctx, types.NamespacedName{ - Namespace: req.NamespacedName.Namespace, + Namespace: r.defaultNamespace, Name: database.Spec.Monitoring.MonitoringConfigName, }, monitoring) if err != nil { return err } + if database.Namespace != r.defaultNamespace { + if err := r.reconcileMonitoringConfigSecret(ctx, monitoring, database); err != nil { + return err + } + } } // We have to assign the default spec here explicitly becase PG reconciliation @@ -2571,19 +2630,7 @@ func (r *DatabaseClusterReconciler) getOperatorVersion(ctx context.Context, name } func (r *DatabaseClusterReconciler) addPXCKnownTypes(scheme *runtime.Scheme) error { - version, err := r.getOperatorVersion(context.Background(), types.NamespacedName{ - Name: pxcDeploymentName, - Namespace: os.Getenv("WATCH_NAMESPACE"), - }) - if err != nil { - return err - } - pxcSchemeGroupVersion := schema.GroupVersion{Group: pxcAPIGroup, Version: strings.ReplaceAll("v"+version.String(), ".", "-")} - ver, _ := goversion.NewVersion("v1.11.0") - if version.version.GreaterThan(ver) { - pxcSchemeGroupVersion = schema.GroupVersion{Group: pxcAPIGroup, Version: "v1"} - } - + pxcSchemeGroupVersion := schema.GroupVersion{Group: pxcAPIGroup, Version: "v1"} scheme.AddKnownTypes(pxcSchemeGroupVersion, &pxcv1.PerconaXtraDBCluster{}, &pxcv1.PerconaXtraDBClusterList{}) @@ -2592,18 +2639,7 @@ func (r *DatabaseClusterReconciler) addPXCKnownTypes(scheme *runtime.Scheme) err } func (r *DatabaseClusterReconciler) addPSMDBKnownTypes(scheme *runtime.Scheme) error { - version, err := r.getOperatorVersion(context.Background(), types.NamespacedName{ - Name: psmdbDeploymentName, - Namespace: os.Getenv("WATCH_NAMESPACE"), - }) - if err != nil { - return err - } - psmdbSchemeGroupVersion := schema.GroupVersion{Group: psmdbAPIGroup, Version: strings.ReplaceAll("v"+version.String(), ".", "-")} - ver, _ := goversion.NewVersion("v1.12.0") - if version.version.GreaterThan(ver) { - psmdbSchemeGroupVersion = schema.GroupVersion{Group: psmdbAPIGroup, Version: "v1"} - } + psmdbSchemeGroupVersion := schema.GroupVersion{Group: psmdbAPIGroup, Version: "v1"} scheme.AddKnownTypes(psmdbSchemeGroupVersion, &psmdbv1.PerconaServerMongoDB{}, &psmdbv1.PerconaServerMongoDBList{}) @@ -2636,7 +2672,7 @@ func (r *DatabaseClusterReconciler) addPGToScheme(scheme *runtime.Scheme) error } // SetupWithManager sets up the controller with the Manager. -func (r *DatabaseClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *DatabaseClusterReconciler) SetupWithManager(mgr ctrl.Manager, defaultNamespace string) error { if err := r.initIndexers(context.Background(), mgr); err != nil { return err } @@ -2669,6 +2705,7 @@ func (r *DatabaseClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { } r.initWatchers(controller) + r.defaultNamespace = defaultNamespace return controller.Complete(r) } @@ -3258,3 +3295,65 @@ func (r *DatabaseClusterReconciler) defaultPSMDBSpec() *psmdbv1.PerconaServerMon }, } } + +func (r *DatabaseClusterReconciler) reconcileBackupStorageSecret( //nolint:dupl + ctx context.Context, + backupStorage *everestv1alpha1.BackupStorage, + database *everestv1alpha1.DatabaseCluster, +) error { + secret := &corev1.Secret{} + err := r.Get(ctx, types.NamespacedName{Name: backupStorage.Spec.CredentialsSecretName, Namespace: database.Namespace}, secret) + if err != nil && !k8serrors.IsNotFound(err) { + return err + } + if secret.Name != "" { + return nil + } + + err = r.Get(ctx, types.NamespacedName{Name: backupStorage.Spec.CredentialsSecretName, Namespace: r.defaultNamespace}, secret) + if err != nil { + return err + } + secret.ObjectMeta = metav1.ObjectMeta{ + Namespace: database.Namespace, + Name: backupStorage.Spec.CredentialsSecretName, + Labels: map[string]string{ + labelBackupStorageName: backupStorage.Name, + }, + } + if !backupStorage.IsNamespaceAllowed(database.Namespace) { + return fmt.Errorf("%s namespace is not allowed to use for %s backup storage", database.Namespace, backupStorage.Name) + } + return r.Create(ctx, secret) +} + +func (r *DatabaseClusterReconciler) reconcileMonitoringConfigSecret( //nolint:dupl + ctx context.Context, + monitoringConfig *everestv1alpha1.MonitoringConfig, + database *everestv1alpha1.DatabaseCluster, +) error { + secret := &corev1.Secret{} + err := r.Get(ctx, types.NamespacedName{Name: monitoringConfig.Spec.CredentialsSecretName, Namespace: database.Namespace}, secret) + if err != nil && !k8serrors.IsNotFound(err) { + return err + } + if secret.Name != "" { + return nil + } + + err = r.Get(ctx, types.NamespacedName{Name: monitoringConfig.Spec.CredentialsSecretName, Namespace: r.defaultNamespace}, secret) + if err != nil { + return err + } + secret.ObjectMeta = metav1.ObjectMeta{ + Namespace: database.Namespace, + Name: monitoringConfig.Spec.CredentialsSecretName, + Labels: map[string]string{ + labelMonitoringConfigName: monitoringConfig.Name, + }, + } + if !monitoringConfig.IsNamespaceAllowed(database.Namespace) { + return fmt.Errorf("%s namespace is not allowed to use for %s backup storage", database.Namespace, monitoringConfig.Name) + } + return r.Create(ctx, secret) +} diff --git a/controllers/databaseengine_controller.go b/controllers/databaseengine_controller.go index 98b28984..d2e3060e 100644 --- a/controllers/databaseengine_controller.go +++ b/controllers/databaseengine_controller.go @@ -17,7 +17,6 @@ package controllers import ( "context" - "os" "strings" appsv1 "k8s.io/api/apps/v1" @@ -156,36 +155,37 @@ func (r *DatabaseEngineReconciler) getOperatorStatus(ctx context.Context, name t } // SetupWithManager sets up the controller with the Manager. -func (r *DatabaseEngineReconciler) SetupWithManager(mgr ctrl.Manager) error { +func (r *DatabaseEngineReconciler) SetupWithManager(mgr ctrl.Manager, namespaces []string) error { // There's a good chance that the reconciler's client cache is not started // yet so we use the client.Reader returned from manager.GetAPIReader() to // hit the API server directly and avoid an ErrCacheNotStarted. clientReader := mgr.GetAPIReader() r.versionService = NewVersionService() + for _, namespaceName := range namespaces { + namespaceName := namespaceName + for operatorName, engineType := range operatorEngine { + dbEngine := &everestv1alpha1.DatabaseEngine{ + ObjectMeta: metav1.ObjectMeta{ + Name: operatorName, + Namespace: namespaceName, + }, + Spec: everestv1alpha1.DatabaseEngineSpec{ + Type: engineType, + }, + } - for operatorName, engineType := range operatorEngine { - dbEngine := &everestv1alpha1.DatabaseEngine{ - ObjectMeta: metav1.ObjectMeta{ - Name: operatorName, - Namespace: os.Getenv("WATCH_NAMESPACE"), - }, - Spec: everestv1alpha1.DatabaseEngineSpec{ - Type: engineType, - }, - } - - found := &everestv1alpha1.DatabaseEngine{} - err := clientReader.Get(context.Background(), types.NamespacedName{Name: dbEngine.Name, Namespace: dbEngine.Namespace}, found) - if err != nil && apierrors.IsNotFound(err) { - err = r.Create(context.Background(), dbEngine) - if err != nil { + found := &everestv1alpha1.DatabaseEngine{} + err := clientReader.Get(context.Background(), types.NamespacedName{Name: dbEngine.Name, Namespace: dbEngine.Namespace}, found) + if err != nil && apierrors.IsNotFound(err) { + err = r.Create(context.Background(), dbEngine) + if err != nil { + return err + } + } else if err != nil { return err } - } else if err != nil { - return err } } - return ctrl.NewControllerManagedBy(mgr). For(&everestv1alpha1.DatabaseEngine{}). Watches(&appsv1.Deployment{}, &handler.EnqueueRequestForObject{}). diff --git a/controllers/monitoringconfig_controller.go b/controllers/monitoringconfig_controller.go new file mode 100644 index 00000000..989c82f0 --- /dev/null +++ b/controllers/monitoringconfig_controller.go @@ -0,0 +1,185 @@ +// everest-operator +// Copyright (C) 2022 Percona LLC +// +// 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" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" +) + +const ( + labelMonitoringConfigName = "percona.com/monitoring-config-name" +) + +// MonitoringConfigReconciler reconciles a MonitoringConfig object. +type MonitoringConfigReconciler struct { + client.Client + Scheme *runtime.Scheme + defaultNamespace string +} + +//+kubebuilder:rbac:groups=everest.percona.com,resources=monitoringconfigs,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=everest.percona.com,resources=monitoringconfigs/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=everest.percona.com,resources=monitoringconfigs/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. +// Modify the Reconcile function to compare the state specified by +// the DatabaseClusterBackup 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 *MonitoringConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { //nolint:dupl + mc := &everestv1alpha1.MonitoringConfig{} + logger := log.FromContext(ctx) + monitoringConfigNamespace := req.NamespacedName.Namespace + if req.NamespacedName.Namespace != r.defaultNamespace { + monitoringConfigNamespace = r.defaultNamespace + } + + err := r.Get(ctx, types.NamespacedName{Name: req.NamespacedName.Name, Namespace: monitoringConfigNamespace}, mc) + if err != nil { + // NotFound cannot be fixed by requeuing so ignore it. During background + // deletion, we receive delete events from cluster's dependents after + // cluster is deleted. + if err = client.IgnoreNotFound(err); err != nil { + logger.Error(err, "unable to fetch BackupStorage") + } + return reconcile.Result{}, err + } + if mc.DeletionTimestamp != nil { + logger.Info("cleaning up the secrets across namespaces") + if err := r.handleDelete(ctx, mc); err != nil { + return ctrl.Result{}, err + } + logger.Info("all secrets were removed") + controllerutil.RemoveFinalizer(mc, cleanupSecretsFinalizer) + if err := r.Update(ctx, mc); err != nil { + return ctrl.Result{}, err + } + } + defaultSecret := &corev1.Secret{} + err = r.Get(ctx, types.NamespacedName{Name: req.NamespacedName.Name, Namespace: r.defaultNamespace}, defaultSecret) + if err != nil { + if err = client.IgnoreNotFound(err); err != nil { + logger.Error(err, "unable to fetch Secret") + } + return ctrl.Result{}, err + } + var needsUpdate bool + if req.NamespacedName.Namespace == r.defaultNamespace { + logger.Info("setting controller references for the secret") + needsUpdate, err = r.reconcileMonitoringConfig(ctx, mc, defaultSecret) + if err != nil { + return ctrl.Result{}, err + } + if !controllerutil.ContainsFinalizer(mc, cleanupSecretsFinalizer) { + controllerutil.AddFinalizer(mc, cleanupSecretsFinalizer) + if err := r.Update(ctx, mc); err != nil { + return ctrl.Result{}, err + } + } + } + + logger.Info("updating secrets in used namespaces") + if err := r.handleSecretUpdate(ctx, mc, defaultSecret); err != nil { + return ctrl.Result{}, err + } + if needsUpdate { + err := r.Status().Update(ctx, mc) + if err != nil { + return ctrl.Result{}, err + } + } + + return ctrl.Result{}, nil +} + +func (r *MonitoringConfigReconciler) handleDelete(ctx context.Context, mc *everestv1alpha1.MonitoringConfig) error { + for namespace := range mc.Status.UsedNamespaces { + if namespace == r.defaultNamespace { + continue + } + secret := &corev1.Secret{} + err := r.Get(ctx, types.NamespacedName{Name: mc.Name, Namespace: namespace}, secret) + if err != nil { + return err + } + err = r.Delete(ctx, secret) + if err != nil { + return err + } + } + return nil +} + +func (r *MonitoringConfigReconciler) handleSecretUpdate(ctx context.Context, mc *everestv1alpha1.MonitoringConfig, defaultSecret *corev1.Secret) error { + for namespace := range mc.Status.UsedNamespaces { + if namespace == r.defaultNamespace { + continue + } + secret := &corev1.Secret{} + err := r.Get(ctx, types.NamespacedName{Name: mc.Name, Namespace: namespace}, secret) + if err != nil { + return err + } + secret.Data = defaultSecret.Data + secret.Type = defaultSecret.Type + secret.StringData = defaultSecret.StringData + err = r.Update(ctx, secret) + if err != nil { + return err + } + } + return nil +} + +func (r *MonitoringConfigReconciler) reconcileMonitoringConfig(ctx context.Context, mc *everestv1alpha1.MonitoringConfig, defaultSecret *corev1.Secret) (bool, error) { + err := controllerutil.SetControllerReference(mc, defaultSecret, r.Client.Scheme()) + if err != nil { + return false, err + } + if err = r.Update(ctx, defaultSecret); err != nil { + return false, err + } + + if mc.UpdateNamespacesList(defaultSecret.Namespace) { + if err := r.Status().Update(ctx, mc); err != nil { + return false, err + } + } + return true, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *MonitoringConfigReconciler) SetupWithManager(mgr ctrl.Manager, defaultNamespace string) error { + r.defaultNamespace = defaultNamespace + return ctrl.NewControllerManagedBy(mgr). + For(&everestv1alpha1.MonitoringConfig{}). + Complete(r) +} diff --git a/controllers/secrets.go b/controllers/secrets.go new file mode 100644 index 00000000..300eba46 --- /dev/null +++ b/controllers/secrets.go @@ -0,0 +1,179 @@ +// everest-operator +// Copyright (C) 2022 Percona LLC +// +// 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" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" +) + +// SecretReconciler reconciles a Secret object. +type SecretReconciler struct { + client.Client + Scheme *runtime.Scheme + defaultNamespace string +} + +//+kubebuilder:rbac:groups=everest.percona.com,resources=backupstorages,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=everest.percona.com,resources=backupstorages/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=everest.percona.com,resources=backupstorages/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. +// Modify the Reconcile function to compare the state specified by +// the DatabaseClusterBackup 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 *SecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + secret := &corev1.Secret{} + err := r.Get(ctx, req.NamespacedName, secret) + if err != nil { + if err = client.IgnoreNotFound(err); err != nil { + logger.Error(err, "unable to fetch Secret") + } + return ctrl.Result{}, err + } + if _, ok := secret.Labels[labelBackupStorageName]; ok { + if err := r.reconcileBackupStorageSecret(ctx, req, secret); err != nil { + return ctrl.Result{}, err + } + } + if _, ok := secret.Labels[labelMonitoringConfigName]; ok { + if err := r.reconcileMonitoringConfigSecret(ctx, req, secret); err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, nil +} + +func (r *SecretReconciler) reconcileMonitoringConfigSecret(ctx context.Context, req ctrl.Request, secret *corev1.Secret) error { //nolint:dupl + logger := log.FromContext(ctx) + mc := &everestv1alpha1.MonitoringConfig{} + err := r.Get(ctx, types.NamespacedName{Name: req.NamespacedName.Name, Namespace: r.defaultNamespace}, mc) + if err != nil { + // NotFound cannot be fixed by requeuing so ignore it. During background + // deletion, we receive delete events from cluster's dependents after + // cluster is deleted. + if err = client.IgnoreNotFound(err); err != nil { + logger.Error(err, "unable to fetch BackupStorage") + } + return err + } + var needsUpdate bool + if secret.DeletionTimestamp == nil && mc.DeletionTimestamp == nil && mc.UpdateNamespacesList(req.NamespacedName.Namespace) { + needsUpdate = true + } + if secret.DeletionTimestamp != nil && mc.DeletionTimestamp == nil { + if mc.DeleteUsedNamespace(secret.Namespace) { + logger.Info("Status updated") + needsUpdate = true + } + } + if needsUpdate { + if err := r.Status().Update(ctx, mc); err != nil { + return err + } + } + return nil +} + +func (r *SecretReconciler) reconcileBackupStorageSecret(ctx context.Context, req ctrl.Request, secret *corev1.Secret) error { //nolint:dupl + logger := log.FromContext(ctx) + bs := &everestv1alpha1.BackupStorage{} + err := r.Get(ctx, types.NamespacedName{Name: req.NamespacedName.Name, Namespace: r.defaultNamespace}, bs) + if err != nil { + // NotFound cannot be fixed by requeuing so ignore it. During background + // deletion, we receive delete events from cluster's dependents after + // cluster is deleted. + if err = client.IgnoreNotFound(err); err != nil { + logger.Error(err, "unable to fetch BackupStorage") + } + return err + } + + var needsUpdate bool + if secret.DeletionTimestamp == nil && bs.DeletionTimestamp == nil && bs.UpdateNamespacesList(req.NamespacedName.Namespace) { + needsUpdate = true + } + if secret.DeletionTimestamp != nil && bs.DeletionTimestamp == nil { + if bs.DeleteUsedNamespace(secret.Namespace) { + logger.Info("Status updated") + needsUpdate = true + } + } + if needsUpdate { + if err := r.Status().Update(ctx, bs); err != nil { + return err + } + } + return nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *SecretReconciler) SetupWithManager(mgr ctrl.Manager, defaultNamespace string) error { + r.defaultNamespace = defaultNamespace + return ctrl.NewControllerManagedBy(mgr). + For(&corev1.Secret{}). + WithEventFilter(filterSecretsFunc()). + Complete(r) +} + +func filterSecretsFunc() predicate.Predicate { //nolint:ireturn + return predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + if _, ok := e.Object.GetLabels()[labelBackupStorageName]; ok { + return true + } + if _, ok := e.Object.GetLabels()[labelMonitoringConfigName]; ok { + return true + } + return false + }, + + UpdateFunc: func(e event.UpdateEvent) bool { + if _, ok := e.ObjectNew.GetLabels()[labelBackupStorageName]; ok { + return true + } + if _, ok := e.ObjectNew.GetLabels()[labelMonitoringConfigName]; ok { + return true + } + return false + }, + DeleteFunc: func(e event.DeleteEvent) bool { + if _, ok := e.Object.GetLabels()[labelBackupStorageName]; ok { + return true + } + if _, ok := e.Object.GetLabels()[labelMonitoringConfigName]; ok { + return true + } + return false + }, + } +} diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index b457cd08..1b86e2e2 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -58,6 +58,11 @@ spec: region: description: Region is a region where the bucket is located. type: string + targetNamespaces: + description: TargetNamespaces is the list of namespaces where the operator will copy secrets provided in the CredentialsSecretsName. + items: + type: string + type: array type: description: Type is a type of backup storage. enum: @@ -71,6 +76,13 @@ spec: type: object status: description: BackupStorageStatus defines the observed state of BackupStorage. + properties: + usedNamespaces: + additionalProperties: + type: boolean + type: object + required: + - usedNamespaces type: object type: object served: true @@ -828,6 +840,11 @@ spec: - image - url type: object + targetNamespaces: + description: TargetNamespaces is the list of namespaces where the operator will copy secrets provided in the CredentialsSecretsName. + items: + type: string + type: array type: description: Type is type of monitoring. enum: @@ -839,6 +856,13 @@ spec: type: object status: description: MonitoringConfigStatus defines the observed state of MonitoringConfig. + properties: + usedNamespaces: + additionalProperties: + type: boolean + type: object + required: + - usedNamespaces type: object type: object served: true @@ -950,6 +974,20 @@ rules: - patch - update - watch +- apiGroups: + - everest.percona.com + resources: + - backupstorages/finalizers + verbs: + - update +- apiGroups: + - everest.percona.com + resources: + - backupstorages/status + verbs: + - get + - patch + - update - apiGroups: - everest.percona.com resources: @@ -1066,6 +1104,20 @@ rules: - patch - update - watch +- apiGroups: + - everest.percona.com + resources: + - monitoringconfigs/finalizers + verbs: + - update +- apiGroups: + - everest.percona.com + resources: + - monitoringconfigs/status + verbs: + - get + - patch + - update - apiGroups: - pgv2.percona.com resources: @@ -1384,11 +1436,11 @@ spec: command: - /manager env: - - name: WATCH_NAMESPACE + - name: DEFAULT_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - image: docker.io/perconalab/everest-operator:0.5.0-dev2 + image: docker.io/perconalab/everest-operator:0.6.0-dev1 livenessProbe: httpGet: path: /healthz diff --git a/e2e-tests/tests/core/dbengine/00-install-dbaas.yaml b/e2e-tests/tests/core/dbengine/00-install-dbaas.yaml index 02f6b80d..c0315c5d 100644 --- a/e2e-tests/tests/core/dbengine/00-install-dbaas.yaml +++ b/e2e-tests/tests/core/dbengine/00-install-dbaas.yaml @@ -2,5 +2,5 @@ apiVersion: kuttl.dev/v1 kind: TestStep timeout: 10 commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8085 -health-probe-bind-address :8086 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8085 -health-probe-bind-address :8086 background: true diff --git a/e2e-tests/tests/core/pg/01-deploy-dbaas.yaml b/e2e-tests/tests/core/pg/01-deploy-dbaas.yaml index 2935d494..eab6eb56 100644 --- a/e2e-tests/tests/core/pg/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/core/pg/01-deploy-dbaas.yaml @@ -2,6 +2,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep timeout: 10 commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8091 -health-probe-bind-address :8092 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8091 -health-probe-bind-address :8092 background: true skipLogOutput: true diff --git a/e2e-tests/tests/core/psmdb/01-deploy-dbaas.yaml b/e2e-tests/tests/core/psmdb/01-deploy-dbaas.yaml index f16ca465..57ef3e4c 100644 --- a/e2e-tests/tests/core/psmdb/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/core/psmdb/01-deploy-dbaas.yaml @@ -2,6 +2,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep timeout: 10 commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8082 -health-probe-bind-address :8083 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8082 -health-probe-bind-address :8083 background: true skipLogOutput: true diff --git a/e2e-tests/tests/core/pxc/01-deploy-dbaas.yaml b/e2e-tests/tests/core/pxc/01-deploy-dbaas.yaml index 49e0c899..07dfe66f 100644 --- a/e2e-tests/tests/core/pxc/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/core/pxc/01-deploy-dbaas.yaml @@ -2,6 +2,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep commands: - command: kubectl apply -f https://raw.githubusercontent.com/percona/percona-xtradb-cluster-operator/v${PXC_OPERATOR_VERSION}/deploy/bundle.yaml -n "${NAMESPACE}" - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager background: true skipLogOutput: true diff --git a/e2e-tests/tests/features/dbbackup_pg/01-deploy-dbaas.yaml b/e2e-tests/tests/features/dbbackup_pg/01-deploy-dbaas.yaml index 7aae2872..4bbcc912 100644 --- a/e2e-tests/tests/features/dbbackup_pg/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/features/dbbackup_pg/01-deploy-dbaas.yaml @@ -2,6 +2,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep timeout: 10 commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8071 -health-probe-bind-address :8072 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8071 -health-probe-bind-address :8072 background: true skipLogOutput: true diff --git a/e2e-tests/tests/features/dbbackup_pg/90-delete-clusters.yaml b/e2e-tests/tests/features/dbbackup_pg/90-delete-clusters.yaml index 9f9ba519..8b46f756 100644 --- a/e2e-tests/tests/features/dbbackup_pg/90-delete-clusters.yaml +++ b/e2e-tests/tests/features/dbbackup_pg/90-delete-clusters.yaml @@ -2,5 +2,7 @@ apiVersion: kuttl.dev/v1 kind: TestStep commands: - command: kubectl -n $NAMESPACE delete db test-pg-cluster + - command: kubectl patch backupstorage test-storage-scheduled -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true - command: kubectl patch postgresclusters test-pg-cluster -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge ignoreFailure: true diff --git a/e2e-tests/tests/features/dbbackup_psmdb/01-deploy-dbaas.yaml b/e2e-tests/tests/features/dbbackup_psmdb/01-deploy-dbaas.yaml index d7d3bc34..070b774d 100644 --- a/e2e-tests/tests/features/dbbackup_psmdb/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/features/dbbackup_psmdb/01-deploy-dbaas.yaml @@ -2,6 +2,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep timeout: 10 commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8051 -health-probe-bind-address :8052 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8051 -health-probe-bind-address :8052 background: true skipLogOutput: true diff --git a/e2e-tests/tests/features/dbbackup_psmdb/90-delete-cluster.yaml b/e2e-tests/tests/features/dbbackup_psmdb/90-delete-cluster.yaml index 031e32a9..33f620bd 100644 --- a/e2e-tests/tests/features/dbbackup_psmdb/90-delete-cluster.yaml +++ b/e2e-tests/tests/features/dbbackup_psmdb/90-delete-cluster.yaml @@ -4,3 +4,5 @@ commands: - command: kubectl -n $NAMESPACE delete db test-psmdb-cluster - command: kubectl patch psmdb test-psmdb-cluster -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge ignoreFailure: true + - command: kubectl patch backupstorage test-storage-scheduled -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true diff --git a/e2e-tests/tests/features/dbbackup_pxc/01-deploy-dbaas.yaml b/e2e-tests/tests/features/dbbackup_pxc/01-deploy-dbaas.yaml index e7d933c5..2495b3ba 100644 --- a/e2e-tests/tests/features/dbbackup_pxc/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/features/dbbackup_pxc/01-deploy-dbaas.yaml @@ -1,6 +1,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8061 -health-probe-bind-address :8062 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8061 -health-probe-bind-address :8062 background: true skipLogOutput: true diff --git a/e2e-tests/tests/features/dbbackup_pxc/90-delete-cluster.yaml b/e2e-tests/tests/features/dbbackup_pxc/90-delete-cluster.yaml index 71c6cf8f..20f79f3f 100644 --- a/e2e-tests/tests/features/dbbackup_pxc/90-delete-cluster.yaml +++ b/e2e-tests/tests/features/dbbackup_pxc/90-delete-cluster.yaml @@ -2,5 +2,7 @@ apiVersion: kuttl.dev/v1 kind: TestStep commands: - command: kubectl -n $NAMESPACE delete db test-pxc-cluster + - command: kubectl patch backupstorage test-storage-scheduled -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true - command: kubectl patch pxc test-pxc-cluster -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge ignoreFailure: true diff --git a/e2e-tests/tests/features/monitoringconfig_pg/00-deploy-operators.yaml b/e2e-tests/tests/features/monitoringconfig_pg/00-deploy-operators.yaml index 413826ad..2bf9ba95 100644 --- a/e2e-tests/tests/features/monitoringconfig_pg/00-deploy-operators.yaml +++ b/e2e-tests/tests/features/monitoringconfig_pg/00-deploy-operators.yaml @@ -3,5 +3,5 @@ kind: TestStep timeout: 10 commands: - command: kubectl apply --server-side -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/v${PG_OPERATOR_VERSION}/deploy/bundle.yaml -n "${NAMESPACE}" - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :0 -health-probe-bind-address :0 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :0 -health-probe-bind-address :0 background: true diff --git a/e2e-tests/tests/features/monitoringconfig_pg/96-delete-clusters.yaml b/e2e-tests/tests/features/monitoringconfig_pg/96-delete-clusters.yaml index 0cd5b0e7..5007c618 100644 --- a/e2e-tests/tests/features/monitoringconfig_pg/96-delete-clusters.yaml +++ b/e2e-tests/tests/features/monitoringconfig_pg/96-delete-clusters.yaml @@ -2,5 +2,7 @@ apiVersion: kuttl.dev/v1 kind: TestStep commands: - command: kubectl -n $NAMESPACE delete db pg-mc + - command: kubectl patch monitoringconfig test-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true - command: kubectl patch postgresclusters pg-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge ignoreFailure: true diff --git a/e2e-tests/tests/features/monitoringconfig_psmdb/00-deploy-operators.yaml b/e2e-tests/tests/features/monitoringconfig_psmdb/00-deploy-operators.yaml index 4b8621d8..422f1ec0 100644 --- a/e2e-tests/tests/features/monitoringconfig_psmdb/00-deploy-operators.yaml +++ b/e2e-tests/tests/features/monitoringconfig_psmdb/00-deploy-operators.yaml @@ -3,5 +3,5 @@ kind: TestStep timeout: 10 commands: - command: kubectl apply --server-side -f https://raw.githubusercontent.com/percona/percona-server-mongodb-operator/v${PSMDB_OPERATOR_VERSION}/deploy/bundle.yaml -n "${NAMESPACE}" - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :0 -health-probe-bind-address :0 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :0 -health-probe-bind-address :0 background: true diff --git a/e2e-tests/tests/features/monitoringconfig_psmdb/96-delete-clusters.yaml b/e2e-tests/tests/features/monitoringconfig_psmdb/96-delete-clusters.yaml index 190aac96..289ea32a 100644 --- a/e2e-tests/tests/features/monitoringconfig_psmdb/96-delete-clusters.yaml +++ b/e2e-tests/tests/features/monitoringconfig_psmdb/96-delete-clusters.yaml @@ -4,3 +4,5 @@ commands: - command: kubectl -n $NAMESPACE delete db mongo-mc - command: kubectl patch psmdb mongo-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge ignoreFailure: true + - command: kubectl patch monitoringconfig test-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true diff --git a/e2e-tests/tests/features/monitoringconfig_pxc/00-deploy-operators.yaml b/e2e-tests/tests/features/monitoringconfig_pxc/00-deploy-operators.yaml index 8ffa67dd..4335dbcd 100644 --- a/e2e-tests/tests/features/monitoringconfig_pxc/00-deploy-operators.yaml +++ b/e2e-tests/tests/features/monitoringconfig_pxc/00-deploy-operators.yaml @@ -2,5 +2,5 @@ apiVersion: kuttl.dev/v1 kind: TestStep commands: - command: kubectl apply -f https://raw.githubusercontent.com/percona/percona-xtradb-cluster-operator/v${PXC_OPERATOR_VERSION}/deploy/bundle.yaml -n "${NAMESPACE}" - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :0 -health-probe-bind-address :0 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :0 -health-probe-bind-address :0 background: true diff --git a/e2e-tests/tests/features/monitoringconfig_pxc/96-delete-clusters.yaml b/e2e-tests/tests/features/monitoringconfig_pxc/96-delete-clusters.yaml index b74001bb..aec60882 100644 --- a/e2e-tests/tests/features/monitoringconfig_pxc/96-delete-clusters.yaml +++ b/e2e-tests/tests/features/monitoringconfig_pxc/96-delete-clusters.yaml @@ -4,3 +4,5 @@ commands: - command: kubectl -n $NAMESPACE delete db pxc-mc - command: kubectl patch pxc pxc-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge ignoreFailure: true + - command: kubectl patch monitoringconfig test-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true diff --git a/e2e-tests/tests/features/multinamespace_pg/00-deploy-operators.yaml b/e2e-tests/tests/features/multinamespace_pg/00-deploy-operators.yaml new file mode 100644 index 00000000..d3c6c562 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/00-deploy-operators.yaml @@ -0,0 +1,7 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +timeout: 10 +commands: + - command: kubectl create ns kuttl-test-pg + - command: kubectl apply --server-side -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/v${PG_OPERATOR_VERSION}/deploy/bundle.yaml -n "${NAMESPACE}" + - command: kubectl apply --server-side -f https://raw.githubusercontent.com/percona/percona-postgresql-operator/v${PG_OPERATOR_VERSION}/deploy/bundle.yaml -n kuttl-test-pg diff --git a/e2e-tests/tests/features/multinamespace_pg/01-assert.yaml b/e2e-tests/tests/features/multinamespace_pg/01-assert.yaml new file mode 100644 index 00000000..dcd89874 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/01-assert.yaml @@ -0,0 +1,65 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 120 +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: perconapgclusters.pgv2.percona.com +spec: + group: pgv2.percona.com + names: + kind: PerconaPGCluster + listKind: PerconaPGClusterList + plural: perconapgclusters + singular: perconapgcluster + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: databaseclusters.everest.percona.com +spec: + group: everest.percona.com + names: + kind: DatabaseCluster + listKind: DatabaseClusterList + plural: databaseclusters + shortNames: + - db + - dbc + - dbcluster + singular: databasecluster + scope: Namespaced +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: percona-postgresql-operator +status: + availableReplicas: 1 + observedGeneration: 1 + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: percona-postgresql-operator + namespace: kuttl-test-pg +status: + availableReplicas: 1 + observedGeneration: 1 + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 +--- +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseEngine +metadata: + name: percona-postgresql-operator +spec: + type: postgresql +status: + status: installed diff --git a/e2e-tests/tests/features/multinamespace_pg/01-deploy-dbaas.yaml b/e2e-tests/tests/features/multinamespace_pg/01-deploy-dbaas.yaml new file mode 100644 index 00000000..85aee5f3 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/01-deploy-dbaas.yaml @@ -0,0 +1,7 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +timeout: 10 +commands: + - script: DEFAULT_NAMESPACE=$NAMESPACE WATCH_NAMESPACES=$NAMESPACE,kuttl-test-pg ../../../../bin/manager -metrics-bind-address :8079 -health-probe-bind-address :8078 + background: true + skipLogOutput: true diff --git a/e2e-tests/tests/features/multinamespace_pg/10-assert.yaml b/e2e-tests/tests/features/multinamespace_pg/10-assert.yaml new file mode 100644 index 00000000..bbdbadb2 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/10-assert.yaml @@ -0,0 +1,97 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 120 +--- +apiVersion: everest.percona.com/v1alpha1 +kind: MonitoringConfig +metadata: + name: test-mc +spec: + type: pmm + credentialsSecretName: test-mc + pmm: + url: http://localhost + image: percona/pmm-client:latest +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: everest.percona.com/v1alpha1 +kind: BackupStorage +metadata: + name: test-storage-scheduled +spec: + type: s3 + bucket: test-backup-bucket-scheduled + credentialsSecretName: test-storage-scheduled + region: us-east-2 + endpointURL: s3.amazonaws.com +--- +--- +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGCluster +metadata: + name: test-pg-cluster +spec: + instances: + - dataVolumeClaimSpec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1G + name: instance1 + replicas: 1 + port: 5432 + pmm: + enabled: true + serverHost: localhost + image: percona/pmm-client:latest + secret: everest-secrets-test-pg-cluster-pmm + resources: + limits: + memory: "128Mi" + cpu: "500m" + proxy: + pgBouncer: + port: 5432 + replicas: 1 + expose: + type: ClusterIP + backups: + pgbackrest: + configuration: + - secret: + name: test-pg-cluster-pgbackrest-secrets + global: + repo1-retention-full: "1" + repo2-retention-full: "1" + repos: + - name: repo1 + volume: + volumeClaimSpec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1G + - name: repo2 + s3: + bucket: test-backup-bucket-scheduled + endpoint: s3.amazonaws.com + region: us-east-2 + schedules: + full: 0 0 * * * diff --git a/e2e-tests/tests/features/multinamespace_pg/10-pg-cluster-with-schedule.yaml b/e2e-tests/tests/features/multinamespace_pg/10-pg-cluster-with-schedule.yaml new file mode 100644 index 00000000..27d658a7 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/10-pg-cluster-with-schedule.yaml @@ -0,0 +1,69 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +--- +apiVersion: everest.percona.com/v1alpha1 +kind: MonitoringConfig +metadata: + name: test-mc +spec: + type: pmm + credentialsSecretName: test-mc + pmm: + url: http://localhost + image: percona/pmm-client:latest +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: everest.percona.com/v1alpha1 +kind: BackupStorage +metadata: + name: test-storage-scheduled +spec: + type: s3 + bucket: test-backup-bucket-scheduled + credentialsSecretName: test-storage-scheduled + region: us-east-2 + endpointURL: s3.amazonaws.com +--- +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseCluster +metadata: + name: test-pg-cluster +spec: + monitoring: + resources: + limits: + memory: "128Mi" + cpu: "500m" + monitoringConfigName: test-mc + image: percona/pmm-client:latest + engine: + type: postgresql + replicas: 1 + storage: + size: 1G + proxy: + type: pgbouncer + replicas: 1 + backup: + enabled: true + schedules: + - name: daily-backup + enabled: true + schedule: "0 0 * * *" + retentionCopies: 1 + backupStorageName: test-storage-scheduled diff --git a/e2e-tests/tests/features/multinamespace_pg/20-assert.yaml b/e2e-tests/tests/features/multinamespace_pg/20-assert.yaml new file mode 100644 index 00000000..c3b5be82 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/20-assert.yaml @@ -0,0 +1,77 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 120 +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc + namespace: kuttl-test-pg +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled + namespace: kuttl-test-pg +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: pgv2.percona.com/v2 +kind: PerconaPGCluster +metadata: + name: test-pg-cluster + namespace: kuttl-test-pg +spec: + instances: + - dataVolumeClaimSpec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1G + name: instance1 + replicas: 1 + port: 5432 + pmm: + enabled: true + serverHost: localhost + image: percona/pmm-client:latest + secret: everest-secrets-test-pg-cluster-pmm + resources: + limits: + memory: "128Mi" + cpu: "500m" + proxy: + pgBouncer: + port: 5432 + replicas: 1 + expose: + type: ClusterIP + backups: + pgbackrest: + configuration: + - secret: + name: test-pg-cluster-pgbackrest-secrets + global: + repo1-retention-full: "1" + repo2-retention-full: "1" + repos: + - name: repo1 + volume: + volumeClaimSpec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1G + - name: repo2 + s3: + bucket: test-backup-bucket-scheduled + endpoint: s3.amazonaws.com + region: us-east-2 + schedules: + full: 0 0 * * * diff --git a/e2e-tests/tests/features/multinamespace_pg/20-pg-cluster-with-schedule.yaml b/e2e-tests/tests/features/multinamespace_pg/20-pg-cluster-with-schedule.yaml new file mode 100644 index 00000000..3ef68898 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/20-pg-cluster-with-schedule.yaml @@ -0,0 +1,31 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseCluster +metadata: + name: test-pg-cluster + namespace: kuttl-test-pg +spec: + monitoring: + resources: + limits: + memory: "128Mi" + cpu: "500m" + monitoringConfigName: test-mc + image: percona/pmm-client:latest + engine: + type: postgresql + replicas: 1 + storage: + size: 1G + proxy: + type: pgbouncer + replicas: 1 + backup: + enabled: true + schedules: + - name: daily-backup + enabled: true + schedule: "0 0 * * *" + retentionCopies: 1 + backupStorageName: test-storage-scheduled diff --git a/e2e-tests/tests/features/multinamespace_pg/90-delete-clusters.yaml b/e2e-tests/tests/features/multinamespace_pg/90-delete-clusters.yaml new file mode 100644 index 00000000..0143d5c8 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/90-delete-clusters.yaml @@ -0,0 +1,13 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +commands: + - command: kubectl -n $NAMESPACE delete db test-pg-cluster + - command: kubectl patch postgresclusters test-pg-cluster -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl -n kuttl-test-pg delete db test-pg-cluster + - command: kubectl patch postgresclusters test-pg-cluster -n kuttl-test-pg -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl patch monitoringconfig test-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl patch backupstorage test-storage-scheduled -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true diff --git a/e2e-tests/tests/features/multinamespace_pg/98-drop-pvc.yaml b/e2e-tests/tests/features/multinamespace_pg/98-drop-pvc.yaml new file mode 100644 index 00000000..4620f0b6 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pg/98-drop-pvc.yaml @@ -0,0 +1,9 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +delete: +- apiVersion: v1 + kind: PersistentVolumeClaim +- apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + namespace: kuttl-test-pg diff --git a/e2e-tests/tests/features/multinamespace_psmdb/00-deploy-operators.yaml b/e2e-tests/tests/features/multinamespace_psmdb/00-deploy-operators.yaml new file mode 100644 index 00000000..c05721c8 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/00-deploy-operators.yaml @@ -0,0 +1,7 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +timeout: 10 +commands: + - command: kubectl create ns kuttl-test-psmdb + - command: kubectl apply --server-side -f https://raw.githubusercontent.com/percona/percona-server-mongodb-operator/v${PSMDB_OPERATOR_VERSION}/deploy/bundle.yaml -n kuttl-test-psmdb + - command: kubectl apply --server-side -f https://raw.githubusercontent.com/percona/percona-server-mongodb-operator/v${PSMDB_OPERATOR_VERSION}/deploy/bundle.yaml -n "${NAMESPACE}" diff --git a/e2e-tests/tests/features/multinamespace_psmdb/01-assert.yaml b/e2e-tests/tests/features/multinamespace_psmdb/01-assert.yaml new file mode 100644 index 00000000..5d6ad234 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/01-assert.yaml @@ -0,0 +1,67 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 120 +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: perconaservermongodbs.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDB + listKind: PerconaServerMongoDBList + plural: perconaservermongodbs + shortNames: + - psmdb + singular: perconaservermongodb + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: databaseclusters.everest.percona.com +spec: + group: everest.percona.com + names: + kind: DatabaseCluster + listKind: DatabaseClusterList + plural: databaseclusters + shortNames: + - db + - dbc + - dbcluster + singular: databasecluster + scope: Namespaced +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: percona-server-mongodb-operator +status: + availableReplicas: 1 + observedGeneration: 1 + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: percona-server-mongodb-operator + namespace: kuttl-test-psmdb +status: + availableReplicas: 1 + observedGeneration: 1 + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 +--- +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseEngine +metadata: + name: percona-server-mongodb-operator +spec: + type: psmdb +status: + status: installed diff --git a/e2e-tests/tests/features/multinamespace_psmdb/01-deploy-dbaas.yaml b/e2e-tests/tests/features/multinamespace_psmdb/01-deploy-dbaas.yaml new file mode 100644 index 00000000..1f212c2d --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/01-deploy-dbaas.yaml @@ -0,0 +1,7 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +timeout: 10 +commands: + - script: DEFAULT_NAMESPACE=$NAMESPACE WATCH_NAMESPACES=$NAMESPACE,kuttl-test-psmdb ../../../../bin/manager -metrics-bind-address :8032 -health-probe-bind-address :8048 + background: true + skipLogOutput: true diff --git a/e2e-tests/tests/features/multinamespace_psmdb/10-assert.yaml b/e2e-tests/tests/features/multinamespace_psmdb/10-assert.yaml new file mode 100644 index 00000000..1791ae66 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/10-assert.yaml @@ -0,0 +1,80 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 100 +--- +apiVersion: everest.percona.com/v1alpha1 +kind: MonitoringConfig +metadata: + name: test-mc +spec: + type: pmm + credentialsSecretName: test-mc + pmm: + url: http://localhost + image: percona/pmm-client:latest +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: everest.percona.com/v1alpha1 +kind: BackupStorage +metadata: + name: test-storage-scheduled +spec: + type: s3 + bucket: test-backup-bucket-scheduled + credentialsSecretName: test-storage-scheduled + region: us-east-2 + endpointURL: s3.amazonaws.com +--- +apiVersion: psmdb.percona.com/v1 +kind: PerconaServerMongoDB +metadata: + name: test-psmdb-cluster +spec: + pmm: + enabled: true + serverHost: localhost + image: percona/pmm-client:latest + resources: + limits: + memory: "128Mi" + cpu: "500m" + multiCluster: + enabled: false + backup: + tasks: + - enabled: true + keep: 1 + name: daily-backup + schedule: "0 0 * * *" + storageName: test-storage-scheduled + storages: + test-storage-scheduled: + s3: + bucket: test-backup-bucket-scheduled + credentialsSecret: test-storage-scheduled + endpointUrl: s3.amazonaws.com + region: us-east-2 + type: s3 +status: + replsets: + rs0: + initialized: true + ready: 1 + size: 1 + status: ready + state: ready diff --git a/e2e-tests/tests/features/multinamespace_psmdb/10-psmdb-cluster-with-schedule.yaml b/e2e-tests/tests/features/multinamespace_psmdb/10-psmdb-cluster-with-schedule.yaml new file mode 100644 index 00000000..cba42467 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/10-psmdb-cluster-with-schedule.yaml @@ -0,0 +1,68 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +--- +apiVersion: everest.percona.com/v1alpha1 +kind: MonitoringConfig +metadata: + name: test-mc +spec: + type: pmm + credentialsSecretName: test-mc + pmm: + url: http://localhost + image: percona/pmm-client:latest +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: everest.percona.com/v1alpha1 +kind: BackupStorage +metadata: + name: test-storage-scheduled +spec: + type: s3 + bucket: test-backup-bucket-scheduled + credentialsSecretName: test-storage-scheduled + region: us-east-2 + endpointURL: s3.amazonaws.com +--- +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseCluster +metadata: + name: test-psmdb-cluster +spec: + monitoring: + resources: + limits: + memory: "128Mi" + cpu: "500m" + monitoringConfigName: test-mc + engine: + type: psmdb + replicas: 1 + storage: + size: 1G + proxy: + type: haproxy + replicas: 1 + backup: + enabled: true + schedules: + - name: daily-backup + enabled: true + schedule: "0 0 * * *" + retentionCopies: 1 + backupStorageName: test-storage-scheduled diff --git a/e2e-tests/tests/features/multinamespace_psmdb/20-assert.yaml b/e2e-tests/tests/features/multinamespace_psmdb/20-assert.yaml new file mode 100644 index 00000000..17c647ea --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/20-assert.yaml @@ -0,0 +1,61 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 100 +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc + namespace: kuttl-test-psmdb +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled + namespace: kuttl-test-psmdb +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: psmdb.percona.com/v1 +kind: PerconaServerMongoDB +metadata: + name: test-psmdb-cluster + namespace: kuttl-test-psmdb +spec: + pmm: + enabled: true + serverHost: localhost + image: percona/pmm-client:latest + resources: + limits: + memory: "128Mi" + cpu: "500m" + multiCluster: + enabled: false + backup: + tasks: + - enabled: true + keep: 1 + name: daily-backup + schedule: "0 0 * * *" + storageName: test-storage-scheduled + storages: + test-storage-scheduled: + s3: + bucket: test-backup-bucket-scheduled + credentialsSecret: test-storage-scheduled + endpointUrl: s3.amazonaws.com + region: us-east-2 + type: s3 +status: + replsets: + rs0: + initialized: true + ready: 1 + size: 1 + status: ready + state: ready diff --git a/e2e-tests/tests/features/multinamespace_psmdb/20-psmdb-cluster-with-schedule.yaml b/e2e-tests/tests/features/multinamespace_psmdb/20-psmdb-cluster-with-schedule.yaml new file mode 100644 index 00000000..a17aeaee --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/20-psmdb-cluster-with-schedule.yaml @@ -0,0 +1,31 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +--- +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseCluster +metadata: + name: test-psmdb-cluster + namespace: kuttl-test-psmdb +spec: + monitoring: + resources: + limits: + memory: "128Mi" + cpu: "500m" + monitoringConfigName: test-mc + engine: + type: psmdb + replicas: 1 + storage: + size: 1G + proxy: + type: haproxy + replicas: 1 + backup: + enabled: true + schedules: + - name: daily-backup + enabled: true + schedule: "0 0 * * *" + retentionCopies: 1 + backupStorageName: test-storage-scheduled diff --git a/e2e-tests/tests/features/multinamespace_psmdb/90-delete-cluster.yaml b/e2e-tests/tests/features/multinamespace_psmdb/90-delete-cluster.yaml new file mode 100644 index 00000000..a341c9cc --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/90-delete-cluster.yaml @@ -0,0 +1,13 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +commands: + - command: kubectl -n $NAMESPACE delete db test-psmdb-cluster + - command: kubectl patch psmdb test-psmdb-cluster -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl -n kuttl-test-psmdb delete db test-psmdb-cluster + - command: kubectl patch psmdb test-psmdb-cluster -n kuttl-test-psmdb -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl patch monitoringconfig test-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl patch backupstorage test-storage-scheduled -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true diff --git a/e2e-tests/tests/features/multinamespace_psmdb/98-drop-pvc.yaml b/e2e-tests/tests/features/multinamespace_psmdb/98-drop-pvc.yaml new file mode 100644 index 00000000..f5305422 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_psmdb/98-drop-pvc.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +delete: +- apiVersion: v1 + kind: PersistentVolumeClaim diff --git a/e2e-tests/tests/features/multinamespace_pxc/00-deploy-operators.yaml b/e2e-tests/tests/features/multinamespace_pxc/00-deploy-operators.yaml new file mode 100644 index 00000000..648e9077 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/00-deploy-operators.yaml @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +commands: + - command: kubectl create ns kuttl-test-pxc + - command: kubectl apply -f https://raw.githubusercontent.com/percona/percona-xtradb-cluster-operator/v${PXC_OPERATOR_VERSION}/deploy/bundle.yaml -n kuttl-test-pxc + - command: kubectl apply -f https://raw.githubusercontent.com/percona/percona-xtradb-cluster-operator/v${PXC_OPERATOR_VERSION}/deploy/bundle.yaml -n "${NAMESPACE}" diff --git a/e2e-tests/tests/features/multinamespace_pxc/01-assert.yaml b/e2e-tests/tests/features/multinamespace_pxc/01-assert.yaml new file mode 100644 index 00000000..5c9d6f7d --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/01-assert.yaml @@ -0,0 +1,68 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 120 +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: perconaxtradbclusters.pxc.percona.com +spec: + group: pxc.percona.com + names: + kind: PerconaXtraDBCluster + listKind: PerconaXtraDBClusterList + plural: perconaxtradbclusters + shortNames: + - pxc + - pxcs + singular: perconaxtradbcluster + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: databaseclusters.everest.percona.com +spec: + group: everest.percona.com + names: + kind: DatabaseCluster + listKind: DatabaseClusterList + plural: databaseclusters + shortNames: + - db + - dbc + - dbcluster + singular: databasecluster + scope: Namespaced +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: percona-xtradb-cluster-operator + namespace: kuttl-test-pxc +status: + availableReplicas: 1 + observedGeneration: 1 + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: percona-xtradb-cluster-operator +status: + availableReplicas: 1 + observedGeneration: 1 + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 +--- +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseEngine +metadata: + name: percona-xtradb-cluster-operator +spec: + type: pxc +status: + status: installed diff --git a/e2e-tests/tests/features/multinamespace_pxc/01-deploy-dbaas.yaml b/e2e-tests/tests/features/multinamespace_pxc/01-deploy-dbaas.yaml new file mode 100644 index 00000000..cc6e7789 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/01-deploy-dbaas.yaml @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +commands: + - script: DEFAULT_NAMESPACE=$NAMESPACE WATCH_NAMESPACES=$NAMESPACE,kuttl-test-pxc ../../../../bin/manager -metrics-bind-address :8011 -health-probe-bind-address :8012 + background: true + skipLogOutput: true diff --git a/e2e-tests/tests/features/multinamespace_pxc/10-assert.yaml b/e2e-tests/tests/features/multinamespace_pxc/10-assert.yaml new file mode 100644 index 00000000..9f6d09c0 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/10-assert.yaml @@ -0,0 +1,74 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 100 +--- +apiVersion: everest.percona.com/v1alpha1 +kind: MonitoringConfig +metadata: + name: test-mc +spec: + type: pmm + credentialsSecretName: test-mc + pmm: + url: http://localhost + image: percona/pmm-client:latest +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: everest.percona.com/v1alpha1 +kind: BackupStorage +metadata: + name: test-storage-scheduled +spec: + type: s3 + bucket: test-backup-bucket-scheduled + credentialsSecretName: test-storage-scheduled + region: us-east-2 + endpointURL: s3.someprovider.com +--- +apiVersion: pxc.percona.com/v1 +kind: PerconaXtraDBCluster +metadata: + name: test-pxc-cluster +spec: + haproxy: + enabled: true + pmm: + enabled: true + serverHost: localhost + image: percona/pmm-client:latest + resources: + limits: + memory: "128Mi" + cpu: "500m" + updateStrategy: SmartUpdate + upgradeOptions: + apply: never + schedule: 0 4 * * * + backup: + schedule: + - keep: 1 + name: daily-backup + schedule: 0 0 * * * + storageName: test-storage-scheduled + storages: + test-storage-scheduled: + s3: + credentialsSecret: test-storage-scheduled + endpointUrl: s3.someprovider.com + region: us-east-2 + type: s3 diff --git a/e2e-tests/tests/features/multinamespace_pxc/10-pxc-cluster-with-schedule.yaml b/e2e-tests/tests/features/multinamespace_pxc/10-pxc-cluster-with-schedule.yaml new file mode 100644 index 00000000..3285a416 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/10-pxc-cluster-with-schedule.yaml @@ -0,0 +1,69 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +--- +apiVersion: everest.percona.com/v1alpha1 +kind: MonitoringConfig +metadata: + name: test-mc +spec: + type: pmm + credentialsSecretName: test-mc + pmm: + url: http://localhost + image: percona/pmm-client:latest +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: everest.percona.com/v1alpha1 +kind: BackupStorage +metadata: + name: test-storage-scheduled +spec: + type: s3 + bucket: test-backup-bucket-scheduled + credentialsSecretName: test-storage-scheduled + region: us-east-2 + endpointURL: s3.someprovider.com +--- +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseCluster +metadata: + name: test-pxc-cluster +spec: + monitoring: + resources: + limits: + memory: "128Mi" + cpu: "500m" + monitoringConfigName: test-mc + image: percona/pmm-client:latest + engine: + type: pxc + replicas: 1 + storage: + size: 1G + proxy: + type: haproxy + replicas: 1 + backup: + enabled: true + schedules: + - name: daily-backup + enabled: true + schedule: "0 0 * * *" + retentionCopies: 1 + backupStorageName: test-storage-scheduled diff --git a/e2e-tests/tests/features/multinamespace_pxc/20-assert.yaml b/e2e-tests/tests/features/multinamespace_pxc/20-assert.yaml new file mode 100644 index 00000000..932d8c73 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/20-assert.yaml @@ -0,0 +1,55 @@ +apiVersion: kuttl.dev/v1 +kind: TestAssert +timeout: 100 +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-mc + namespace: kuttl-test-pxc +data: + apiKey: YWJjZGVm +--- +apiVersion: v1 +kind: Secret +metadata: + name: test-storage-scheduled + namespace: kuttl-test-pxc +type: Opaque +data: + AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ + AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ +--- +apiVersion: pxc.percona.com/v1 +kind: PerconaXtraDBCluster +metadata: + name: test-pxc-cluster + namespace: kuttl-test-pxc +spec: + haproxy: + enabled: true + pmm: + enabled: true + serverHost: localhost + image: percona/pmm-client:latest + resources: + limits: + memory: "128Mi" + cpu: "500m" + updateStrategy: SmartUpdate + upgradeOptions: + apply: never + schedule: 0 4 * * * + backup: + schedule: + - keep: 1 + name: daily-backup + schedule: 0 0 * * * + storageName: test-storage-scheduled + storages: + test-storage-scheduled: + s3: + credentialsSecret: test-storage-scheduled + endpointUrl: s3.someprovider.com + region: us-east-2 + type: s3 diff --git a/e2e-tests/tests/features/multinamespace_pxc/20-pxc-cluster-with-schedule.yaml b/e2e-tests/tests/features/multinamespace_pxc/20-pxc-cluster-with-schedule.yaml new file mode 100644 index 00000000..cdc129a9 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/20-pxc-cluster-with-schedule.yaml @@ -0,0 +1,32 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +--- +apiVersion: everest.percona.com/v1alpha1 +kind: DatabaseCluster +metadata: + name: test-pxc-cluster + namespace: kuttl-test-pxc +spec: + monitoring: + resources: + limits: + memory: "128Mi" + cpu: "500m" + monitoringConfigName: test-mc + image: percona/pmm-client:latest + engine: + type: pxc + replicas: 1 + storage: + size: 1G + proxy: + type: haproxy + replicas: 1 + backup: + enabled: true + schedules: + - name: daily-backup + enabled: true + schedule: "0 0 * * *" + retentionCopies: 1 + backupStorageName: test-storage-scheduled diff --git a/e2e-tests/tests/features/multinamespace_pxc/90-delete-cluster.yaml b/e2e-tests/tests/features/multinamespace_pxc/90-delete-cluster.yaml new file mode 100644 index 00000000..55a7749f --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/90-delete-cluster.yaml @@ -0,0 +1,13 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +commands: + - command: kubectl patch monitoringconfig test-mc -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl patch backupstorage test-storage-scheduled -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl -n $NAMESPACE delete db test-pxc-cluster + - command: kubectl patch pxc test-pxc-cluster -n $NAMESPACE -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true + - command: kubectl -n kuttl-test-pxc delete db test-pxc-cluster + - command: kubectl patch pxc test-pxc-cluster -n kuttl-test-pxc -p '{"metadata":{"finalizers":null}}' --type merge + ignoreFailure: true diff --git a/e2e-tests/tests/features/multinamespace_pxc/98-drop-pvc.yaml b/e2e-tests/tests/features/multinamespace_pxc/98-drop-pvc.yaml new file mode 100644 index 00000000..f5305422 --- /dev/null +++ b/e2e-tests/tests/features/multinamespace_pxc/98-drop-pvc.yaml @@ -0,0 +1,5 @@ +apiVersion: kuttl.dev/v1 +kind: TestStep +delete: +- apiVersion: v1 + kind: PersistentVolumeClaim diff --git a/e2e-tests/tests/features/scheduled_backups/01-manager.yaml b/e2e-tests/tests/features/scheduled_backups/01-manager.yaml index 3627ae9a..7cb64b0e 100644 --- a/e2e-tests/tests/features/scheduled_backups/01-manager.yaml +++ b/e2e-tests/tests/features/scheduled_backups/01-manager.yaml @@ -1,6 +1,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8087 -health-probe-bind-address :8088 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8087 -health-probe-bind-address :8088 background: true skipLogOutput: true diff --git a/e2e-tests/tests/features/templates/01-deploy-dbaas.yaml b/e2e-tests/tests/features/templates/01-deploy-dbaas.yaml index 4b2e7e10..fad3006f 100644 --- a/e2e-tests/tests/features/templates/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/features/templates/01-deploy-dbaas.yaml @@ -2,5 +2,5 @@ apiVersion: kuttl.dev/v1 kind: TestStep timeout: 10 commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8089 -health-probe-bind-address :8090 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8089 -health-probe-bind-address :8090 background: true diff --git a/e2e-tests/tests/upgrade/pg/01-deploy-dbaas.yaml b/e2e-tests/tests/upgrade/pg/01-deploy-dbaas.yaml index 250eed91..a62e0809 100644 --- a/e2e-tests/tests/upgrade/pg/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/upgrade/pg/01-deploy-dbaas.yaml @@ -2,6 +2,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep timeout: 10 commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8075 -health-probe-bind-address :8076 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8075 -health-probe-bind-address :8076 background: true skipLogOutput: true diff --git a/e2e-tests/tests/upgrade/psmdb/01-deploy-dbaas.yaml b/e2e-tests/tests/upgrade/psmdb/01-deploy-dbaas.yaml index 442fa96d..c7bd6f45 100644 --- a/e2e-tests/tests/upgrade/psmdb/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/upgrade/psmdb/01-deploy-dbaas.yaml @@ -2,6 +2,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep timeout: 10 commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8055 -health-probe-bind-address :8056 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8055 -health-probe-bind-address :8056 background: true skipLogOutput: true diff --git a/e2e-tests/tests/upgrade/pxc/01-deploy-dbaas.yaml b/e2e-tests/tests/upgrade/pxc/01-deploy-dbaas.yaml index 06a4b167..a0b2ca5b 100644 --- a/e2e-tests/tests/upgrade/pxc/01-deploy-dbaas.yaml +++ b/e2e-tests/tests/upgrade/pxc/01-deploy-dbaas.yaml @@ -1,6 +1,6 @@ apiVersion: kuttl.dev/v1 kind: TestStep commands: - - script: WATCH_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8065 -health-probe-bind-address :8066 + - script: DEFAULT_NAMESPACE=$NAMESPACE ../../../../bin/manager -metrics-bind-address :8065 -health-probe-bind-address :8066 background: true skipLogOutput: true diff --git a/main.go b/main.go index 7bf062f1..c80d26c8 100644 --- a/main.go +++ b/main.go @@ -19,12 +19,17 @@ package main import ( + "context" "errors" "flag" "fmt" "os" + "strings" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -40,7 +45,10 @@ import ( "github.com/percona/everest-operator/controllers" ) -const watchNamespaceEnvVar = "WATCH_NAMESPACE" +const ( + defaultNamespaceEnvVar = "DEFAULT_NAMESPACE" + watchNamespacesEnvVar = "WATCH_NAMESPACES" +) var ( scheme = runtime.NewScheme() @@ -70,12 +78,24 @@ func main() { flag.Parse() ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - ns, found := os.LookupEnv(watchNamespaceEnvVar) + defaultNamespace, found := os.LookupEnv(defaultNamespaceEnvVar) if !found { - setupLog.Error(errors.New("failed to get namespace"), fmt.Sprintf("%s must be set", watchNamespaceEnvVar)) + setupLog.Error(errors.New("failed to get the default namespace"), fmt.Sprintf("%s must be set", defaultNamespaceEnvVar)) os.Exit(1) } + watchNamespaces, found := os.LookupEnv(watchNamespacesEnvVar) + if !found { + setupLog.Error(errors.New("failed to get watch namespaces"), fmt.Sprintf("%s must be set", defaultNamespaceEnvVar)) + } + cacheConfig := map[string]cache.Config{} + namespaces := []string{defaultNamespace} + if watchNamespaces != "" && strings.Contains(watchNamespaces, ",") { + namespaces = append(namespaces, strings.Split(watchNamespaces, ",")...) + } + for _, ns := range namespaces { + cacheConfig[ns] = cache.Config{} + } mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, @@ -86,9 +106,7 @@ func main() { LeaderElection: enableLeaderElection, LeaderElectionID: "9094838c.percona.com", Cache: cache.Options{ - DefaultNamespaces: map[string]cache.Config{ - ns: {}, - }, + DefaultNamespaces: cacheConfig, }, // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily // when the Manager ends. This requires the binary to immediately end when the @@ -106,18 +124,31 @@ func main() { setupLog.Error(err, "unable to start manager") os.Exit(1) } - + namespace := &unstructured.Unstructured{} + namespace.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "", + Kind: "Namespace", + Version: "v1", + }) + for _, namespaceName := range namespaces { + namespaceName := namespaceName + err := mgr.GetClient().Get(context.Background(), types.NamespacedName{Name: namespaceName}, namespace) + if err != nil { + setupLog.Error(err, "unable to create controller", "controller", "DatabaseCluster") + os.Exit(1) + } + } if err = (&controllers.DatabaseClusterReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { + }).SetupWithManager(mgr, defaultNamespace); err != nil { setupLog.Error(err, "unable to create controller", "controller", "DatabaseCluster") os.Exit(1) } if err = (&controllers.DatabaseEngineReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { + }).SetupWithManager(mgr, namespaces); err != nil { setupLog.Error(err, "unable to create controller", "controller", "DatabaseEngine") os.Exit(1) } @@ -135,6 +166,27 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "DatabaseClusterBackup") os.Exit(1) } + if err = (&controllers.BackupStorageReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr, defaultNamespace); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "BackupStorage") + os.Exit(1) + } + if err = (&controllers.SecretReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr, defaultNamespace); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Secret") + os.Exit(1) + } + if err = (&controllers.MonitoringConfigReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr, defaultNamespace); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "MonitoringConfig") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {