Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ on:
required: false
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
Expand Down Expand Up @@ -42,7 +56,6 @@ jobs:
do_not_skip: '["workflow_dispatch", "schedule", "push"]'
concurrent_skipping: false


lint:
runs-on: ubuntu-24.04
needs: detect-noop
Expand Down Expand Up @@ -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 || '18' }}
MARIADB_VERSION=${{ inputs.mariadb_version || '12' }}
MSSQL_VERSION=${{ inputs.mssql_version || '2022-CU24-ubuntu-22.04' }}

publish-artifacts:
runs-on: ubuntu-24.04
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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

Expand Down
51 changes: 24 additions & 27 deletions cluster/local/integration_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,10 @@ projectdir="$( cd "$( dirname "${BASH_SOURCE[0]}")"/../.. && pwd )"
scriptdir="$(dirname "$0")"

# get the build environment variables from the special build.vars target in the main makefile
eval $(make --no-print-directory -C ${projectdir} build.vars)
eval "$(make --no-print-directory -C "${projectdir}" build.vars)"

# ------------------------------

SAFEHOSTARCH="${SAFEHOSTARCH:-amd64}"
CONTROLLER_IMAGE="${BUILD_REGISTRY}/${PROJECT_NAME}-${SAFEHOSTARCH}"

K8S_CLUSTER="${K8S_CLUSTER:-${BUILD_REGISTRY}-inttests}"

