From ab9d7d1937e18d58d504110ba5e4514d827b7c18 Mon Sep 17 00:00:00 2001 From: jgilaber Date: Tue, 7 Jan 2025 15:35:36 +0100 Subject: [PATCH] Add database connection details to sub level secret Add the database connection details to the secret creted by the watcher controller to pass to the sub CRs, so we don't need to access the database object from the subCRs. --- .../watcher.openstack.org_watcherapis.yaml | 11 ---- api/v1beta1/common_types.go | 20 +++--- .../watcher.openstack.org_watcherapis.yaml | 11 ---- .../samples/watcher_v1beta1_watcherapi.yaml | 3 +- controllers/watcher_common.go | 7 +++ controllers/watcher_controller.go | 11 +++- controllers/watcherapi_controller.go | 27 +++----- .../functional/watcherapi_controller_test.go | 61 +++---------------- .../default/watcher-api/03-assert.yaml | 2 - .../watcher-api/03-deploy-watcher-api.yaml | 1 - 10 files changed, 45 insertions(+), 109 deletions(-) diff --git a/api/bases/watcher.openstack.org_watcherapis.yaml b/api/bases/watcher.openstack.org_watcherapis.yaml index aa5afc5..36b832d 100644 --- a/api/bases/watcher.openstack.org_watcherapis.yaml +++ b/api/bases/watcher.openstack.org_watcherapis.yaml @@ -43,16 +43,6 @@ spec: description: The service specific Container Image URL (will be set to environmental default if empty) type: string - databaseAccount: - default: watcher - description: DatabaseAccount - MariaDBAccount CR name used for watcher - DB, defaults to watcher - type: string - databaseInstance: - description: |- - MariaDB instance name - Required to use the mariadb-operator instance to create the DB and user - type: string memcachedInstance: default: memcached description: MemcachedInstance is the name of the Memcached CR that @@ -84,7 +74,6 @@ spec: to register in keystone type: string required: - - databaseInstance - secret type: object status: diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index a862c55..dee374b 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -38,16 +38,6 @@ type WatcherCommon struct { // PasswordSelectors - Selectors to identify the ServiceUser password from the Secret PasswordSelectors PasswordSelector `json:"passwordSelectors"` - // +kubebuilder:validation:Required - // MariaDB instance name - // Required to use the mariadb-operator instance to create the DB and user - DatabaseInstance string `json:"databaseInstance"` - - // +kubebuilder:validation:Optional - // +kubebuilder:default=watcher - // DatabaseAccount - MariaDBAccount CR name used for watcher DB, defaults to watcher - DatabaseAccount string `json:"databaseAccount"` - // +kubebuilder:validation:Optional // +kubebuilder:default=memcached // MemcachedInstance is the name of the Memcached CR that all watcher service will use. @@ -75,6 +65,16 @@ type WatcherTemplate struct { // +kubebuilder:default=osp-secret // Secret containing all passwords / keys needed Secret string `json:"secret"` + + // +kubebuilder:validation:Required + // MariaDB instance name + // Required to use the mariadb-operator instance to create the DB and user + DatabaseInstance string `json:"databaseInstance"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default=watcher + // DatabaseAccount - MariaDBAccount CR name used for watcher DB, defaults to watcher + DatabaseAccount string `json:"databaseAccount"` } // PasswordSelector to identify the DB and AdminUser password from the Secret diff --git a/config/crd/bases/watcher.openstack.org_watcherapis.yaml b/config/crd/bases/watcher.openstack.org_watcherapis.yaml index aa5afc5..36b832d 100644 --- a/config/crd/bases/watcher.openstack.org_watcherapis.yaml +++ b/config/crd/bases/watcher.openstack.org_watcherapis.yaml @@ -43,16 +43,6 @@ spec: description: The service specific Container Image URL (will be set to environmental default if empty) type: string - databaseAccount: - default: watcher - description: DatabaseAccount - MariaDBAccount CR name used for watcher - DB, defaults to watcher - type: string - databaseInstance: - description: |- - MariaDB instance name - Required to use the mariadb-operator instance to create the DB and user - type: string memcachedInstance: default: memcached description: MemcachedInstance is the name of the Memcached CR that @@ -84,7 +74,6 @@ spec: to register in keystone type: string required: - - databaseInstance - secret type: object status: diff --git a/config/samples/watcher_v1beta1_watcherapi.yaml b/config/samples/watcher_v1beta1_watcherapi.yaml index b593cf1..164cca9 100644 --- a/config/samples/watcher_v1beta1_watcherapi.yaml +++ b/config/samples/watcher_v1beta1_watcherapi.yaml @@ -6,5 +6,4 @@ metadata: app.kubernetes.io/managed-by: kustomize name: watcherapi-sample spec: - databaseInstance: "openstack" - secret: "osp-secret" + secret: "watcher" diff --git a/controllers/watcher_common.go b/controllers/watcher_common.go index 51681eb..1d4df8a 100644 --- a/controllers/watcher_common.go +++ b/controllers/watcher_common.go @@ -36,6 +36,13 @@ var ( const ( // TransportURLSelector is the name of key in the secret created by TransportURL TransportURLSelector = "transport_url" + // DatabaseUsername is the name of key in the secret for the user name used to login to the database + DatabaseUsername = "database_username" + // DatabaseUsername is the name of key in the secret for the password used to login to the database + DatabasePassword = "database_password" + // DatabaseUsername is the name of key in the secret for the database + // hostname + DatabaseHostname = "database_hostname" ) // GetLogger returns a logger object with a prefix of "controller.name" and additional controller context fields diff --git a/controllers/watcher_controller.go b/controllers/watcher_controller.go index 4080bb2..e0c4999 100644 --- a/controllers/watcher_controller.go +++ b/controllers/watcher_controller.go @@ -182,7 +182,6 @@ func (r *WatcherReconciler) Reconcile(ctx context.Context, req ctrl.Request) (re } else if (result != ctrl.Result{}) { return result, nil } - _ = db // create service DB - end // @@ -245,7 +244,7 @@ func (r *WatcherReconciler) Reconcile(ctx context.Context, req ctrl.Request) (re return ctrl.Result{}, errors.New("error retrieving required data from transporturl secret") } - subLevelSecretName, err := r.createSubLevelSecret(ctx, helper, instance, transporturlSecret, inputSecret) + subLevelSecretName, err := r.createSubLevelSecret(ctx, helper, instance, transporturlSecret, inputSecret, db) if err != nil { return ctrl.Result{}, nil } @@ -698,10 +697,18 @@ func (r *WatcherReconciler) createSubLevelSecret( instance *watcherv1beta1.Watcher, transportURLSecret corev1.Secret, inputSecret corev1.Secret, + db *mariadbv1.Database, ) (string, error) { + Log := r.GetLogger(ctx) + Log.Info(fmt.Sprintf("Creating SubCr Level Secret for '%s'", instance.Name)) + databaseAccount := db.GetAccount() + databaseSecret := db.GetSecret() data := map[string]string{ instance.Spec.PasswordSelectors.Service: string(inputSecret.Data[instance.Spec.PasswordSelectors.Service]), TransportURLSelector: string(transportURLSecret.Data[TransportURLSelector]), + DatabaseUsername: databaseAccount.Spec.UserName, + DatabasePassword: string(databaseSecret.Data[mariadbv1.DatabasePasswordSelector]), + DatabaseHostname: db.GetDatabaseHostname(), } secretName := instance.Name diff --git a/controllers/watcherapi_controller.go b/controllers/watcherapi_controller.go index e3fd48d..da421ea 100644 --- a/controllers/watcherapi_controller.go +++ b/controllers/watcherapi_controller.go @@ -38,7 +38,6 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/helper" "github.com/openstack-k8s-operators/lib-common/modules/common/labels" "github.com/openstack-k8s-operators/lib-common/modules/common/service" - mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" watcherv1beta1 "github.com/openstack-k8s-operators/watcher-operator/api/v1beta1" "github.com/openstack-k8s-operators/watcher-operator/pkg/watcher" @@ -160,17 +159,6 @@ func (r *WatcherAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) configVars[instance.Spec.Secret] = env.SetValue(secretHash) - db, err := mariadbv1.GetDatabaseByNameAndAccount(ctx, helper, watcher.DatabaseCRName, instance.Spec.DatabaseAccount, instance.Namespace) - if err != nil { - instance.Status.Conditions.Set(condition.FalseCondition( - condition.InputReadyCondition, - condition.ErrorReason, - condition.SeverityWarning, - condition.InputReadyErrorMessage, - fmt.Sprintf("couldn't get database %s and account %s", watcher.DatabaseCRName, instance.Spec.DatabaseAccount))) - return ctrl.Result{}, err - } - // all our input checks out so report InputReady instance.Status.Conditions.MarkTrue(condition.InputReadyCondition, condition.InputReadyMessage) @@ -193,7 +181,7 @@ func (r *WatcherAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) } } - err = r.generateServiceConfigs(ctx, instance, secret, db, memcached, helper, &configVars) + err = r.generateServiceConfigs(ctx, instance, secret, memcached, helper, &configVars) if err != nil { return ctrl.Result{}, err } @@ -213,7 +201,7 @@ func (r *WatcherAPIReconciler) Reconcile(ctx context.Context, req ctrl.Request) // generateServiceConfigs - create Secret which holds the service configuration func (r *WatcherAPIReconciler) generateServiceConfigs( ctx context.Context, instance *watcherv1beta1.WatcherAPI, - secret corev1.Secret, db *mariadbv1.Database, + secret corev1.Secret, memcachedInstance *memcachedv1.Memcached, helper *helper.Helper, envVars *map[string]env.Setter, ) error { @@ -243,13 +231,14 @@ func (r *WatcherAPIReconciler) generateServiceConfigs( // implement CustomServiceConfig later customData := map[string]string{} - databaseAccount := db.GetAccount() - databaseSecret := db.GetSecret() + databaseUsername := string(secret.Data[DatabaseUsername]) + databaseHostname := string(secret.Data[DatabaseHostname]) + databasePassword := string(secret.Data[DatabasePassword]) templateParameters := map[string]interface{}{ "DatabaseConnection": fmt.Sprintf("mysql+pymysql://%s:%s@%s/%s?charset=utf8", - databaseAccount.Spec.UserName, - string(databaseSecret.Data[mariadbv1.DatabasePasswordSelector]), - db.GetDatabaseHostname(), + databaseUsername, + databasePassword, + databaseHostname, watcher.DatabaseName, ), "KeystoneAuthURL": keystoneInternalURL, diff --git a/tests/functional/watcherapi_controller_test.go b/tests/functional/watcherapi_controller_test.go index 332fa95..3c37bd1 100644 --- a/tests/functional/watcherapi_controller_test.go +++ b/tests/functional/watcherapi_controller_test.go @@ -12,7 +12,6 @@ import ( . "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" watcherv1beta1 "github.com/openstack-k8s-operators/watcher-operator/api/v1beta1" - "github.com/openstack-k8s-operators/watcher-operator/pkg/watcher" corev1 "k8s.io/api/core/v1" "k8s.io/utils/ptr" ) @@ -20,7 +19,6 @@ import ( var ( MinimalWatcherAPISpec = map[string]interface{}{ "secret": "osp-secret", - "databaseInstance": "openstack", "memcachedInstance": "memcached", } ) @@ -33,8 +31,6 @@ var _ = Describe("WatcherAPI controller with minimal spec values", func() { It("should have the Spec fields defaulted", func() { WatcherAPI := GetWatcherAPI(watcherTest.WatcherAPI) - Expect(WatcherAPI.Spec.DatabaseInstance).Should(Equal("openstack")) - Expect(WatcherAPI.Spec.DatabaseAccount).Should(Equal("watcher")) Expect(WatcherAPI.Spec.Secret).Should(Equal("osp-secret")) Expect(WatcherAPI.Spec.MemcachedInstance).Should(Equal("memcached")) Expect(WatcherAPI.Spec.PasswordSelectors).Should(Equal(watcherv1beta1.PasswordSelector{Service: "WatcherPassword"})) @@ -64,8 +60,6 @@ var _ = Describe("WatcherAPI controller", func() { It("should have the Spec fields defaulted", func() { WatcherAPI := GetWatcherAPI(watcherTest.WatcherAPI) - Expect(WatcherAPI.Spec.DatabaseInstance).Should(Equal("openstack")) - Expect(WatcherAPI.Spec.DatabaseAccount).Should(Equal("watcher")) Expect(WatcherAPI.Spec.Secret).Should(Equal("test-osp-secret")) Expect(WatcherAPI.Spec.MemcachedInstance).Should(Equal("memcached")) }) @@ -218,54 +212,16 @@ var _ = Describe("WatcherAPI controller", func() { ) }) }) - When("A WatcherAPI instance without a database but with a secret is created", func() { - BeforeEach(func() { - secret := th.CreateSecret( - watcherTest.InternalTopLevelSecretName, - map[string][]byte{ - "WatcherPassword": []byte("service-password"), - "transport_url": []byte("url"), - }, - ) - DeferCleanup(k8sClient.Delete, ctx, secret) - DeferCleanup(th.DeleteInstance, CreateWatcherAPI(watcherTest.WatcherAPI, GetDefaultWatcherAPISpec())) - }) - It("should have input not ready", func() { - WatcherAPI := GetWatcherAPI(watcherTest.WatcherAPI) - customErrorString := fmt.Sprintf( - "couldn't get database %s and account %s", - watcher.DatabaseCRName, - WatcherAPI.Spec.DatabaseAccount, - ) - errorString := fmt.Sprintf( - condition.InputReadyErrorMessage, - customErrorString, - ) - th.ExpectConditionWithDetails( - watcherTest.WatcherAPI, - ConditionGetterFunc(WatcherAPIConditionGetter), - condition.InputReadyCondition, - corev1.ConditionFalse, - condition.ErrorReason, - errorString, - ) - }) - It("should have config service unknown", func() { - th.ExpectCondition( - watcherTest.WatcherAPI, - ConditionGetterFunc(WatcherAPIConditionGetter), - condition.ServiceConfigReadyCondition, - corev1.ConditionUnknown, - ) - }) - }) When("secret and db are created, but there is no memcached", func() { BeforeEach(func() { secret := th.CreateSecret( watcherTest.InternalTopLevelSecretName, map[string][]byte{ - "WatcherPassword": []byte("service-password"), - "transport_url": []byte("url"), + "WatcherPassword": []byte("service-password"), + "transport_url": []byte("url"), + "database_username": []byte("username"), + "database_password": []byte("password"), + "database_hostname": []byte("hostname"), }, ) DeferCleanup(k8sClient.Delete, ctx, secret) @@ -303,8 +259,11 @@ var _ = Describe("WatcherAPI controller", func() { secret := th.CreateSecret( watcherTest.InternalTopLevelSecretName, map[string][]byte{ - "WatcherPassword": []byte("service-password"), - "transport_url": []byte("url"), + "WatcherPassword": []byte("service-password"), + "transport_url": []byte("url"), + "database_username": []byte("username"), + "database_password": []byte("password"), + "database_hostname": []byte("hostname"), }, ) DeferCleanup(k8sClient.Delete, ctx, secret) diff --git a/tests/kuttl/test-suites/default/watcher-api/03-assert.yaml b/tests/kuttl/test-suites/default/watcher-api/03-assert.yaml index 98bd268..12f35a9 100644 --- a/tests/kuttl/test-suites/default/watcher-api/03-assert.yaml +++ b/tests/kuttl/test-suites/default/watcher-api/03-assert.yaml @@ -5,8 +5,6 @@ metadata: - openstack.org/watcherapi name: watcherapi-kuttl spec: - databaseAccount: watcher - databaseInstance: openstack passwordSelectors: service: WatcherPassword secret: watcher-kuttl diff --git a/tests/kuttl/test-suites/default/watcher-api/03-deploy-watcher-api.yaml b/tests/kuttl/test-suites/default/watcher-api/03-deploy-watcher-api.yaml index 63c7121..1f6a939 100644 --- a/tests/kuttl/test-suites/default/watcher-api/03-deploy-watcher-api.yaml +++ b/tests/kuttl/test-suites/default/watcher-api/03-deploy-watcher-api.yaml @@ -3,6 +3,5 @@ kind: WatcherAPI metadata: name: watcherapi-kuttl spec: - databaseInstance: openstack secret: watcher-kuttl memcachedInstance: "memcached"