From d4aba7f3ebf30071861de82eb782bc5ce9385075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Mon, 18 May 2026 21:37:02 +0200 Subject: [PATCH 1/4] feat: support version detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- Makefile | 4 ++ cluster/local/integration_tests.sh | 4 +- cluster/local/mariadb.server.yaml | 2 +- cluster/local/mariadb.tls.server.yaml | 2 +- cluster/local/mssql.server.yaml | 2 +- cluster/local/mssqldb_functions.sh | 2 +- go.mod | 1 + pkg/clients/mssql/mssql.go | 19 ++++++-- pkg/clients/mysql/mysql.go | 21 ++++++--- pkg/clients/xsql/common.go | 38 ++++++++++++++++ pkg/clients/xsql/common_test.go | 43 +++++++++++++++++++ .../cluster/mssql/database/reconciler.go | 15 ++++++- .../cluster/mssql/database/reconciler_test.go | 3 ++ .../cluster/mssql/grant/reconciler.go | 17 ++++++-- .../cluster/mssql/grant/reconciler_test.go | 3 ++ .../cluster/mssql/user/reconciler.go | 22 +++++++--- .../cluster/mssql/user/reconciler_test.go | 3 ++ .../cluster/mysql/database/reconciler.go | 19 ++++++-- .../cluster/mysql/database/reconciler_test.go | 3 ++ .../cluster/mysql/grant/reconciler.go | 19 ++++++-- .../cluster/mysql/grant/reconciler_test.go | 3 ++ .../cluster/mysql/user/reconciler.go | 22 +++++++--- .../cluster/mysql/user/reconciler_test.go | 3 ++ .../namespaced/mssql/database/reconciler.go | 19 ++++++-- .../mssql/database/reconciler_test.go | 3 ++ .../namespaced/mssql/grant/reconciler.go | 17 ++++++-- .../namespaced/mssql/grant/reconciler_test.go | 3 ++ .../namespaced/mssql/user/reconciler.go | 22 +++++++--- .../namespaced/mssql/user/reconciler_test.go | 3 ++ .../namespaced/mysql/database/reconciler.go | 19 ++++++-- .../mysql/database/reconciler_test.go | 3 ++ .../namespaced/mysql/grant/reconciler.go | 19 ++++++-- .../namespaced/mysql/grant/reconciler_test.go | 3 ++ .../namespaced/mysql/user/reconciler.go | 22 +++++++--- .../namespaced/mysql/user/reconciler_test.go | 3 ++ 35 files changed, 337 insertions(+), 69 deletions(-) diff --git a/Makefile b/Makefile index dfaac434..2dc97967 100644 --- a/Makefile +++ b/Makefile @@ -87,6 +87,8 @@ e2e.run: test-integration CROSSPLANE_HELM_CHANNEL ?= stable CROSSPLANE_HELM_CHART_VERSION ?= POSTGRES_VERSION ?= 18 +MARIADB_VERSION ?= 12 +MSSQL_VERSION ?= 2022-CU24-ubuntu-22.04 # Run integration tests. test-integration: $(KIND) $(KUBECTL) $(CROSSPLANE_CLI) $(HELM) @@ -95,6 +97,8 @@ test-integration: $(KIND) $(KUBECTL) $(CROSSPLANE_CLI) $(HELM) CROSSPLANE_HELM_CHANNEL=${CROSSPLANE_HELM_CHANNEL} \ CROSSPLANE_HELM_CHART_VERSION=${CROSSPLANE_HELM_CHART_VERSION} \ POSTGRES_VERSION=${POSTGRES_VERSION} \ + MARIADB_VERSION=${MARIADB_VERSION} \ + MSSQL_VERSION=${MSSQL_VERSION} \ $(ROOT_DIR)/cluster/local/integration_tests.sh || $(FAIL) @$(OK) integration tests passed diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index 903eb896..296c1a55 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -203,7 +203,7 @@ setup_mariadb_no_tls() { --from-literal endpoint="mariadb.default.svc.cluster.local" \ --from-literal port="3306" - "${KUBECTL}" apply -f ${scriptdir}/mariadb.server.yaml + MARIADB_VERSION="${MARIADB_VERSION:-12}" envsubst '${MARIADB_VERSION}' < "${scriptdir}/mariadb.server.yaml" | "${KUBECTL}" apply -f - echo_step "Waiting for MariaDB to be ready" "${KUBECTL}" rollout status statefulset/mariadb --timeout=120s @@ -228,7 +228,7 @@ setup_mariadb_tls() { " # Deploy MariaDB using official mariadb image with TLS - "${KUBECTL}" apply -f "${scriptdir}/mariadb.tls.server.yaml" + MARIADB_VERSION="${MARIADB_VERSION:-12}" envsubst '${MARIADB_VERSION}' < "${scriptdir}/mariadb.tls.server.yaml" | "${KUBECTL}" apply -f - echo_step "Waiting for MariaDB to be ready" "${KUBECTL}" rollout status statefulset/mariadb --timeout=120s diff --git a/cluster/local/mariadb.server.yaml b/cluster/local/mariadb.server.yaml index dc60ec1b..0662e8e1 100644 --- a/cluster/local/mariadb.server.yaml +++ b/cluster/local/mariadb.server.yaml @@ -28,7 +28,7 @@ spec: spec: containers: - name: mariadb - image: mariadb:12 + image: mariadb:${MARIADB_VERSION} env: - name: MARIADB_ROOT_PASSWORD valueFrom: diff --git a/cluster/local/mariadb.tls.server.yaml b/cluster/local/mariadb.tls.server.yaml index ed4a2094..81b5edca 100644 --- a/cluster/local/mariadb.tls.server.yaml +++ b/cluster/local/mariadb.tls.server.yaml @@ -28,7 +28,7 @@ spec: spec: containers: - name: mariadb - image: mariadb:12 + image: mariadb:${MARIADB_VERSION} args: - --ssl - --require-secure-transport=ON diff --git a/cluster/local/mssql.server.yaml b/cluster/local/mssql.server.yaml index 9168416b..80b76b0b 100644 --- a/cluster/local/mssql.server.yaml +++ b/cluster/local/mssql.server.yaml @@ -28,7 +28,7 @@ spec: spec: containers: - name: mssql - image: mcr.microsoft.com/mssql/server:2019-CU32-ubuntu-20.04 + image: mcr.microsoft.com/mssql/server:${MSSQL_VERSION} env: - name: SA_PASSWORD valueFrom: diff --git a/cluster/local/mssqldb_functions.sh b/cluster/local/mssqldb_functions.sh index d7941cc4..7dd0637a 100644 --- a/cluster/local/mssqldb_functions.sh +++ b/cluster/local/mssqldb_functions.sh @@ -13,7 +13,7 @@ setup_mssql() { echo_step "Verifying secret creation" "${KUBECTL}" get secret mssql-creds -o yaml - "${KUBECTL}" apply -f ${scriptdir}/mssql.server.yaml + MSSQL_VERSION="${MSSQL_VERSION:-2022-CU24-ubuntu-22.04}" envsubst '${MSSQL_VERSION}' < "${scriptdir}/mssql.server.yaml" | "${KUBECTL}" apply -f - echo_step "Waiting for MSSQL Server to be ready" "${KUBECTL}" rollout status statefulset/mssql --timeout=300s diff --git a/go.mod b/go.mod index 4295bebd..a4a8ac38 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/lib/pq v1.12.3 github.com/microsoft/go-mssqldb v1.10.0 github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.11.1 k8s.io/api v0.35.0 k8s.io/apimachinery v0.35.0 k8s.io/utils v0.0.0-20260108192941-914a6e750570 diff --git a/pkg/clients/mssql/mssql.go b/pkg/clients/mssql/mssql.go index 1c0a5ac0..cac81d3b 100644 --- a/pkg/clients/mssql/mssql.go +++ b/pkg/clients/mssql/mssql.go @@ -119,11 +119,22 @@ func (c mssqlDB) GetConnectionDetails(username, password string) managed.Connect } } -// GetServerVersion is not supported by the MSSQL client (only used by PostgreSQL). +// GetServerVersion returns the MSSQL server version as an integer. +// For example, SQL Server 2022 (16.0.1125) returns 160000 (major*10000 + minor*100). +// Build number is ignored as it exceeds the encoding range. func (c mssqlDB) GetServerVersion(ctx context.Context) (int, error) { - // This method should never be called for MSSQL clients - // but is implemented to satisfy the xsql.DB interface - return 0, nil + db, err := sql.Open(driverName, c.dsn) + if err != nil { + return 0, err + } + defer db.Close() //nolint:errcheck + + var version string + if err := db.QueryRowContext(ctx, "SELECT SERVERPROPERTY('ProductVersion')").Scan(&version); err != nil { + return 0, err + } + + return xsql.ParseVersion(version) } // QuoteIdentifier for mssql queries diff --git a/pkg/clients/mysql/mysql.go b/pkg/clients/mysql/mysql.go index 4ab55902..220dea01 100644 --- a/pkg/clients/mysql/mysql.go +++ b/pkg/clients/mysql/mysql.go @@ -7,9 +7,10 @@ import ( "strconv" "strings" - "github.com/crossplane-contrib/provider-sql/pkg/clients/xsql" "github.com/pkg/errors" + "github.com/crossplane-contrib/provider-sql/pkg/clients/xsql" + xpv1 "github.com/crossplane/crossplane-runtime/v2/apis/common/v1" "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed" ) @@ -117,11 +118,21 @@ func (c mySQLDB) GetConnectionDetails(username, password string) managed.Connect } } -// GetServerVersion is not supported by the MySQL client (only used by PostgreSQL). +// GetServerVersion returns the MySQL server version as an integer. +// For example, MySQL 8.0.35 returns 80035 (major*10000 + minor*100 + patch). func (c mySQLDB) GetServerVersion(ctx context.Context) (int, error) { - // This method should never be called for MySQL clients - // but is implemented to satisfy the xsql.DB interface - return 0, nil + db, err := sql.Open("mysql", c.dsn) + if err != nil { + return 0, err + } + defer db.Close() //nolint:errcheck + + var version string + if err := db.QueryRowContext(ctx, "SELECT VERSION()").Scan(&version); err != nil { + return 0, err + } + + return xsql.ParseVersion(version) } // QuoteIdentifier for MySQL queries diff --git a/pkg/clients/xsql/common.go b/pkg/clients/xsql/common.go index b1c78444..6bf3a8b5 100644 --- a/pkg/clients/xsql/common.go +++ b/pkg/clients/xsql/common.go @@ -3,6 +3,9 @@ package xsql import ( "context" "errors" + "fmt" + "strconv" + "strings" "database/sql" @@ -25,6 +28,41 @@ type DB interface { GetServerVersion(ctx context.Context) (int, error) } +// ParseVersion parses a database version string into an integer +// encoded as major*10000 + minor*100 + patch. +// Suffixes after '-' are stripped (e.g. "8.0.35-ubuntu" → 80035). +// Patch values above 99 are ignored (e.g. MSSQL build numbers). +func ParseVersion(version string) (int, error) { + if idx := strings.IndexByte(version, '-'); idx >= 0 { + version = version[:idx] + } + + parts := strings.SplitN(version, ".", 3) + if len(parts) < 2 { + return 0, fmt.Errorf("unexpected version format: %s", version) + } + + major, err := strconv.Atoi(parts[0]) + if err != nil { + return 0, fmt.Errorf("parsing major version %q: %w", parts[0], err) + } + + minor, err := strconv.Atoi(parts[1]) + if err != nil { + return 0, fmt.Errorf("parsing minor version %q: %w", parts[1], err) + } + + var patch int + if len(parts) == 3 { + p, err := strconv.Atoi(parts[2]) + if err == nil && p <= 99 { + patch = p + } + } + + return major*10000 + minor*100 + patch, nil +} + // IsNoRows returns true if the supplied error indicates no rows were returned. func IsNoRows(err error) bool { return errors.Is(err, sql.ErrNoRows) diff --git a/pkg/clients/xsql/common_test.go b/pkg/clients/xsql/common_test.go index 89fad36e..a077435f 100644 --- a/pkg/clients/xsql/common_test.go +++ b/pkg/clients/xsql/common_test.go @@ -4,6 +4,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestRemapCredentialKeys(t *testing.T) { @@ -110,3 +112,44 @@ func TestRemapCredentialKeys(t *testing.T) { } }) } + +func TestParseVersion(t *testing.T) { + tests := []struct { + name string + version string + want int + wantErr bool + }{ + // MySQL-style versions + {name: "MySQL_Standard", version: "8.0.35", want: 80035}, + {name: "MySQL_WithSuffix", version: "8.0.35-0ubuntu0.22.04.1", want: 80035}, + {name: "MySQL_MajorMinorOnly", version: "8.0", want: 80000}, + {name: "MySQL_9", version: "9.1.0", want: 90100}, + {name: "MariaDB", version: "10.11.6-MariaDB", want: 101106}, + + // MSSQL-style versions (build number > 99, ignored) + {name: "MSSQL_2022", version: "16.0.1125.1", want: 160000}, + {name: "MSSQL_2019", version: "15.0.4355.3", want: 150000}, + {name: "MSSQL_NonZeroMinor", version: "16.5.100.1", want: 160500}, + + // PostgreSQL-style (for reference, PG uses its own query) + {name: "ThreeDigitPatch", version: "14.2.1", want: 140201}, + {name: "PatchExactly99", version: "14.0.99", want: 140099}, + {name: "PatchOver99", version: "14.0.100", want: 140000}, + + // Errors + {name: "InvalidFormat", version: "invalid", wantErr: true}, + {name: "EmptyString", version: "", wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseVersion(tt.version) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/controller/cluster/mssql/database/reconciler.go b/pkg/controller/cluster/mssql/database/reconciler.go index bf28ad01..0823c3b8 100644 --- a/pkg/controller/cluster/mssql/database/reconciler.go +++ b/pkg/controller/cluster/mssql/database/reconciler.go @@ -48,6 +48,7 @@ const ( errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" errGetSecret = "cannot get credentials Secret" + errGetServerVersion = "cannot get server version" errSelectDB = "cannot select database" errCreateDB = "cannot create database" @@ -124,10 +125,20 @@ func (c *connector) Connect(ctx context.Context, mg *clusterv1alpha1.Database) ( } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - return &external{db: c.newClient(secretData, "")}, nil + db := c.newClient(secretData, "") + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + + return &external{db: db, serverVersion: serverVersion}, nil } -type external struct{ db xsql.DB } +type external struct { + db xsql.DB + serverVersion int +} var _ managed.TypedExternalClient[*clusterv1alpha1.Database] = &external{} diff --git a/pkg/controller/cluster/mssql/database/reconciler_test.go b/pkg/controller/cluster/mssql/database/reconciler_test.go index a0d77a67..5ae28e93 100644 --- a/pkg/controller/cluster/mssql/database/reconciler_test.go +++ b/pkg/controller/cluster/mssql/database/reconciler_test.go @@ -59,6 +59,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti return m.MockGetConnectionDetails(username, password) } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/cluster/mssql/grant/reconciler.go b/pkg/controller/cluster/mssql/grant/reconciler.go index 7549077b..28e70d0f 100644 --- a/pkg/controller/cluster/mssql/grant/reconciler.go +++ b/pkg/controller/cluster/mssql/grant/reconciler.go @@ -47,7 +47,8 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" + errGetSecret = "cannot get credentials Secret" + errGetServerVersion = "cannot get server version" errGrant = "cannot grant" errRevoke = "cannot revoke" @@ -125,10 +126,20 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.Grant) (managed.Ty } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - return &external{db: c.newClient(secretData, ptr.Deref(mg.Spec.ForProvider.Database, ""))}, nil + db := c.newClient(secretData, ptr.Deref(mg.Spec.ForProvider.Database, "")) + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + + return &external{db: db, serverVersion: serverVersion}, nil } -type external struct{ db xsql.DB } +type external struct { + db xsql.DB + serverVersion int +} var _ managed.TypedExternalClient[*v1alpha1.Grant] = &external{} diff --git a/pkg/controller/cluster/mssql/grant/reconciler_test.go b/pkg/controller/cluster/mssql/grant/reconciler_test.go index b47ea255..1145df0f 100644 --- a/pkg/controller/cluster/mssql/grant/reconciler_test.go +++ b/pkg/controller/cluster/mssql/grant/reconciler_test.go @@ -68,6 +68,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti return m.MockGetConnectionDetails(username, password) } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/cluster/mssql/user/reconciler.go b/pkg/controller/cluster/mssql/user/reconciler.go index 5f766f73..ba87f988 100644 --- a/pkg/controller/cluster/mssql/user/reconciler.go +++ b/pkg/controller/cluster/mssql/user/reconciler.go @@ -47,7 +47,8 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" + errGetSecret = "cannot get credentials Secret" + errGetServerVersion = "cannot get server version" errSelectUser = "cannot select user" errCreateUser = "cannot create user %s" @@ -137,17 +138,24 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.User) (managed.Typ loginDB = c.newClient(secretData, ptr.Deref(mg.Spec.ForProvider.LoginDatabase, "")) } + serverVersion, err := userDB.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + return &external{ - userDB: userDB, - loginDB: loginDB, - kube: c.kube, + userDB: userDB, + loginDB: loginDB, + kube: c.kube, + serverVersion: serverVersion, }, nil } type external struct { - userDB xsql.DB - loginDB xsql.DB - kube client.Client + userDB xsql.DB + loginDB xsql.DB + kube client.Client + serverVersion int } var _ managed.TypedExternalClient[*v1alpha1.User] = &external{} diff --git a/pkg/controller/cluster/mssql/user/reconciler_test.go b/pkg/controller/cluster/mssql/user/reconciler_test.go index f560515e..faf16585 100644 --- a/pkg/controller/cluster/mssql/user/reconciler_test.go +++ b/pkg/controller/cluster/mssql/user/reconciler_test.go @@ -70,6 +70,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti } } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/cluster/mysql/database/reconciler.go b/pkg/controller/cluster/mysql/database/reconciler.go index 86443b59..7e0151ee 100644 --- a/pkg/controller/cluster/mysql/database/reconciler.go +++ b/pkg/controller/cluster/mysql/database/reconciler.go @@ -45,8 +45,9 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" + errGetServerVersion = "cannot get server version" errSelectDB = "cannot select database" errCreateDB = "cannot create database" @@ -131,10 +132,20 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.Database) (managed } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - return &external{db: c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog)}, nil + db := c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog) + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + + return &external{db: db, serverVersion: serverVersion}, nil } -type external struct{ db xsql.DB } +type external struct { + db xsql.DB + serverVersion int +} var _ managed.TypedExternalClient[*v1alpha1.Database] = &external{} diff --git a/pkg/controller/cluster/mysql/database/reconciler_test.go b/pkg/controller/cluster/mysql/database/reconciler_test.go index 2928bda1..287ea7e1 100644 --- a/pkg/controller/cluster/mysql/database/reconciler_test.go +++ b/pkg/controller/cluster/mysql/database/reconciler_test.go @@ -59,6 +59,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti return m.MockGetConnectionDetails(username, password) } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/cluster/mysql/grant/reconciler.go b/pkg/controller/cluster/mysql/grant/reconciler.go index 50546675..a8ec03d6 100644 --- a/pkg/controller/cluster/mysql/grant/reconciler.go +++ b/pkg/controller/cluster/mysql/grant/reconciler.go @@ -49,8 +49,9 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" + errGetServerVersion = "cannot get server version" errCreateGrant = "cannot create grant" errRevokeGrant = "cannot revoke grant" @@ -139,10 +140,20 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.Grant) (managed.Ty } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - return &external{db: c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog)}, nil + db := c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog) + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + + return &external{db: db, serverVersion: serverVersion}, nil } -type external struct{ db xsql.DB } +type external struct { + db xsql.DB + serverVersion int +} var _ managed.TypedExternalClient[*v1alpha1.Grant] = &external{} diff --git a/pkg/controller/cluster/mysql/grant/reconciler_test.go b/pkg/controller/cluster/mysql/grant/reconciler_test.go index 39d95b3a..ca983b44 100644 --- a/pkg/controller/cluster/mysql/grant/reconciler_test.go +++ b/pkg/controller/cluster/mysql/grant/reconciler_test.go @@ -69,6 +69,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti return m.MockGetConnectionDetails(username, password) } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/cluster/mysql/user/reconciler.go b/pkg/controller/cluster/mysql/user/reconciler.go index 3eba36a6..cf81eb0e 100644 --- a/pkg/controller/cluster/mysql/user/reconciler.go +++ b/pkg/controller/cluster/mysql/user/reconciler.go @@ -48,8 +48,9 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" + errGetServerVersion = "cannot get server version" errSelectUser = "cannot select user" errCreateUser = "cannot create user" @@ -134,15 +135,24 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.User) (managed.Typ } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) + db := c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog) + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + return &external{ - db: c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog), - kube: c.kube, + db: db, + kube: c.kube, + serverVersion: serverVersion, }, nil } type external struct { - db xsql.DB - kube client.Client + db xsql.DB + kube client.Client + serverVersion int } var _ managed.TypedExternalClient[*v1alpha1.User] = &external{} diff --git a/pkg/controller/cluster/mysql/user/reconciler_test.go b/pkg/controller/cluster/mysql/user/reconciler_test.go index 8d88abd0..9f62c055 100644 --- a/pkg/controller/cluster/mysql/user/reconciler_test.go +++ b/pkg/controller/cluster/mysql/user/reconciler_test.go @@ -67,6 +67,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti } } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/namespaced/mssql/database/reconciler.go b/pkg/controller/namespaced/mssql/database/reconciler.go index fcad40b7..38a88bed 100644 --- a/pkg/controller/namespaced/mssql/database/reconciler.go +++ b/pkg/controller/namespaced/mssql/database/reconciler.go @@ -40,8 +40,9 @@ import ( ) const ( - errTrackUsage = "cannot track ProviderConfig usage" - errTrackPCUsage = "cannot track ProviderConfig usage" + errTrackUsage = "cannot track ProviderConfig usage" + errTrackPCUsage = "cannot track ProviderConfig usage" + errGetServerVersion = "cannot get server version" errSelectDB = "cannot select database" errCreateDB = "cannot create database" @@ -104,10 +105,20 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.Database return nil, err } - return &external{db: c.newClient(providerInfo.SecretData, "")}, nil + db := c.newClient(providerInfo.SecretData, "") + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + + return &external{db: db, serverVersion: serverVersion}, nil } -type external struct{ db xsql.DB } +type external struct { + db xsql.DB + serverVersion int +} var _ managed.TypedExternalClient[*namespacedv1alpha1.Database] = &external{} diff --git a/pkg/controller/namespaced/mssql/database/reconciler_test.go b/pkg/controller/namespaced/mssql/database/reconciler_test.go index bfee3cee..65e8c437 100644 --- a/pkg/controller/namespaced/mssql/database/reconciler_test.go +++ b/pkg/controller/namespaced/mssql/database/reconciler_test.go @@ -62,6 +62,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti return m.MockGetConnectionDetails(username, password) } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/namespaced/mssql/grant/reconciler.go b/pkg/controller/namespaced/mssql/grant/reconciler.go index bba34f77..e5789a50 100644 --- a/pkg/controller/namespaced/mssql/grant/reconciler.go +++ b/pkg/controller/namespaced/mssql/grant/reconciler.go @@ -43,7 +43,8 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" + errTrackPCUsage = "cannot track ProviderConfig usage" + errGetServerVersion = "cannot get server version" errGrant = "cannot grant" errRevoke = "cannot revoke" @@ -107,10 +108,20 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.Grant) ( return nil, err } - return &external{db: c.newClient(providerInfo.SecretData, ptr.Deref(mg.Spec.ForProvider.Database, ""))}, nil + db := c.newClient(providerInfo.SecretData, ptr.Deref(mg.Spec.ForProvider.Database, "")) + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + + return &external{db: db, serverVersion: serverVersion}, nil } -type external struct{ db xsql.DB } +type external struct { + db xsql.DB + serverVersion int +} var _ managed.TypedExternalClient[*namespacedv1alpha1.Grant] = &external{} diff --git a/pkg/controller/namespaced/mssql/grant/reconciler_test.go b/pkg/controller/namespaced/mssql/grant/reconciler_test.go index 7cddc966..7123da19 100644 --- a/pkg/controller/namespaced/mssql/grant/reconciler_test.go +++ b/pkg/controller/namespaced/mssql/grant/reconciler_test.go @@ -71,6 +71,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti return m.MockGetConnectionDetails(username, password) } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/namespaced/mssql/user/reconciler.go b/pkg/controller/namespaced/mssql/user/reconciler.go index 20f62de4..59714023 100644 --- a/pkg/controller/namespaced/mssql/user/reconciler.go +++ b/pkg/controller/namespaced/mssql/user/reconciler.go @@ -43,7 +43,8 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" + errTrackPCUsage = "cannot track ProviderConfig usage" + errGetServerVersion = "cannot get server version" errSelectUser = "cannot select user" errCreateUser = "cannot create user %s" @@ -119,17 +120,24 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.User) (m loginDB = c.newClient(providerInfo.SecretData, ptr.Deref(mg.Spec.ForProvider.LoginDatabase, "")) } + serverVersion, err := userDB.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + return &external{ - userDB: userDB, - loginDB: loginDB, - kube: c.kube, + userDB: userDB, + loginDB: loginDB, + kube: c.kube, + serverVersion: serverVersion, }, nil } type external struct { - userDB xsql.DB - loginDB xsql.DB - kube client.Client + userDB xsql.DB + loginDB xsql.DB + kube client.Client + serverVersion int } var _ managed.TypedExternalClient[*namespacedv1alpha1.User] = &external{} diff --git a/pkg/controller/namespaced/mssql/user/reconciler_test.go b/pkg/controller/namespaced/mssql/user/reconciler_test.go index 976aae78..950c34ea 100644 --- a/pkg/controller/namespaced/mssql/user/reconciler_test.go +++ b/pkg/controller/namespaced/mssql/user/reconciler_test.go @@ -73,6 +73,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti } } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/namespaced/mysql/database/reconciler.go b/pkg/controller/namespaced/mysql/database/reconciler.go index 55d94991..a281f61b 100644 --- a/pkg/controller/namespaced/mysql/database/reconciler.go +++ b/pkg/controller/namespaced/mysql/database/reconciler.go @@ -41,8 +41,9 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" - errTLSConfig = "cannot load TLS config" + errTrackPCUsage = "cannot track ProviderConfig usage" + errTLSConfig = "cannot load TLS config" + errGetServerVersion = "cannot get server version" errSelectDB = "cannot select database" errCreateDB = "cannot create database" @@ -112,10 +113,20 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.Database return nil, errors.Wrap(err, errTLSConfig) } - return &external{db: c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog)}, nil + db := c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog) + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + + return &external{db: db, serverVersion: serverVersion}, nil } -type external struct{ db xsql.DB } +type external struct { + db xsql.DB + serverVersion int +} var _ managed.TypedExternalClient[*namespacedv1alpha1.Database] = &external{} diff --git a/pkg/controller/namespaced/mysql/database/reconciler_test.go b/pkg/controller/namespaced/mysql/database/reconciler_test.go index 8d0abd2c..b473dfc6 100644 --- a/pkg/controller/namespaced/mysql/database/reconciler_test.go +++ b/pkg/controller/namespaced/mysql/database/reconciler_test.go @@ -62,6 +62,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti return m.MockGetConnectionDetails(username, password) } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/namespaced/mysql/grant/reconciler.go b/pkg/controller/namespaced/mysql/grant/reconciler.go index fd431e85..58e579b7 100644 --- a/pkg/controller/namespaced/mysql/grant/reconciler.go +++ b/pkg/controller/namespaced/mysql/grant/reconciler.go @@ -45,8 +45,9 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" - errTLSConfig = "cannot load TLS config" + errTrackPCUsage = "cannot track ProviderConfig usage" + errTLSConfig = "cannot load TLS config" + errGetServerVersion = "cannot get server version" errCreateGrant = "cannot create grant" errRevokeGrant = "cannot revoke grant" @@ -121,10 +122,20 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.Grant) ( return nil, errors.Wrap(err, errTLSConfig) } - return &external{db: c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog)}, nil + db := c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog) + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + + return &external{db: db, serverVersion: serverVersion}, nil } -type external struct{ db xsql.DB } +type external struct { + db xsql.DB + serverVersion int +} var _ managed.TypedExternalClient[*namespacedv1alpha1.Grant] = &external{} diff --git a/pkg/controller/namespaced/mysql/grant/reconciler_test.go b/pkg/controller/namespaced/mysql/grant/reconciler_test.go index 41fb1802..f6ba7bf2 100644 --- a/pkg/controller/namespaced/mysql/grant/reconciler_test.go +++ b/pkg/controller/namespaced/mysql/grant/reconciler_test.go @@ -71,6 +71,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti return m.MockGetConnectionDetails(username, password) } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } diff --git a/pkg/controller/namespaced/mysql/user/reconciler.go b/pkg/controller/namespaced/mysql/user/reconciler.go index de6f2189..621e0459 100644 --- a/pkg/controller/namespaced/mysql/user/reconciler.go +++ b/pkg/controller/namespaced/mysql/user/reconciler.go @@ -44,8 +44,9 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" - errTLSConfig = "cannot load TLS config" + errTrackPCUsage = "cannot track ProviderConfig usage" + errTLSConfig = "cannot load TLS config" + errGetServerVersion = "cannot get server version" errSelectUser = "cannot select user" errCreateUser = "cannot create user" @@ -116,15 +117,24 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.User) (m return nil, errors.Wrap(err, errTLSConfig) } + db := c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog) + + serverVersion, err := db.GetServerVersion(ctx) + if err != nil { + return nil, errors.Wrap(err, errGetServerVersion) + } + return &external{ - db: c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog), - kube: c.kube, + db: db, + kube: c.kube, + serverVersion: serverVersion, }, nil } type external struct { - db xsql.DB - kube client.Client + db xsql.DB + kube client.Client + serverVersion int } var _ managed.TypedExternalClient[*namespacedv1alpha1.User] = &external{} diff --git a/pkg/controller/namespaced/mysql/user/reconciler_test.go b/pkg/controller/namespaced/mysql/user/reconciler_test.go index 23e9cb56..fe67177a 100644 --- a/pkg/controller/namespaced/mysql/user/reconciler_test.go +++ b/pkg/controller/namespaced/mysql/user/reconciler_test.go @@ -70,6 +70,9 @@ func (m mockDB) GetConnectionDetails(username, password string) managed.Connecti } } func (m mockDB) GetServerVersion(ctx context.Context) (int, error) { + if m.MockGetServerVersion == nil { + return 0, nil + } return m.MockGetServerVersion(ctx) } From 4a4b0202472df7d116d300ef22e85100f8b15c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Mon, 18 May 2026 21:53:07 +0200 Subject: [PATCH 2/4] chore: disable for mssql/mariadb until used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- pkg/clients/postgresql/postgresql.go | 9 ++++--- .../cluster/mssql/database/reconciler.go | 19 ++++----------- .../cluster/mssql/grant/reconciler.go | 19 ++++----------- .../cluster/mssql/user/reconciler.go | 24 +++++++------------ .../cluster/mysql/database/reconciler.go | 21 +++++----------- .../cluster/mysql/grant/reconciler.go | 21 +++++----------- .../cluster/mysql/user/reconciler.go | 24 +++++++------------ .../namespaced/mssql/database/reconciler.go | 21 +++++----------- .../namespaced/mssql/grant/reconciler.go | 19 ++++----------- .../namespaced/mssql/user/reconciler.go | 24 +++++++------------ .../namespaced/mysql/database/reconciler.go | 21 +++++----------- .../namespaced/mysql/grant/reconciler.go | 21 +++++----------- .../namespaced/mysql/user/reconciler.go | 24 +++++++------------ 13 files changed, 85 insertions(+), 182 deletions(-) diff --git a/pkg/clients/postgresql/postgresql.go b/pkg/clients/postgresql/postgresql.go index 97ef36cc..e76a0986 100644 --- a/pkg/clients/postgresql/postgresql.go +++ b/pkg/clients/postgresql/postgresql.go @@ -138,7 +138,7 @@ func (c postgresDB) GetConnectionDetails(username, password string) managed.Conn } } -// GetServerVersion returns the PostgreSQL server version as an integer +// GetServerVersion returns the PostgreSQL server version as an integer. // For example, PostgreSQL 16.2 would return 160200. func (c postgresDB) GetServerVersion(ctx context.Context) (int, error) { db, err := sql.Open("postgres", c.dsn) @@ -148,8 +148,11 @@ func (c postgresDB) GetServerVersion(ctx context.Context) (int, error) { defer db.Close() //nolint:errcheck var version int - err = db.QueryRowContext(ctx, "SELECT current_setting('server_version_num')::int").Scan(&version) - return version, err + if err := db.QueryRowContext(ctx, "SELECT current_setting('server_version_num')::int").Scan(&version); err != nil { + return 0, err + } + + return version, nil } // IsInvalidCatalog returns true if passed a pq error indicating diff --git a/pkg/controller/cluster/mssql/database/reconciler.go b/pkg/controller/cluster/mssql/database/reconciler.go index 0823c3b8..bae3edf0 100644 --- a/pkg/controller/cluster/mssql/database/reconciler.go +++ b/pkg/controller/cluster/mssql/database/reconciler.go @@ -47,8 +47,7 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errGetServerVersion = "cannot get server version" + errGetSecret = "cannot get credentials Secret" errSelectDB = "cannot select database" errCreateDB = "cannot create database" @@ -125,20 +124,12 @@ func (c *connector) Connect(ctx context.Context, mg *clusterv1alpha1.Database) ( } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - db := c.newClient(secretData, "") - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - - return &external{db: db, serverVersion: serverVersion}, nil + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). + return &external{db: c.newClient(secretData, "")}, nil } -type external struct { - db xsql.DB - serverVersion int -} +type external struct{ db xsql.DB } var _ managed.TypedExternalClient[*clusterv1alpha1.Database] = &external{} diff --git a/pkg/controller/cluster/mssql/grant/reconciler.go b/pkg/controller/cluster/mssql/grant/reconciler.go index 28e70d0f..86a1958b 100644 --- a/pkg/controller/cluster/mssql/grant/reconciler.go +++ b/pkg/controller/cluster/mssql/grant/reconciler.go @@ -47,8 +47,7 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errGetServerVersion = "cannot get server version" + errGetSecret = "cannot get credentials Secret" errGrant = "cannot grant" errRevoke = "cannot revoke" @@ -126,20 +125,12 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.Grant) (managed.Ty } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - db := c.newClient(secretData, ptr.Deref(mg.Spec.ForProvider.Database, "")) - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - - return &external{db: db, serverVersion: serverVersion}, nil + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). + return &external{db: c.newClient(secretData, ptr.Deref(mg.Spec.ForProvider.Database, ""))}, nil } -type external struct { - db xsql.DB - serverVersion int -} +type external struct{ db xsql.DB } var _ managed.TypedExternalClient[*v1alpha1.Grant] = &external{} diff --git a/pkg/controller/cluster/mssql/user/reconciler.go b/pkg/controller/cluster/mssql/user/reconciler.go index ba87f988..90e3039c 100644 --- a/pkg/controller/cluster/mssql/user/reconciler.go +++ b/pkg/controller/cluster/mssql/user/reconciler.go @@ -47,8 +47,7 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errGetServerVersion = "cannot get server version" + errGetSecret = "cannot get credentials Secret" errSelectUser = "cannot select user" errCreateUser = "cannot create user %s" @@ -138,24 +137,19 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.User) (managed.Typ loginDB = c.newClient(secretData, ptr.Deref(mg.Spec.ForProvider.LoginDatabase, "")) } - serverVersion, err := userDB.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - + // To add version-gated logic, call userDB.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). return &external{ - userDB: userDB, - loginDB: loginDB, - kube: c.kube, - serverVersion: serverVersion, + userDB: userDB, + loginDB: loginDB, + kube: c.kube, }, nil } type external struct { - userDB xsql.DB - loginDB xsql.DB - kube client.Client - serverVersion int + userDB xsql.DB + loginDB xsql.DB + kube client.Client } var _ managed.TypedExternalClient[*v1alpha1.User] = &external{} diff --git a/pkg/controller/cluster/mysql/database/reconciler.go b/pkg/controller/cluster/mysql/database/reconciler.go index 7e0151ee..1ef9917b 100644 --- a/pkg/controller/cluster/mysql/database/reconciler.go +++ b/pkg/controller/cluster/mysql/database/reconciler.go @@ -45,9 +45,8 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" - errGetServerVersion = "cannot get server version" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errSelectDB = "cannot select database" errCreateDB = "cannot create database" @@ -132,20 +131,12 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.Database) (managed } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - db := c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog) - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - - return &external{db: db, serverVersion: serverVersion}, nil + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). + return &external{db: c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog)}, nil } -type external struct { - db xsql.DB - serverVersion int -} +type external struct{ db xsql.DB } var _ managed.TypedExternalClient[*v1alpha1.Database] = &external{} diff --git a/pkg/controller/cluster/mysql/grant/reconciler.go b/pkg/controller/cluster/mysql/grant/reconciler.go index a8ec03d6..9805a8d4 100644 --- a/pkg/controller/cluster/mysql/grant/reconciler.go +++ b/pkg/controller/cluster/mysql/grant/reconciler.go @@ -49,9 +49,8 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" - errGetServerVersion = "cannot get server version" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errCreateGrant = "cannot create grant" errRevokeGrant = "cannot revoke grant" @@ -140,20 +139,12 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.Grant) (managed.Ty } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - db := c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog) - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - - return &external{db: db, serverVersion: serverVersion}, nil + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). + return &external{db: c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog)}, nil } -type external struct { - db xsql.DB - serverVersion int -} +type external struct{ db xsql.DB } var _ managed.TypedExternalClient[*v1alpha1.Grant] = &external{} diff --git a/pkg/controller/cluster/mysql/user/reconciler.go b/pkg/controller/cluster/mysql/user/reconciler.go index cf81eb0e..2a10f91b 100644 --- a/pkg/controller/cluster/mysql/user/reconciler.go +++ b/pkg/controller/cluster/mysql/user/reconciler.go @@ -48,9 +48,8 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" - errGetServerVersion = "cannot get server version" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errSelectUser = "cannot select user" errCreateUser = "cannot create user" @@ -135,24 +134,17 @@ func (c *connector) Connect(ctx context.Context, mg *v1alpha1.User) (managed.Typ } secretData := xsql.RemapCredentialKeys(s.Data, pc.Spec.Credentials.SecretKeyMapping.ToMap()) - db := c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog) - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). return &external{ - db: db, - kube: c.kube, - serverVersion: serverVersion, + db: c.newDB(secretData, tlsName, mg.Spec.ForProvider.BinLog), + kube: c.kube, }, nil } type external struct { - db xsql.DB - kube client.Client - serverVersion int + db xsql.DB + kube client.Client } var _ managed.TypedExternalClient[*v1alpha1.User] = &external{} diff --git a/pkg/controller/namespaced/mssql/database/reconciler.go b/pkg/controller/namespaced/mssql/database/reconciler.go index 38a88bed..d9154c9b 100644 --- a/pkg/controller/namespaced/mssql/database/reconciler.go +++ b/pkg/controller/namespaced/mssql/database/reconciler.go @@ -40,9 +40,8 @@ import ( ) const ( - errTrackUsage = "cannot track ProviderConfig usage" - errTrackPCUsage = "cannot track ProviderConfig usage" - errGetServerVersion = "cannot get server version" + errTrackUsage = "cannot track ProviderConfig usage" + errTrackPCUsage = "cannot track ProviderConfig usage" errSelectDB = "cannot select database" errCreateDB = "cannot create database" @@ -105,20 +104,12 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.Database return nil, err } - db := c.newClient(providerInfo.SecretData, "") - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - - return &external{db: db, serverVersion: serverVersion}, nil + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). + return &external{db: c.newClient(providerInfo.SecretData, "")}, nil } -type external struct { - db xsql.DB - serverVersion int -} +type external struct{ db xsql.DB } var _ managed.TypedExternalClient[*namespacedv1alpha1.Database] = &external{} diff --git a/pkg/controller/namespaced/mssql/grant/reconciler.go b/pkg/controller/namespaced/mssql/grant/reconciler.go index e5789a50..3bdb031e 100644 --- a/pkg/controller/namespaced/mssql/grant/reconciler.go +++ b/pkg/controller/namespaced/mssql/grant/reconciler.go @@ -43,8 +43,7 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" - errGetServerVersion = "cannot get server version" + errTrackPCUsage = "cannot track ProviderConfig usage" errGrant = "cannot grant" errRevoke = "cannot revoke" @@ -108,20 +107,12 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.Grant) ( return nil, err } - db := c.newClient(providerInfo.SecretData, ptr.Deref(mg.Spec.ForProvider.Database, "")) - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - - return &external{db: db, serverVersion: serverVersion}, nil + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). + return &external{db: c.newClient(providerInfo.SecretData, ptr.Deref(mg.Spec.ForProvider.Database, ""))}, nil } -type external struct { - db xsql.DB - serverVersion int -} +type external struct{ db xsql.DB } var _ managed.TypedExternalClient[*namespacedv1alpha1.Grant] = &external{} diff --git a/pkg/controller/namespaced/mssql/user/reconciler.go b/pkg/controller/namespaced/mssql/user/reconciler.go index 59714023..29d9455a 100644 --- a/pkg/controller/namespaced/mssql/user/reconciler.go +++ b/pkg/controller/namespaced/mssql/user/reconciler.go @@ -43,8 +43,7 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" - errGetServerVersion = "cannot get server version" + errTrackPCUsage = "cannot track ProviderConfig usage" errSelectUser = "cannot select user" errCreateUser = "cannot create user %s" @@ -120,24 +119,19 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.User) (m loginDB = c.newClient(providerInfo.SecretData, ptr.Deref(mg.Spec.ForProvider.LoginDatabase, "")) } - serverVersion, err := userDB.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - + // To add version-gated logic, call userDB.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). return &external{ - userDB: userDB, - loginDB: loginDB, - kube: c.kube, - serverVersion: serverVersion, + userDB: userDB, + loginDB: loginDB, + kube: c.kube, }, nil } type external struct { - userDB xsql.DB - loginDB xsql.DB - kube client.Client - serverVersion int + userDB xsql.DB + loginDB xsql.DB + kube client.Client } var _ managed.TypedExternalClient[*namespacedv1alpha1.User] = &external{} diff --git a/pkg/controller/namespaced/mysql/database/reconciler.go b/pkg/controller/namespaced/mysql/database/reconciler.go index a281f61b..40641dca 100644 --- a/pkg/controller/namespaced/mysql/database/reconciler.go +++ b/pkg/controller/namespaced/mysql/database/reconciler.go @@ -41,9 +41,8 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" - errTLSConfig = "cannot load TLS config" - errGetServerVersion = "cannot get server version" + errTrackPCUsage = "cannot track ProviderConfig usage" + errTLSConfig = "cannot load TLS config" errSelectDB = "cannot select database" errCreateDB = "cannot create database" @@ -113,20 +112,12 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.Database return nil, errors.Wrap(err, errTLSConfig) } - db := c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog) - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - - return &external{db: db, serverVersion: serverVersion}, nil + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). + return &external{db: c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog)}, nil } -type external struct { - db xsql.DB - serverVersion int -} +type external struct{ db xsql.DB } var _ managed.TypedExternalClient[*namespacedv1alpha1.Database] = &external{} diff --git a/pkg/controller/namespaced/mysql/grant/reconciler.go b/pkg/controller/namespaced/mysql/grant/reconciler.go index 58e579b7..678283ec 100644 --- a/pkg/controller/namespaced/mysql/grant/reconciler.go +++ b/pkg/controller/namespaced/mysql/grant/reconciler.go @@ -45,9 +45,8 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" - errTLSConfig = "cannot load TLS config" - errGetServerVersion = "cannot get server version" + errTrackPCUsage = "cannot track ProviderConfig usage" + errTLSConfig = "cannot load TLS config" errCreateGrant = "cannot create grant" errRevokeGrant = "cannot revoke grant" @@ -122,20 +121,12 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.Grant) ( return nil, errors.Wrap(err, errTLSConfig) } - db := c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog) - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - - return &external{db: db, serverVersion: serverVersion}, nil + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). + return &external{db: c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog)}, nil } -type external struct { - db xsql.DB - serverVersion int -} +type external struct{ db xsql.DB } var _ managed.TypedExternalClient[*namespacedv1alpha1.Grant] = &external{} diff --git a/pkg/controller/namespaced/mysql/user/reconciler.go b/pkg/controller/namespaced/mysql/user/reconciler.go index 621e0459..182fc77e 100644 --- a/pkg/controller/namespaced/mysql/user/reconciler.go +++ b/pkg/controller/namespaced/mysql/user/reconciler.go @@ -44,9 +44,8 @@ import ( ) const ( - errTrackPCUsage = "cannot track ProviderConfig usage" - errTLSConfig = "cannot load TLS config" - errGetServerVersion = "cannot get server version" + errTrackPCUsage = "cannot track ProviderConfig usage" + errTLSConfig = "cannot load TLS config" errSelectUser = "cannot select user" errCreateUser = "cannot create user" @@ -117,24 +116,17 @@ func (c *connector) Connect(ctx context.Context, mg *namespacedv1alpha1.User) (m return nil, errors.Wrap(err, errTLSConfig) } - db := c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog) - - serverVersion, err := db.GetServerVersion(ctx) - if err != nil { - return nil, errors.Wrap(err, errGetServerVersion) - } - + // To add version-gated logic, call db.GetServerVersion(ctx) here + // and store it in the external struct (see PostgreSQL grant reconciler). return &external{ - db: db, - kube: c.kube, - serverVersion: serverVersion, + db: c.newDB(providerInfo.SecretData, tlsName, mg.Spec.ForProvider.BinLog), + kube: c.kube, }, nil } type external struct { - db xsql.DB - kube client.Client - serverVersion int + db xsql.DB + kube client.Client } var _ managed.TypedExternalClient[*namespacedv1alpha1.User] = &external{} From 82e775e60d3d02442c852c1ea2e9779d66fc2785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Mon, 18 May 2026 21:57:48 +0200 Subject: [PATCH 3/4] fix: lint issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- pkg/controller/cluster/mssql/database/reconciler.go | 2 +- pkg/controller/cluster/mssql/user/reconciler.go | 2 +- pkg/controller/cluster/mysql/database/reconciler.go | 4 ++-- pkg/controller/cluster/mysql/grant/reconciler.go | 4 ++-- pkg/controller/cluster/mysql/user/reconciler.go | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/controller/cluster/mssql/database/reconciler.go b/pkg/controller/cluster/mssql/database/reconciler.go index bae3edf0..e82642de 100644 --- a/pkg/controller/cluster/mssql/database/reconciler.go +++ b/pkg/controller/cluster/mssql/database/reconciler.go @@ -47,7 +47,7 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" + errGetSecret = "cannot get credentials Secret" errSelectDB = "cannot select database" errCreateDB = "cannot create database" diff --git a/pkg/controller/cluster/mssql/user/reconciler.go b/pkg/controller/cluster/mssql/user/reconciler.go index 90e3039c..c5909346 100644 --- a/pkg/controller/cluster/mssql/user/reconciler.go +++ b/pkg/controller/cluster/mssql/user/reconciler.go @@ -47,7 +47,7 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" + errGetSecret = "cannot get credentials Secret" errSelectUser = "cannot select user" errCreateUser = "cannot create user %s" diff --git a/pkg/controller/cluster/mysql/database/reconciler.go b/pkg/controller/cluster/mysql/database/reconciler.go index 1ef9917b..cb0402f1 100644 --- a/pkg/controller/cluster/mysql/database/reconciler.go +++ b/pkg/controller/cluster/mysql/database/reconciler.go @@ -45,8 +45,8 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errSelectDB = "cannot select database" errCreateDB = "cannot create database" diff --git a/pkg/controller/cluster/mysql/grant/reconciler.go b/pkg/controller/cluster/mysql/grant/reconciler.go index 9805a8d4..718eeb05 100644 --- a/pkg/controller/cluster/mysql/grant/reconciler.go +++ b/pkg/controller/cluster/mysql/grant/reconciler.go @@ -49,8 +49,8 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errCreateGrant = "cannot create grant" errRevokeGrant = "cannot revoke grant" diff --git a/pkg/controller/cluster/mysql/user/reconciler.go b/pkg/controller/cluster/mysql/user/reconciler.go index 2a10f91b..827804b6 100644 --- a/pkg/controller/cluster/mysql/user/reconciler.go +++ b/pkg/controller/cluster/mysql/user/reconciler.go @@ -48,8 +48,8 @@ const ( errTrackPCUsage = "cannot track ProviderConfig usage" errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" - errGetSecret = "cannot get credentials Secret" - errTLSConfig = "cannot load TLS config" + errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errSelectUser = "cannot select user" errCreateUser = "cannot create user" From 2b65ebe67b81ed4def4a45ef00c43dce92e73b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Mon, 18 May 2026 22:01:48 +0200 Subject: [PATCH 4/4] fix: set CI concurrency and add missing inputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- .github/workflows/ci.yml | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 998b2e82..e2e526eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,16 +9,30 @@ on: workflow_dispatch: inputs: postgres_version: - description: 'PostgreSQL major version to test against (e.g. 16, 17, 18)' + description: "PostgreSQL major version to test against (e.g. 16, 17, 18)" required: false - default: '18' + default: "18" type: string + mariadb_version: + description: "MariaDB major version to test against (e.g. 11, 12)" + required: false + default: "12" + type: string + mssql_version: + description: "MSSQL Server image tag (e.g. 2022-CU24-ubuntu-22.04)" + required: false + default: "2022-CU24-ubuntu-22.04" + type: string + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} env: # Common versions - GO_VERSION: '1.26' - GOLANGCI_VERSION: 'v2.10.1' - DOCKER_BUILDX_VERSION: 'v0.23.0' + GO_VERSION: "1.26" + GOLANGCI_VERSION: "v2.10.1" + DOCKER_BUILDX_VERSION: "v0.23.0" # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run # a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether @@ -42,7 +56,6 @@ jobs: do_not_skip: '["workflow_dispatch", "schedule", "push"]' concurrent_skipping: false - lint: runs-on: ubuntu-24.04 needs: detect-noop @@ -245,7 +258,11 @@ jobs: # BUILD_ARGS: "--load" - name: Run E2E Tests - run: make e2e USE_HELM=true POSTGRES_VERSION=${{ inputs.postgres_version || '18' }} + run: >- + make e2e USE_HELM=true + POSTGRES_VERSION=${{ inputs.postgres_version }} + MARIADB_VERSION=${{ inputs.mariadb_version }} + MSSQL_VERSION=${{ inputs.mssql_version }} publish-artifacts: runs-on: ubuntu-24.04