PACKAGE_NAME="provider-sql"
Expand Down Expand Up @@ -117,7 +114,7 @@ setup_crossplane() {

setup_provider() {
echo_step "deploying provider via local.xpkg.deploy"
make -C "${projectdir}" local.xpkg.deploy.provider.${PACKAGE_NAME} KIND_CLUSTER_NAME="${K8S_CLUSTER}"
make -C "${projectdir}" "local.xpkg.deploy.provider.${PACKAGE_NAME}" KIND_CLUSTER_NAME="${K8S_CLUSTER}"

echo_step "waiting for provider to be installed"
"${KUBECTL}" wait "provider.pkg.crossplane.io/${PACKAGE_NAME}" --for=condition=healthy --timeout=60s
Expand All @@ -127,13 +124,13 @@ cleanup_provider() {
echo_step "uninstalling provider"

"${KUBECTL}" delete provider.pkg.crossplane.io "${PACKAGE_NAME}"
"${KUBECTL}" delete deploymentruntimeconfig.pkg.crossplane.io runtimeconfig-${PACKAGE_NAME}
"${KUBECTL}" delete deploymentruntimeconfig.pkg.crossplane.io "runtimeconfig-${PACKAGE_NAME}"

echo_step "waiting for provider pods to be deleted"
timeout=60
current=0
step=3
while [[ $(kubectl get providerrevision.pkg.crossplane.io -o name | wc -l | tr -d '[:space:]') != "0" ]]; do
while [[ $("${KUBECTL}" get providerrevision.pkg.crossplane.io -o name | wc -l | tr -d '[:space:]') != "0" ]]; do
echo "waiting another $step seconds"
current=$((current + step))
if [[ $current -ge $timeout ]]; then
Expand Down Expand Up @@ -192,7 +189,7 @@ setup_provider_config_tls() {

cleanup_provider_config() {
echo_step "cleaning up ProviderConfig"
"${KUBECTL}" delete providerconfig.mysql.sql.${APIGROUP_SUFFIX}crossplane.io default
"${KUBECTL}" delete "providerconfig.mysql.sql.${APIGROUP_SUFFIX}crossplane.io" default
}

setup_mariadb_no_tls() {
Expand All @@ -203,7 +200,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
Expand All @@ -228,7 +225,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
Expand All @@ -244,10 +241,10 @@ cleanup_mariadb() {

test_create_database() {
echo_step "test creating MySQL Database resource"
"${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mysql/database.yaml
"${KUBECTL}" apply -f "${projectdir}/examples/${API_TYPE}/mysql/database.yaml"

echo_info "check if is ready"
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/mysql/database.yaml
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${projectdir}/examples/${API_TYPE}/mysql/database.yaml"
echo_step_completed
}

Expand Down Expand Up @@ -278,7 +275,7 @@ test_update_database_charset() {
echo_step "test updating MySQL Database charset and collation"

# Patch the database to use a different collation
"${KUBECTL}" patch database.mysql.sql.${APIGROUP_SUFFIX}crossplane.io example-db --type merge \
"${KUBECTL}" patch "database.mysql.sql.${APIGROUP_SUFFIX}crossplane.io" example-db --type merge \
-p '{"spec":{"forProvider":{"defaultCollation":"utf8mb4_general_ci"}}}'

# Wait for the controller to reconcile the change
Expand All @@ -298,7 +295,7 @@ test_update_database_charset() {
echo_step_completed

# Restore original collation for subsequent tests
"${KUBECTL}" patch database.mysql.sql.${APIGROUP_SUFFIX}crossplane.io example-db --type merge \
"${KUBECTL}" patch "database.mysql.sql.${APIGROUP_SUFFIX}crossplane.io" example-db --type merge \
-p '{"spec":{"forProvider":{"defaultCollation":"utf8mb4_bin"}}}'
sleep 10
}
Expand All @@ -307,14 +304,14 @@ test_remove_database_charset() {
echo_step "test removing charset/collation from spec leaves database unchanged"

# Remove charset and collation from the spec (set forProvider to only have empty fields)
"${KUBECTL}" patch database.mysql.sql.${APIGROUP_SUFFIX}crossplane.io example-db --type json \
"${KUBECTL}" patch "database.mysql.sql.${APIGROUP_SUFFIX}crossplane.io" example-db --type json \
-p '[{"op":"remove","path":"/spec/forProvider/defaultCharacterSet"},{"op":"remove","path":"/spec/forProvider/defaultCollation"}]'

# Wait for the controller to reconcile -- late init should re-populate the fields
sleep 15

echo_info "check database resource is still Ready"
"${KUBECTL}" wait --timeout 30s --for condition=Ready database.mysql.sql.${APIGROUP_SUFFIX}crossplane.io/example-db
"${KUBECTL}" wait --timeout 30s --for condition=Ready "database.mysql.sql.${APIGROUP_SUFFIX}crossplane.io/example-db"
echo_step_completed

echo_info "check charset/collation unchanged in MariaDB"
Expand Down Expand Up @@ -342,10 +339,10 @@ test_create_user() {
echo_step "test creating MySQL User resource"
local user_pw="asdf1234"
"${KUBECTL}" create secret generic example-pw --from-literal password="${user_pw}" --save-config
"${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mysql/user.yaml
"${KUBECTL}" apply -f "${projectdir}/examples/${API_TYPE}/mysql/user.yaml"

echo_info "check if is ready"
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/mysql/user.yaml
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${projectdir}/examples/${API_TYPE}/mysql/user.yaml"
echo_step_completed

echo_info "check if connection secret exists"
Expand All @@ -361,7 +358,7 @@ test_update_user_password() {
"${KUBECTL}" apply -f -

# trigger reconcile
"${KUBECTL}" annotate -f ${projectdir}/examples/${API_TYPE}/mysql/user.yaml reconcile=now
"${KUBECTL}" annotate -f "${projectdir}/examples/${API_TYPE}/mysql/user.yaml" reconcile=now

sleep 3

Expand All @@ -376,12 +373,12 @@ test_create_grant() {
"${KUBECTL}" exec mariadb-0 -- bash -c \
'mariadb -uroot -p${MARIADB_ROOT_PASSWORD} -N -e "CREATE TABLE \`example-db\`.\`example-table\` (id INT, status VARCHAR(50), updated_at TIMESTAMP);"'

"${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mysql/grant_database.yaml
"${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mysql/grant_table.yaml
"${KUBECTL}" apply -f "${projectdir}/examples/${API_TYPE}/mysql/grant_database.yaml"
"${KUBECTL}" apply -f "${projectdir}/examples/${API_TYPE}/mysql/grant_table.yaml"

echo_info "check if is ready"
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/mysql/grant_database.yaml
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/mysql/grant_table.yaml
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${projectdir}/examples/${API_TYPE}/mysql/grant_database.yaml"
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${projectdir}/examples/${API_TYPE}/mysql/grant_table.yaml"
echo_step_completed
}

Expand All @@ -397,10 +394,10 @@ test_all() {

cleanup_test_resources() {
echo_step "cleaning up test resources"
"${KUBECTL}" delete -f ${projectdir}/examples/${API_TYPE}/mysql/grant_database.yaml
"${KUBECTL}" delete -f ${projectdir}/examples/${API_TYPE}/mysql/grant_table.yaml
"${KUBECTL}" delete -f ${projectdir}/examples/${API_TYPE}/mysql/database.yaml
"${KUBECTL}" delete -f ${projectdir}/examples/${API_TYPE}/mysql/user.yaml
"${KUBECTL}" delete -f "${projectdir}/examples/${API_TYPE}/mysql/grant_database.yaml"
"${KUBECTL}" delete -f "${projectdir}/examples/${API_TYPE}/mysql/grant_table.yaml"
"${KUBECTL}" delete -f "${projectdir}/examples/${API_TYPE}/mysql/database.yaml"
"${KUBECTL}" delete -f "${projectdir}/examples/${API_TYPE}/mysql/user.yaml"
"${KUBECTL}" delete secret example-pw
}

Expand Down
2 changes: 1 addition & 1 deletion cluster/local/mariadb.server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ spec:
spec:
containers:
- name: mariadb
image: mariadb:12
image: mariadb:${MARIADB_VERSION}
env:
- name: MARIADB_ROOT_PASSWORD
valueFrom:
Expand Down
2 changes: 1 addition & 1 deletion cluster/local/mariadb.tls.server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ spec:
spec:
containers:
- name: mariadb
image: mariadb:12
image: mariadb:${MARIADB_VERSION}
args:
- --ssl
- --require-secure-transport=ON
Expand Down
2 changes: 1 addition & 1 deletion cluster/local/mssql.server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think MSSQL_VERSION reaches anything — setup_mssql still seds the image line and replaces it with ${MSSQL_IMAGE}. Could we pick one? envsubst like postgres/mariadb perhaps, but it'd need a ${MSSQL_VERSION:-2019-CU32-ubuntu-20.04} default the way they have one — CI passes it empty on push/PR (see the ci.yml comment), so otherwise the tag ends up blank.

env:
- name: SA_PASSWORD
valueFrom:
Expand Down
17 changes: 8 additions & 9 deletions cluster/local/mssqldb_functions.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/env bash
set -e

MSSQL_IMAGE="${MSSQL_IMAGE:-mcr.microsoft.com/mssql/server:2019-CU32-ubuntu-20.04}"
scriptdir=$(dirname "$0")

setup_mssql() {
echo_step "installing MSSQL Server (image ${MSSQL_IMAGE})"
echo_step "installing MSSQL Server (version ${MSSQL_VERSION:-2022-CU24-ubuntu-22.04})"

"${KUBECTL}" create secret generic mssql-creds \
--from-literal username="sa" \
Expand All @@ -15,8 +15,7 @@ setup_mssql() {
echo_step "Verifying secret creation"
"${KUBECTL}" get secret mssql-creds -o yaml

sed "s|image: mcr.microsoft.com/mssql/server:.*|image: ${MSSQL_IMAGE}|" \
"${scriptdir}/mssql.server.yaml" | "${KUBECTL}" apply -f -
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
Expand All @@ -27,7 +26,7 @@ setup_mssql() {

cleanup_mssql() {
echo_step "cleaning up MSSQL server"
"${KUBECTL}" delete -f ${scriptdir}/mssql.server.yaml --ignore-not-found=true
"${KUBECTL}" delete -f "${scriptdir}/mssql.server.yaml" --ignore-not-found=true
"${KUBECTL}" delete secret mssql-creds --ignore-not-found=true
}

Expand All @@ -43,10 +42,10 @@ cleanup_mssql_provider_config() {

test_create_mssql_database() {
echo_step "test creating MSSQL Database resource"
"${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mssql/database.yaml
"${KUBECTL}" apply -f "${projectdir}/examples/${API_TYPE}/mssql/database.yaml"

echo_step "Waiting for MSSQL Database to be ready"
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/mssql/database.yaml
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${projectdir}/examples/${API_TYPE}/mssql/database.yaml"

echo_step_completed
}
Expand All @@ -56,10 +55,10 @@ test_create_mssql_user() {
# Create password secret first
"${KUBECTL}" create secret generic example-pw --from-literal password="Test123!" --dry-run=client -o yaml | "${KUBECTL}" apply -f -

"${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mssql/user.yaml
"${KUBECTL}" apply -f "${projectdir}/examples/${API_TYPE}/mssql/user.yaml"

echo_step "Waiting for MSSQL User to be ready"
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/mssql/user.yaml
"${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${projectdir}/examples/${API_TYPE}/mssql/user.yaml"

echo_step_completed
}
Expand Down
19 changes: 15 additions & 4 deletions pkg/clients/mssql/mssql.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 16 additions & 5 deletions pkg/clients/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

"github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/managed"
xpv2 "github.com/crossplane/crossplane/apis/v2/core/v2"
)
Expand Down Expand Up @@ -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
Expand Down
Loading