From 216e226e0a3eb0b528cd20ca78bea36a3376d127 Mon Sep 17 00:00:00 2001 From: Murad Biashimov Date: Thu, 16 May 2024 10:35:13 +0200 Subject: [PATCH] fix(connectionpool): check user exists (#734) --- CHANGELOG.md | 1 + controllers/connectionpool_controller.go | 33 ++++---- docs/docs/api-reference/connectionpool.md | 57 ++++++++++--- .../examples/connectionpool.yaml | 57 ++++++++++--- tests/connectionpool_test.go | 80 +++---------------- 5 files changed, 120 insertions(+), 108 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be3cb9f6..40483d95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Change `Kafka` field `userConfig.kafka_version`: enum ~~`[3.4, 3.5, 3.6]`~~ → `[3.4, 3.5, 3.6, 3.7]` - Add `ServiceIntegration` `flink_external_postgresql` type - Remove `CA_CERT` secret key for `Grafana`, `OpenSearch`, `Redis`, and `Clickhouse`. Can't be used with these service types +- Fix `ConnectionPool` doesn't check service user precondition ## v0.19.0 - 2024-04-18 diff --git a/controllers/connectionpool_controller.go b/controllers/connectionpool_controller.go index b7ce8eb1..00b0e51a 100644 --- a/controllers/connectionpool_controller.go +++ b/controllers/connectionpool_controller.go @@ -114,14 +114,10 @@ func (h ConnectionPoolHandler) delete(ctx context.Context, avn *aiven.Client, av func (h ConnectionPoolHandler) exists(ctx context.Context, avn *aiven.Client, cp *v1alpha1.ConnectionPool) (bool, error) { conPool, err := avn.ConnectionPools.Get(ctx, cp.Spec.Project, cp.Spec.ServiceName, cp.Name) - if err != nil { - if isNotFound(err) { - return false, nil - } - return false, err + if isNotFound(err) { + return false, nil } - - return conPool != nil, nil + return conPool != nil, err } func (h ConnectionPoolHandler) get(ctx context.Context, avn *aiven.Client, avnGen avngen.Client, obj client.Object) (*corev1.Secret, error) { @@ -219,24 +215,25 @@ func (h ConnectionPoolHandler) checkPreconditions(ctx context.Context, avn *aive meta.SetStatusCondition(&cp.Status.Conditions, getInitializedCondition("Preconditions", "Checking preconditions")) - check, err := checkServiceIsRunning(ctx, avn, avnGen, cp.Spec.Project, cp.Spec.ServiceName) + isRunning, err := checkServiceIsRunning(ctx, avn, avnGen, cp.Spec.Project, cp.Spec.ServiceName) if err != nil { return false, err } - if check { - db, err := avn.Databases.Get(ctx, cp.Spec.Project, cp.Spec.ServiceName, cp.Spec.DatabaseName) - if err != nil { - if isNotFound(err) { - return false, nil - } - return false, err - } + if !isRunning { + return false, nil + } + + _, err = avn.Databases.Get(ctx, cp.Spec.Project, cp.Spec.ServiceName, cp.Spec.DatabaseName) + if err == nil { + _, err = avnGen.ServiceUserGet(ctx, cp.Spec.Project, cp.Spec.ServiceName, cp.Spec.Username) + } - return db != nil, nil + if isNotFound(err) { + return false, nil } - return false, nil + return err == nil, err } func (h ConnectionPoolHandler) convert(i client.Object) (*v1alpha1.ConnectionPool, error) { diff --git a/docs/docs/api-reference/connectionpool.md b/docs/docs/api-reference/connectionpool.md index c2e5ec7f..15822a7b 100644 --- a/docs/docs/api-reference/connectionpool.md +++ b/docs/docs/api-reference/connectionpool.md @@ -15,20 +15,55 @@ title: "ConnectionPool" name: aiven-token key: token - connInfoSecretTarget: - name: connection-pool-secret - prefix: MY_SECRET_PREFIX_ - annotations: - foo: bar - labels: - baz: egg - project: aiven-project-name - serviceName: my-service - databaseName: my-db - username: my-user + serviceName: my-pg + databaseName: my-database + username: my-service-user poolMode: transaction poolSize: 25 + + --- + + apiVersion: aiven.io/v1alpha1 + kind: PostgreSQL + metadata: + name: my-pg + spec: + authSecretRef: + name: aiven-token + key: token + + project: aiven-project-name + cloudName: google-europe-west1 + plan: startup-4 + + --- + + apiVersion: aiven.io/v1alpha1 + kind: Database + metadata: + name: my-database + spec: + authSecretRef: + name: aiven-token + key: token + + project: aiven-project-name + serviceName: my-pg + + --- + + apiVersion: aiven.io/v1alpha1 + kind: ServiceUser + metadata: + name: my-service-user + spec: + authSecretRef: + name: aiven-token + key: token + + project: aiven-project-name + serviceName: my-pg ``` ## ConnectionPool {: #ConnectionPool } diff --git a/docs/docs/api-reference/examples/connectionpool.yaml b/docs/docs/api-reference/examples/connectionpool.yaml index e8879c61..98855f21 100644 --- a/docs/docs/api-reference/examples/connectionpool.yaml +++ b/docs/docs/api-reference/examples/connectionpool.yaml @@ -7,17 +7,52 @@ spec: name: aiven-token key: token - connInfoSecretTarget: - name: connection-pool-secret - prefix: MY_SECRET_PREFIX_ - annotations: - foo: bar - labels: - baz: egg - project: aiven-project-name - serviceName: my-service - databaseName: my-db - username: my-user + serviceName: my-pg + databaseName: my-database + username: my-service-user poolMode: transaction poolSize: 25 + +--- + +apiVersion: aiven.io/v1alpha1 +kind: PostgreSQL +metadata: + name: my-pg +spec: + authSecretRef: + name: aiven-token + key: token + + project: aiven-project-name + cloudName: google-europe-west1 + plan: startup-4 + +--- + +apiVersion: aiven.io/v1alpha1 +kind: Database +metadata: + name: my-database +spec: + authSecretRef: + name: aiven-token + key: token + + project: aiven-project-name + serviceName: my-pg + +--- + +apiVersion: aiven.io/v1alpha1 +kind: ServiceUser +metadata: + name: my-service-user +spec: + authSecretRef: + name: aiven-token + key: token + + project: aiven-project-name + serviceName: my-pg diff --git a/tests/connectionpool_test.go b/tests/connectionpool_test.go index 2a0ff2fb..c4fbf676 100644 --- a/tests/connectionpool_test.go +++ b/tests/connectionpool_test.go @@ -1,7 +1,6 @@ package tests import ( - "fmt" "testing" "github.com/stretchr/testify/assert" @@ -10,69 +9,6 @@ import ( "github.com/aiven/aiven-operator/api/v1alpha1" ) -func getConnectionPoolYaml(project, pgName, dbName, userName, poolName, cloudName string) string { - return fmt.Sprintf(` -apiVersion: aiven.io/v1alpha1 -kind: PostgreSQL -metadata: - name: %[2]s -spec: - authSecretRef: - name: aiven-token - key: token - - project: %[1]s - cloudName: %[6]s - plan: startup-4 - ---- - -apiVersion: aiven.io/v1alpha1 -kind: Database -metadata: - name: %[3]s -spec: - authSecretRef: - name: aiven-token - key: token - - project: %[1]s - serviceName: %[2]s - ---- - -apiVersion: aiven.io/v1alpha1 -kind: ServiceUser -metadata: - name: %[4]s -spec: - authSecretRef: - name: aiven-token - key: token - - project: %[1]s - serviceName: %[2]s - ---- - -apiVersion: aiven.io/v1alpha1 -kind: ConnectionPool -metadata: - name: %[5]s -spec: - authSecretRef: - name: aiven-token - key: token - - project: %[1]s - serviceName: %[2]s - databaseName: %[3]s - username: %[4]s - poolMode: transaction - poolSize: 25 -`, project, pgName, dbName, userName, poolName, cloudName) -} - func TestConnectionPool(t *testing.T) { t.Parallel() defer recoverPanic(t) @@ -81,11 +17,19 @@ func TestConnectionPool(t *testing.T) { ctx, cancel := testCtx() defer cancel() - pgName := randName("connection-pool") - dbName := randName("connection-pool") - userName := randName("connection-pool") + pgName := randName("pg") + dbName := randName("database") + userName := randName("service-user") poolName := randName("connection-pool") - yml := getConnectionPoolYaml(cfg.Project, pgName, dbName, userName, poolName, cfg.PrimaryCloudName) + yml, err := loadExampleYaml("connectionpool.yaml", map[string]string{ + "aiven-project-name": cfg.Project, + "google-europe-west1": cfg.PrimaryCloudName, + "my-connection-pool": poolName, + "my-pg": pgName, + "my-database": dbName, + "my-service-user": userName, + }) + require.NoError(t, err) s := NewSession(ctx, k8sClient, cfg.Project) // Cleans test afterward