From d6f3f67e5c86297701a487dc7ad2745139f7170f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Tue, 8 Sep 2026 16:23:09 +0200 Subject: [PATCH 1/6] chore: bump up runners and decouple CI from go version 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 | 23 +++++++++---------- .github/workflows/codeql.yml | 4 ++-- .../workflows/publish-provider-package.yml | 6 +---- .github/workflows/tag.yml | 2 +- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 692228bc..28ef4968 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,6 @@ on: env: # Common versions - GO_VERSION: '1.26.8' GOLANGCI_VERSION: 'v2.10.1' DOCKER_BUILDX_VERSION: 'v0.23.0' @@ -29,7 +28,7 @@ env: jobs: detect-noop: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 outputs: noop: ${{ steps.noop.outputs.should_skip }} steps: @@ -44,7 +43,7 @@ jobs: lint: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' @@ -57,7 +56,7 @@ jobs: - name: Setup Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Find the Go Build Cache id: go @@ -88,7 +87,7 @@ jobs: version: ${{ env.GOLANGCI_VERSION }} check-diff: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' @@ -101,7 +100,7 @@ jobs: - name: Setup Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Find the Go Build Cache id: go @@ -135,7 +134,7 @@ jobs: run: git diff unit-tests: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' permissions: @@ -154,7 +153,7 @@ jobs: - name: Setup Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Find the Go Build Cache id: go @@ -188,7 +187,7 @@ jobs: files: _output/tests/linux_amd64/coverage.txt e2e-tests: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' @@ -214,7 +213,7 @@ jobs: - name: Setup Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Find the Go Build Cache id: go @@ -248,7 +247,7 @@ jobs: run: make e2e USE_HELM=true POSTGRES_VERSION=${{ inputs.postgres_version || '18' }} publish-artifacts: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' @@ -282,7 +281,7 @@ jobs: - name: Setup Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: ${{ env.GO_VERSION }} + go-version-file: go.mod - name: Find the Go Build Cache id: go diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9b42232a..8fc620ac 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -9,7 +9,7 @@ on: jobs: detect-noop: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 outputs: noop: ${{ steps.noop.outputs.should_skip }} steps: @@ -23,7 +23,7 @@ jobs: concurrent_skipping: false analyze: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' diff --git a/.github/workflows/publish-provider-package.yml b/.github/workflows/publish-provider-package.yml index 2e7b6849..1ea7ceba 100644 --- a/.github/workflows/publish-provider-package.yml +++ b/.github/workflows/publish-provider-package.yml @@ -7,10 +7,6 @@ on: description: "Version string to use while publishing the package (e.g. v1.0.0-alpha.1)" default: "" required: false - go-version: - description: "Go version to use if building needs to be done" - default: "1.26.8" - required: false jobs: publish-provider-package: @@ -27,7 +23,7 @@ jobs: add-extensions: needs: publish-provider-package - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index c61733a7..eb8b79ff 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -12,7 +12,7 @@ on: jobs: create-tag: - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 steps: - name: Checkout From 3f35eda97f0c53519c8d7cdde087e36711873554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Tue, 22 Sep 2026 23:28:42 +0200 Subject: [PATCH 2/6] fix: infer go version 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/publish-provider-package.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-provider-package.yml b/.github/workflows/publish-provider-package.yml index 1ea7ceba..4649b4a3 100644 --- a/.github/workflows/publish-provider-package.yml +++ b/.github/workflows/publish-provider-package.yml @@ -9,12 +9,26 @@ on: required: false jobs: + get-go-version: + runs-on: ubuntu-latest + outputs: + go-version: ${{ steps.extract-version.outputs.version }} + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Extract Go version from go.mod + id: extract-version + run: | + GO_VERSION=$(grep '^go ' go.mod | awk '{print $2}') + echo "version=${GO_VERSION}" | tee -a $GITHUB_OUTPUT + publish-provider-package: + needs: get-go-version uses: crossplane-contrib/provider-workflows/.github/workflows/publish-provider-non-family.yml@d736839d853a03083eb1aac9af4825f11321c88c with: repository: provider-sql version: ${{ github.event.inputs.version }} - go-version: ${{ github.event.inputs.go-version }} + go-version: ${{ needs.get-go-version.outputs.go-version }} cleanup-disk: true secrets: GHCR_PAT: ${{ secrets.GITHUB_TOKEN }} From 29a4c7adbea30905d1180e759fe0221a16c03da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Thu, 1 Oct 2026 01:02:06 +0200 Subject: [PATCH 3/6] ci: allow (re)running test for a specific DB engine 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 | 6 ++++ README.md | 31 ++++++++++++++++++++ cluster/local/integration_tests.sh | 45 +++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 31517508..7735a178 100644 --- a/Makefile +++ b/Makefile @@ -87,6 +87,10 @@ e2e.run: test-integration CROSSPLANE_HELM_CHANNEL ?= stable CROSSPLANE_HELM_CHART_VERSION ?= POSTGRES_VERSION ?= 18 +# DB selects the integration test suite: all, mysql, postgresql or mssql. +DB ?= all +# skipcleanup=true keeps the kind cluster and provider after the run; the next run reuses them. +skipcleanup ?= false # Run integration tests. test-integration: $(KIND) $(KUBECTL) $(CROSSPLANE_CLI) $(HELM) @@ -95,6 +99,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} \ + DB=${DB} \ + skipcleanup=${skipcleanup} \ $(ROOT_DIR)/cluster/local/integration_tests.sh || $(FAIL) @$(OK) integration tests passed diff --git a/README.md b/README.md index 174e38a5..459a7314 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,37 @@ Check the example: 5. Run `make reviewable` to run code generation, linters, and tests. 6. Commit, push, and PR. +## Integration tests + +Integration tests run against a local [kind](https://kind.sigs.k8s.io) cluster +with Crossplane, the provider, and the database servers deployed in it. + +```console +make build +make e2e # or: make test-integration +``` + +Options (pass as `make` variables, e.g. `make e2e DB=postgresql`): + +| Variable | Default | Description | +|---|---|---| +| `DB` | `all` | Database suite to run: `all`, `mysql`, `postgresql` or `mssql`. | +| `skipcleanup` | `false` | `true` keeps the kind cluster and the provider after the run. The next run reuses the cluster (skips cluster and Crossplane setup) and redeploys the provider. | +| `QUICK_TEST` | unset | `true` stops after the provider is healthy, without running database tests. | +| `POSTGRES_VERSION` | `18` | PostgreSQL server image version. | +| `MSSQL_IMAGE` | `mcr.microsoft.com/mssql/server:2019-CU32-ubuntu-20.04` | MSSQL server image. | +| `KIND_NODE_IMAGE_TAG` | see `Makefile` | kind node image tag (Kubernetes version). | +| `K8S_CLUSTER` | `-inttests` | kind cluster name. | +| `CROSSPLANE_HELM_CHANNEL` | `stable` | Crossplane Helm chart channel. | +| `CROSSPLANE_HELM_CHART_VERSION` | latest in channel | Crossplane Helm chart version. | + +A preserved cluster can hold leftover database resources from a failed run. +If the next run fails on them, delete the cluster: + +```console +kind delete cluster --name +``` + ## Developing locally **Pre-requisite:** A Kubernetes cluster with Crossplane installed diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index 903eb896..b2ff336a 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -81,8 +81,10 @@ if [ $? -ne 0 ]; then fi integration_tests_end() { - echo_step "--- CLEAN-UP ---" - cleanup_provider + if [ "$skipcleanup" != true ]; then + echo_step "--- CLEAN-UP ---" + cleanup_provider + fi echo_success " All integration tests succeeded!" } @@ -404,8 +406,25 @@ cleanup_test_resources() { "${KUBECTL}" delete secret example-pw } -setup_cluster -setup_crossplane +# DB selects which database suite to run: all (default), mysql, postgresql or mssql. +DB="${DB:-all}" +case "${DB}" in + all|mysql|postgresql|mssql) ;; + *) echo_error "Invalid DB='${DB}'. Expected one of: all, mysql, postgresql, mssql." ;; +esac + +db_selected() { + [[ "${DB}" == "all" || "${DB}" == "$1" ]] +} + +# reuse a cluster kept by a previous run with skipcleanup=true +if "${KIND}" get clusters | grep -qx "${K8S_CLUSTER}"; then + echo_step "reusing existing k8s cluster ${K8S_CLUSTER}" + "${KIND}" export kubeconfig --name="${K8S_CLUSTER}" +else + setup_cluster + setup_crossplane +fi setup_provider if [ "${QUICK_TEST:-}" == "true" ]; then @@ -451,14 +470,20 @@ run_test() { echo_step "--- TESTING $testmain DONE IN ${duration}s ---" } -TLS=true API_TYPE="namespaced" run_test integration_tests_mariadb -TLS=false API_TYPE="cluster" run_test integration_tests_mariadb +if db_selected mysql; then + TLS=true API_TYPE="namespaced" run_test integration_tests_mariadb + TLS=false API_TYPE="cluster" run_test integration_tests_mariadb +fi -TLS=false API_TYPE="cluster" run_test integration_tests_postgres -TLS=false API_TYPE="namespaced" run_test integration_tests_postgres +if db_selected postgresql; then + TLS=false API_TYPE="cluster" run_test integration_tests_postgres + TLS=false API_TYPE="namespaced" run_test integration_tests_postgres +fi # no TLS=false variant - MSSQL uses built-in encryption -TLS=true API_TYPE="cluster" run_test integration_tests_mssql -TLS=true API_TYPE="namespaced" run_test integration_tests_mssql +if db_selected mssql; then + TLS=true API_TYPE="cluster" run_test integration_tests_mssql + TLS=true API_TYPE="namespaced" run_test integration_tests_mssql +fi integration_tests_end From a03574578ea0a481b168906e31d055f7fedbee9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Thu, 8 Oct 2026 23:34:45 +0200 Subject: [PATCH 4/6] ci: run e2e tests per engine in a matrix and clean up test scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Run the e2e job as a matrix over mysql, postgresql and mssql, each in its own kind cluster. - Rename the DB make/script variable to ENGINE. - Stop printing the mssql-creds secret (SA password) to the logs. - Delete the postgres ProviderConfig on cleanup; it referenced an unset variable and was never deleted. - Run psql inside the pod via kubectl exec instead of a port-forward, and add mariadb_query/pg_query helpers for the repeated exec calls. - Fix all shellcheck findings and add a .shellcheckrc so sourced files are followed. Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +- Makefile | 6 +- README.md | 4 +- cluster/local/.shellcheckrc | 1 + cluster/local/integration_tests.sh | 153 +++++++++++------------- cluster/local/mssqldb_functions.sh | 64 +++++----- cluster/local/postgresdb_functions.sh | 163 ++++++++++---------------- 7 files changed, 173 insertions(+), 224 deletions(-) create mode 100644 cluster/local/.shellcheckrc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bb99396..40802803 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -190,6 +190,10 @@ jobs: runs-on: ubuntu-26.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' + strategy: + fail-fast: false + matrix: + engine: [mysql, postgresql, mssql] steps: - name: Setup QEMU @@ -244,7 +248,7 @@ 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 ENGINE=${{ matrix.engine }} POSTGRES_VERSION=${{ inputs.postgres_version || '18' }} publish-artifacts: runs-on: ubuntu-26.04 diff --git a/Makefile b/Makefile index 7735a178..0cc75c88 100644 --- a/Makefile +++ b/Makefile @@ -87,8 +87,8 @@ e2e.run: test-integration CROSSPLANE_HELM_CHANNEL ?= stable CROSSPLANE_HELM_CHART_VERSION ?= POSTGRES_VERSION ?= 18 -# DB selects the integration test suite: all, mysql, postgresql or mssql. -DB ?= all +# ENGINE selects the integration test suite: all, mysql, postgresql or mssql. +ENGINE ?= all # skipcleanup=true keeps the kind cluster and provider after the run; the next run reuses them. skipcleanup ?= false @@ -99,7 +99,7 @@ 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} \ - DB=${DB} \ + ENGINE=${ENGINE} \ skipcleanup=${skipcleanup} \ $(ROOT_DIR)/cluster/local/integration_tests.sh || $(FAIL) @$(OK) integration tests passed diff --git a/README.md b/README.md index 459a7314..2c65692c 100644 --- a/README.md +++ b/README.md @@ -86,11 +86,11 @@ make build make e2e # or: make test-integration ``` -Options (pass as `make` variables, e.g. `make e2e DB=postgresql`): +Options (pass as `make` variables, e.g. `make e2e ENGINE=postgresql`): | Variable | Default | Description | |---|---|---| -| `DB` | `all` | Database suite to run: `all`, `mysql`, `postgresql` or `mssql`. | +| `ENGINE` | `all` | Database engine suite to run: `all`, `mysql`, `postgresql` or `mssql`. | | `skipcleanup` | `false` | `true` keeps the kind cluster and the provider after the run. The next run reuses the cluster (skips cluster and Crossplane setup) and redeploys the provider. | | `QUICK_TEST` | unset | `true` stops after the provider is healthy, without running database tests. | | `POSTGRES_VERSION` | `18` | PostgreSQL server image version. | diff --git a/cluster/local/.shellcheckrc b/cluster/local/.shellcheckrc new file mode 100644 index 00000000..8226afb6 --- /dev/null +++ b/cluster/local/.shellcheckrc @@ -0,0 +1 @@ +external-sources=true diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index b2ff336a..673f7b92 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -1,55 +1,50 @@ #!/usr/bin/env bash +# shellcheck source-path=SCRIPTDIR set -e # setting up colors BLU='\033[0;34m' -YLW='\033[0;33m' GRN='\033[0;32m' RED='\033[0;31m' NOC='\033[0m' # No Color echo_info() { - printf "\n${BLU}%s${NOC}" "$1" + printf '\n%b%s%b' "${BLU}" "$1" "${NOC}" } echo_step() { - printf "\n${BLU}>>>>>>> %s${NOC}\n" "$1" + printf '\n%b>>>>>>> %s%b\n' "${BLU}" "$1" "${NOC}" } echo_sub_step() { - printf "\n${BLU}>>> %s${NOC}\n" "$1" + printf '\n%b>>> %s%b\n' "${BLU}" "$1" "${NOC}" } echo_step_completed() { - printf "${GRN} [✔]${NOC}" + printf '%b [✔]%b' "${GRN}" "${NOC}" } echo_success() { - printf "\n${GRN}%s${NOC}\n" "$1" -} -echo_warn() { - printf "\n${YLW}%s${NOC}" "$1" + printf '\n%b%s%b\n' "${GRN}" "$1" "${NOC}" } echo_error() { - printf "\n${RED}%s${NOC}" "$1" + printf '\n%b%s%b' "${RED}" "$1" "${NOC}" exit 1 } # ------------------------------ -projectdir="$( cd "$( dirname "${BASH_SOURCE[0]}")"/../.. && pwd )" -scriptdir="$(dirname "$0")" +scriptdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +projectdir="$(cd "${scriptdir}/../.." && pwd)" # 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" MARIADB_ROOT_PW=$(openssl rand -base64 32) MARIADB_TEST_PW=$(openssl rand -base64 32) -MSSQL_SA_PW="$(openssl rand -base64 16)Aa1!" # MSSQL requires complex password + +skipcleanup="${skipcleanup:-false}" # cleanup on exit if [ "$skipcleanup" != true ]; then @@ -65,20 +60,8 @@ fi # Global variable to control API type API_TYPE="cluster" -SCRIPT_DIR="$(dirname "$(realpath "$0")")" -# shellcheck source="$SCRIPT_DIR/postgresdb_functions.sh" -source "$SCRIPT_DIR/postgresdb_functions.sh" -if [ $? -ne 0 ]; then - echo "postgresdb_functions.sh failed. Exiting." - exit 1 -fi - -# shellcheck source="$SCRIPT_DIR/mssqldb_functions.sh" -source "$SCRIPT_DIR/mssqldb_functions.sh" -if [ $? -ne 0 ]; then - echo "mssqldb_functions.sh failed. Exiting." - exit 1 -fi +source "${scriptdir}/postgresdb_functions.sh" +source "${scriptdir}/mssqldb_functions.sh" integration_tests_end() { if [ "$skipcleanup" != true ]; then @@ -119,7 +102,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 @@ -129,13 +112,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 @@ -194,7 +177,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() { @@ -205,7 +188,7 @@ setup_mariadb_no_tls() { --from-literal endpoint="mariadb.default.svc.cluster.local" \ --from-literal port="3306" - "${KUBECTL}" apply -f ${scriptdir}/mariadb.server.yaml + "${KUBECTL}" apply -f "${scriptdir}/mariadb.server.yaml" echo_step "Waiting for MariaDB to be ready" "${KUBECTL}" rollout status statefulset/mariadb --timeout=120s @@ -244,12 +227,23 @@ cleanup_mariadb() { "${KUBECTL}" delete secret mariadb-creds } +# Runs SQL as root inside the MariaDB pod. The password expands in the pod, the SQL is passed as $1. +mariadb_query() { + # shellcheck disable=SC2016 + "${KUBECTL}" exec mariadb-0 -- bash -c 'mariadb -uroot -p"${MARIADB_ROOT_PASSWORD}" -N -e "$1"' _ "$1" +} + +# Prints a column of information_schema.schemata for example-db. +example_db_schema_field() { + mariadb_query "SELECT $1 FROM information_schema.schemata WHERE schema_name = 'example-db'" | tr -d '[:space:]' +} + test_create_database() { echo_step "test creating MySQL Database resource" - "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mysql/database.yaml + "${KUBECTL}" apply -f "${EXAMPLES}/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 "${EXAMPLES}/mysql/database.yaml" echo_step_completed } @@ -257,13 +251,8 @@ test_database_charset() { echo_step "test database has correct charset and collation" local charset collation - charset=$("${KUBECTL}" exec mariadb-0 -- bash -c \ - 'mariadb -uroot -p${MARIADB_ROOT_PASSWORD} -N -e "SELECT default_character_set_name FROM information_schema.schemata WHERE schema_name = '"'"'example-db'"'"'"') - collation=$("${KUBECTL}" exec mariadb-0 -- bash -c \ - 'mariadb -uroot -p${MARIADB_ROOT_PASSWORD} -N -e "SELECT default_collation_name FROM information_schema.schemata WHERE schema_name = '"'"'example-db'"'"'"') - - charset=$(echo "${charset}" | tr -d '[:space:]') - collation=$(echo "${collation}" | tr -d '[:space:]') + charset=$(example_db_schema_field default_character_set_name) + collation=$(example_db_schema_field default_collation_name) echo_info "charset=${charset}, collation=${collation}" @@ -280,7 +269,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 @@ -288,9 +277,7 @@ test_update_database_charset() { echo_info "check if collation was updated in MariaDB" local collation - collation=$("${KUBECTL}" exec mariadb-0 -- bash -c \ - 'mariadb -uroot -p${MARIADB_ROOT_PASSWORD} -N -e "SELECT default_collation_name FROM information_schema.schemata WHERE schema_name = '"'"'example-db'"'"'"') - collation=$(echo "${collation}" | tr -d '[:space:]') + collation=$(example_db_schema_field default_collation_name) echo_info "collation=${collation}" @@ -300,7 +287,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 } @@ -309,25 +296,20 @@ 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" local charset collation - charset=$("${KUBECTL}" exec mariadb-0 -- bash -c \ - 'mariadb -uroot -p${MARIADB_ROOT_PASSWORD} -N -e "SELECT default_character_set_name FROM information_schema.schemata WHERE schema_name = '"'"'example-db'"'"'"') - collation=$("${KUBECTL}" exec mariadb-0 -- bash -c \ - 'mariadb -uroot -p${MARIADB_ROOT_PASSWORD} -N -e "SELECT default_collation_name FROM information_schema.schemata WHERE schema_name = '"'"'example-db'"'"'"') - - charset=$(echo "${charset}" | tr -d '[:space:]') - collation=$(echo "${collation}" | tr -d '[:space:]') + charset=$(example_db_schema_field default_character_set_name) + collation=$(example_db_schema_field default_collation_name) echo_info "charset=${charset}, collation=${collation}" @@ -344,14 +326,15 @@ 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 "${EXAMPLES}/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 "${EXAMPLES}/mysql/user.yaml" echo_step_completed echo_info "check if connection secret exists" - local pw=$("${KUBECTL}" get secret example-connection-secret -ojsonpath='{.data.password}' | base64 --decode) + local pw + pw=$("${KUBECTL}" get secret example-connection-secret -ojsonpath='{.data.password}' | base64 --decode) [ "${pw}" == "${user_pw}" ] echo_step_completed } @@ -363,27 +346,28 @@ test_update_user_password() { "${KUBECTL}" apply -f - # trigger reconcile - "${KUBECTL}" annotate -f ${projectdir}/examples/${API_TYPE}/mysql/user.yaml reconcile=now + "${KUBECTL}" annotate -f "${EXAMPLES}/mysql/user.yaml" reconcile=now sleep 3 echo_info "check if connection secret has been updated" - local pw=$("${KUBECTL}" get secret example-connection-secret -ojsonpath='{.data.password}' | base64 --decode) + local pw + pw=$("${KUBECTL}" get secret example-connection-secret -ojsonpath='{.data.password}' | base64 --decode) [ "${pw}" == "${user_pw}" ] echo_step_completed } test_create_grant() { echo_step "test creating MySQL Grant resource" - "${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);"' + # shellcheck disable=SC2016 # backticks are MariaDB identifier quotes + mariadb_query '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 "${EXAMPLES}/mysql/grant_database.yaml" + "${KUBECTL}" apply -f "${EXAMPLES}/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 "${EXAMPLES}/mysql/grant_database.yaml" + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${EXAMPLES}/mysql/grant_table.yaml" echo_step_completed } @@ -399,22 +383,22 @@ 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 "${EXAMPLES}/mysql/grant_database.yaml" + "${KUBECTL}" delete -f "${EXAMPLES}/mysql/grant_table.yaml" + "${KUBECTL}" delete -f "${EXAMPLES}/mysql/database.yaml" + "${KUBECTL}" delete -f "${EXAMPLES}/mysql/user.yaml" "${KUBECTL}" delete secret example-pw } -# DB selects which database suite to run: all (default), mysql, postgresql or mssql. -DB="${DB:-all}" -case "${DB}" in +# ENGINE selects which database engine suite to run: all (default), mysql, postgresql or mssql. +ENGINE="${ENGINE:-all}" +case "${ENGINE}" in all|mysql|postgresql|mssql) ;; - *) echo_error "Invalid DB='${DB}'. Expected one of: all, mysql, postgresql, mssql." ;; + *) echo_error "Invalid ENGINE='${ENGINE}'. Expected one of: all, mysql, postgresql, mssql." ;; esac -db_selected() { - [[ "${DB}" == "all" || "${DB}" == "$1" ]] +engine_selected() { + [[ "${ENGINE}" == "all" || "${ENGINE}" == "$1" ]] } # reuse a cluster kept by a previous run with skipcleanup=true @@ -459,29 +443,30 @@ run_test() { APIGROUP_SUFFIX="m." fi + EXAMPLES="${projectdir}/examples/${API_TYPE}" local testmain="$1" echo_step "--- TESTING $testmain $API_TYPE WITH TLS=$TLS ---" start=$(date +%s) - $testmain + "$testmain" duration=$(( $(date +%s) - start )) echo_step "--- TESTING $testmain DONE IN ${duration}s ---" } -if db_selected mysql; then +if engine_selected mysql; then TLS=true API_TYPE="namespaced" run_test integration_tests_mariadb TLS=false API_TYPE="cluster" run_test integration_tests_mariadb fi -if db_selected postgresql; then +if engine_selected postgresql; then TLS=false API_TYPE="cluster" run_test integration_tests_postgres TLS=false API_TYPE="namespaced" run_test integration_tests_postgres fi # no TLS=false variant - MSSQL uses built-in encryption -if db_selected mssql; then +if engine_selected mssql; then TLS=true API_TYPE="cluster" run_test integration_tests_mssql TLS=true API_TYPE="namespaced" run_test integration_tests_mssql fi diff --git a/cluster/local/mssqldb_functions.sh b/cluster/local/mssqldb_functions.sh index ddeef31a..0fb0c50c 100644 --- a/cluster/local/mssqldb_functions.sh +++ b/cluster/local/mssqldb_functions.sh @@ -1,20 +1,20 @@ #!/usr/bin/env bash -set -e +# Sourced by integration_tests.sh, which defines KUBECTL, scriptdir, EXAMPLES, APIGROUP_SUFFIX and the echo_* helpers. +# shellcheck disable=SC2154 MSSQL_IMAGE="${MSSQL_IMAGE:-mcr.microsoft.com/mssql/server:2019-CU32-ubuntu-20.04}" setup_mssql() { echo_step "installing MSSQL Server (image ${MSSQL_IMAGE})" + local sa_pw + sa_pw="$(openssl rand -base64 16)Aa1!" # MSSQL requires complex password "${KUBECTL}" create secret generic mssql-creds \ --from-literal username="sa" \ - --from-literal password="${MSSQL_SA_PW}" \ + --from-literal password="${sa_pw}" \ --from-literal endpoint="mssql.default.svc.cluster.local" \ --from-literal port="1433" - 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 - @@ -27,7 +27,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 } @@ -38,15 +38,15 @@ setup_mssql_provider_config() { cleanup_mssql_provider_config() { echo_step "cleaning up MSSQL provider config" - "${KUBECTL}" delete providerconfig.mssql.sql.${APIGROUP_SUFFIX}crossplane.io default --ignore-not-found=true + "${KUBECTL}" delete "providerconfig.mssql.sql.${APIGROUP_SUFFIX}crossplane.io" default --ignore-not-found=true } test_create_mssql_database() { echo_step "test creating MSSQL Database resource" - "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mssql/database.yaml + "${KUBECTL}" apply -f "${EXAMPLES}/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 "${EXAMPLES}/mssql/database.yaml" echo_step_completed } @@ -56,10 +56,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 "${EXAMPLES}/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 "${EXAMPLES}/mssql/user.yaml" echo_step_completed } @@ -68,10 +68,10 @@ test_update_mssql_user_password() { echo_step "test updating MSSQL User password" # Update password secret - "${KUBECTL}" patch secret example-pw -p '{"data":{"password":"'$(echo -n "NewTest123!" | base64)'"}}' + "${KUBECTL}" create secret generic example-pw --from-literal password="NewTest123!" --dry-run=client -o yaml | "${KUBECTL}" apply -f - # Force reconcile by adding annotation - "${KUBECTL}" annotate -f ${projectdir}/examples/${API_TYPE}/mssql/user.yaml reconcile=now + "${KUBECTL}" annotate -f "${EXAMPLES}/mssql/user.yaml" reconcile=now # Wait a bit for password update sleep 10 @@ -81,10 +81,10 @@ test_update_mssql_user_password() { test_create_mssql_grant() { echo_step "test creating MSSQL Grant resource" - "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mssql/grant.yaml + "${KUBECTL}" apply -f "${EXAMPLES}/mssql/grant.yaml" echo_step "Waiting for MSSQL Grant to be ready" - "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/mssql/grant.yaml + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${EXAMPLES}/mssql/grant.yaml" echo_step_completed } @@ -95,18 +95,18 @@ test_create_mssql_shared_login_users() { "${KUBECTL}" create secret generic shared-login-pw \ --from-literal password="Shared123!" --dry-run=client -o yaml | "${KUBECTL}" apply -f - - "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/mssql/user-shared-login.yaml + "${KUBECTL}" apply -f "${EXAMPLES}/mssql/user-shared-login.yaml" echo_step "Waiting for db1/db2 to be ready" "${KUBECTL}" wait --timeout 2m --for condition=Ready \ - database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/db1 \ - database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/db2 + "database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/db1" \ + "database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/db2" echo_step "Waiting for both shared-login Users to be ready" # Before the fix the second User is stuck with "server principal already exists". "${KUBECTL}" wait --timeout 2m --for condition=Ready \ - user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/shared-login-user-db1 \ - user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/shared-login-user-db2 + "user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/shared-login-user-db1" \ + "user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/shared-login-user-db2" echo_step_completed # DROP LOGIN guard: enable deletion (examples orphan) and delete sequentially - @@ -119,10 +119,10 @@ test_create_mssql_shared_login_users() { enable_delete='{"spec":{"deletionPolicy":"Delete"}}' fi for u in shared-login-user-db1 shared-login-user-db2; do - "${KUBECTL}" patch user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/$u \ + "${KUBECTL}" patch "user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/$u" \ --type merge -p "${enable_delete}" - "${KUBECTL}" delete user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/$u - "${KUBECTL}" wait --for=delete user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/$u --timeout=90s + "${KUBECTL}" delete "user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/$u" + "${KUBECTL}" wait --for=delete "user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/$u" --timeout=90s done echo_step_completed } @@ -137,20 +137,20 @@ test_mssql_all() { cleanup_mssql_test_resources() { echo_step "cleaning up MSSQL test resources" - "${KUBECTL}" delete -f ${projectdir}/examples/${API_TYPE}/mssql/grant.yaml --ignore-not-found=true - "${KUBECTL}" wait --for=delete grant.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/example-grant --timeout=60s + "${KUBECTL}" delete -f "${EXAMPLES}/mssql/grant.yaml" --ignore-not-found=true + "${KUBECTL}" wait --for=delete "grant.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/example-grant" --timeout=60s - "${KUBECTL}" delete -f ${projectdir}/examples/${API_TYPE}/mssql/user.yaml --ignore-not-found=true - "${KUBECTL}" wait --for=delete user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/example-user --timeout=60s + "${KUBECTL}" delete -f "${EXAMPLES}/mssql/user.yaml" --ignore-not-found=true + "${KUBECTL}" wait --for=delete "user.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/example-user" --timeout=60s # Users already deleted by the test; this removes db1/db2 and the secret. - "${KUBECTL}" delete -f ${projectdir}/examples/${API_TYPE}/mssql/user-shared-login.yaml --ignore-not-found=true - "${KUBECTL}" wait --for=delete database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/db1 --timeout=60s - "${KUBECTL}" wait --for=delete database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/db2 --timeout=60s + "${KUBECTL}" delete -f "${EXAMPLES}/mssql/user-shared-login.yaml" --ignore-not-found=true + "${KUBECTL}" wait --for=delete "database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/db1" --timeout=60s + "${KUBECTL}" wait --for=delete "database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/db2" --timeout=60s "${KUBECTL}" delete secret shared-login-pw --ignore-not-found=true - "${KUBECTL}" delete -f ${projectdir}/examples/${API_TYPE}/mssql/database.yaml --ignore-not-found=true - "${KUBECTL}" wait --for=delete database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/example-db --timeout=60s + "${KUBECTL}" delete -f "${EXAMPLES}/mssql/database.yaml" --ignore-not-found=true + "${KUBECTL}" wait --for=delete "database.mssql.sql.${APIGROUP_SUFFIX}crossplane.io/example-db" --timeout=60s echo_step "deleting example password secret" "${KUBECTL}" delete secret example-pw --ignore-not-found=true diff --git a/cluster/local/postgresdb_functions.sh b/cluster/local/postgresdb_functions.sh index 7c0182c9..fe24cb70 100644 --- a/cluster/local/postgresdb_functions.sh +++ b/cluster/local/postgresdb_functions.sh @@ -1,5 +1,11 @@ #!/usr/bin/env bash -set -e +# Sourced by integration_tests.sh, which defines KUBECTL, scriptdir, EXAMPLES, APIGROUP_SUFFIX and the echo_* helpers. +# shellcheck disable=SC2154 + +# Runs SQL as postgres inside the PostgreSQL pod (local socket, trust auth): pg_query +pg_query() { + "${KUBECTL}" exec postgresdb-postgresql-0 -- psql -U postgres -d "$1" -wtAc "$2" +} setup_postgresdb_no_tls() { echo_step "Installing PostgresDB into default namespace" @@ -11,16 +17,13 @@ setup_postgresdb_no_tls() { --from-literal endpoint="postgresdb-postgresql.default.svc.cluster.local" \ --from-literal port="5432" - scriptdir=$(dirname "$0") + # shellcheck disable=SC2016 POSTGRES_VERSION="${POSTGRES_VERSION:-18}" envsubst '${POSTGRES_VERSION}' < "${scriptdir}/postgres.server.yaml" | "${KUBECTL}" apply -f - echo_step "Waiting for PostgreSQL to be ready" "${KUBECTL}" rollout status statefulset/postgresdb-postgresql --timeout=120s - "${KUBECTL}" port-forward --namespace default svc/postgresdb-postgresql 5432:5432 > >(grep -v "Handling connection for") 2>&1 & - PORT_FORWARD_PID=$! - - while ! PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -wtAc "SELECT 1;"; do + until pg_query postgres "SELECT 1;" > /dev/null 2>&1; do echo "Waiting for PostgresDB to be ready..." sleep 2 done @@ -57,12 +60,8 @@ create_grantable_objects() { CREATE FOREIGN DATA WRAPPER test_foreign_data_wrapper; CREATE SERVER test_foreign_server FOREIGN DATA WRAPPER test_foreign_data_wrapper; " - create_objects=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -d "$TARGET_DB" -wtAc "$request") - if [ $? -eq 0 ]; then - echo_info "PostgresDB objects created in schema public" - else - echo_error "ERROR: could not create grantable objects: $create_objects" - fi + pg_query "$TARGET_DB" "$request" > /dev/null + echo_info "PostgresDB objects created in schema public" } delete_grantable_objects() { @@ -80,38 +79,34 @@ delete_grantable_objects() { DROP SEQUENCE \"$TARGET_SCHEMA\".test_sequence_2; DROP TABLE \"$TARGET_SCHEMA\".test_table; " - drop_objects=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -d "$TARGET_DB" -wtAc "$request") - if [ $? -eq 0 ]; then - echo_info "PostgresDB objects dropped from schema public" - else - echo_error "ERROR: could not delete grantable objects: $drop_objects" - fi + pg_query "$TARGET_DB" "$request" > /dev/null + echo_info "PostgresDB objects dropped from schema public" } setup_postgresdb_tests(){ # install provider resources echo_step "creating PostgresDB Database resource" # create DB - "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/postgresql/database.yaml + "${KUBECTL}" apply -f "${EXAMPLES}/postgresql/database.yaml" echo_step "creating PostgresDB Role resource" # create grant - "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/postgresql/role.yaml + "${KUBECTL}" apply -f "${EXAMPLES}/postgresql/role.yaml" echo_step "creating PostgresDB Schema resources" # create grant - "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/postgresql/schema.yaml + "${KUBECTL}" apply -f "${EXAMPLES}/postgresql/schema.yaml" echo_step "check if Role is ready" - "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/postgresql/role.yaml > /dev/null + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${EXAMPLES}/postgresql/role.yaml" > /dev/null echo_step_completed echo_step "check if database is ready" - "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/postgresql/database.yaml > /dev/null + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${EXAMPLES}/postgresql/database.yaml" > /dev/null echo_step_completed echo_step "check if schema is ready" - "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/postgresql/schema.yaml + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${EXAMPLES}/postgresql/schema.yaml" echo_step_completed echo_step "create grantable objects" @@ -120,10 +115,10 @@ setup_postgresdb_tests(){ echo_step "creating PostgresDB Grant resource" # create grant - "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/postgresql/grant.yaml + "${KUBECTL}" apply -f "${EXAMPLES}/postgresql/grant.yaml" echo_step "check if grant is ready" - "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/postgresql/grant.yaml + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${EXAMPLES}/postgresql/grant.yaml" echo_step_completed } @@ -131,7 +126,7 @@ check_database_owner_ref() { echo_step "check if database created with ownerSelector has correct owner" local owner - owner=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -d postgres -wtAc \ + owner=$(pg_query postgres \ "SELECT pg_catalog.pg_get_userbyid(d.datdba) FROM pg_catalog.pg_database d WHERE d.datname = 'db-owner-ref';") owner=$(echo "${owner}" | xargs) @@ -148,21 +143,8 @@ check_all_roles_privileges() { # check if granting mechanism is working properly echo_step "check if grant mechanism is working" - TARGET_DB='db1' - OWNER_ROLE='ownerrole' - USER_ROLE='example-role' - - # Define roles and their expected privileges - roles="$OWNER_ROLE $USER_ROLE" - privileges="CONNECT|CREATE|TEMP ||" - - # Iterate over roles and expected privileges - role_index=1 - for role in $roles; do - expected_privileges=$(echo "$privileges" | cut -d ' ' -f $role_index) - check_role_privileges "$role" "$expected_privileges" "${postgres_root_pw}" "$TARGET_DB" - role_index=$((role_index + 1)) - done + check_role_privileges ownerrole 'CONNECT|CREATE|TEMP' db1 + check_role_privileges example-role '||' db1 echo_step_completed } @@ -170,11 +152,11 @@ check_all_roles_privileges() { check_role_privileges() { local role=$1 local expected_privileges=$2 - local target_db=$4 + local target_db=$3 echo -n "Privileges for role: $role (expected: $expected_privileges)" - result=$(PGPASSWORD="$3" psql -h localhost -p 5432 -U postgres -d postgres -wtAc" SELECT CASE WHEN has_database_privilege('$role', '$target_db', 'CONNECT') THEN 'CONNECT' ELSE NULL END, CASE WHEN has_database_privilege('$role', '$target_db', 'CREATE') THEN 'CREATE' ELSE NULL END, CASE WHEN has_database_privilege('$role', '$target_db', 'TEMP') THEN 'TEMP' ELSE NULL END " | tr '\n' ',' | sed 's/,$//') + result=$(pg_query postgres "SELECT CASE WHEN has_database_privilege('$role', '$target_db', 'CONNECT') THEN 'CONNECT' ELSE NULL END, CASE WHEN has_database_privilege('$role', '$target_db', 'CREATE') THEN 'CREATE' ELSE NULL END, CASE WHEN has_database_privilege('$role', '$target_db', 'TEMP') THEN 'TEMP' ELSE NULL END " | tr '\n' ',' | sed 's/,$//') if [ "$result" = "$expected_privileges" ]; then echo " condition met" @@ -189,24 +171,8 @@ check_all_schema_privileges() { # check if schema privileges are set properly echo_step "check if schema privileges are set properly" - OWNER_ROLE='ownerrole' - USER_ROLE='no-grants-role' - - # Define roles and their expected privileges - roles="$OWNER_ROLE $USER_ROLE" - dbs="db1 example" - schemas="public my-schema" - privileges="USAGE|f,CREATE|f USAGE|t,CREATE|t" - - # Iterate over roles and expected privileges - role_index=1 - for role in $roles; do - expected_privileges=$(echo "$privileges" | cut -d ' ' -f $role_index) - target_db=$(echo "$dbs" | cut -d ' ' -f $role_index) - target_schema=$(echo "$schemas" | cut -d ' ' -f $role_index) - check_schema_privileges "$role" "$expected_privileges" "${postgres_root_pw}" "$target_db" "$target_schema" - role_index=$((role_index + 1)) - done + check_schema_privileges ownerrole 'USAGE|f,CREATE|f' db1 public + check_schema_privileges no-grants-role 'USAGE|t,CREATE|t' example my-schema echo_step_completed } @@ -219,7 +185,7 @@ check_privileges(){ local request=$5 echo -n "Privileges on $object for role: $role (expected: $expected)" - response=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -d "$target_db" -wtAc "$request") + response=$(pg_query "$target_db" "$request") response=$(echo "$response" | xargs | tr ' ' ',') if [[ "$response" == "$expected" ]]; then @@ -234,12 +200,12 @@ check_privileges(){ check_schema_privileges(){ local role=$1 local expected_privileges=$2 - local target_db=$4 - local target_schema=$5 + local target_db=$3 + local target_schema=$4 request="select acl.privilege_type, acl.is_grantable from pg_namespace n, aclexplode(n.nspacl) acl INNER JOIN pg_roles s ON acl.grantee = s.oid where n.nspname = '$target_schema' and s.rolname='$role'" - check_privileges $target_db "schema $target_db.$target_schema" $role $expected_privileges "$request" + check_privileges "$target_db" "schema $target_db.$target_schema" "$role" "$expected_privileges" "$request" } check_table_privileges(){ @@ -251,7 +217,7 @@ check_table_privileges(){ request="select privilege_type, is_grantable from information_schema.role_table_grants where grantee = '$role' and table_schema = '$schema' and table_name='$table' order by privilege_type asc" - check_privileges $target_db "table $schema.$table" $role $expected_privileges "$request" + check_privileges "$target_db" "table $schema.$table" "$role" "$expected_privileges" "$request" } check_sequence_privileges(){ @@ -260,13 +226,10 @@ check_sequence_privileges(){ role='no-grants-role' expected_privileges='SELECT|f,UPDATE|f,USAGE|f' - sequence="test_sequence_1" - request="select acl.privilege_type, acl.is_grantable from pg_class c inner join pg_namespace n on c.relnamespace = n.oid, aclexplode(c.relacl) as acl inner join pg_roles s on acl.grantee = s.oid where c.relkind = 'S' and n.nspname = '$schema' and s.rolname='$role' and c.relname = '$sequence'" - check_privileges $target_db "sequence $schema.$sequence" $role $expected_privileges "$request" - - sequence="test_sequence_2" - request="select acl.privilege_type, acl.is_grantable from pg_class c inner join pg_namespace n on c.relnamespace = n.oid, aclexplode(c.relacl) as acl inner join pg_roles s on acl.grantee = s.oid where c.relkind = 'S' and n.nspname = '$schema' and s.rolname='$role' and c.relname = '$sequence'" - check_privileges $target_db "sequence $schema.$sequence" $role $expected_privileges "$request" + for sequence in test_sequence_1 test_sequence_2; do + request="select acl.privilege_type, acl.is_grantable from pg_class c inner join pg_namespace n on c.relnamespace = n.oid, aclexplode(c.relacl) as acl inner join pg_roles s on acl.grantee = s.oid where c.relkind = 'S' and n.nspname = '$schema' and s.rolname='$role' and c.relname = '$sequence'" + check_privileges "$target_db" "sequence $schema.$sequence" "$role" "$expected_privileges" "$request" + done } check_routine_privileges(){ @@ -278,7 +241,7 @@ check_routine_privileges(){ request="select privilege_type, is_grantable from information_schema.role_routine_grants where grantee = '$role' and routine_schema = '$schema' and routine_name='$routine' order by privilege_type asc" - check_privileges $target_db "routine $schema.$routine" $role $expected_privileges "$request" + check_privileges "$target_db" "routine $schema.$routine" "$role" "$expected_privileges" "$request" } check_column_privileges(){ @@ -291,7 +254,7 @@ check_column_privileges(){ request="select privilege_type, is_grantable from information_schema.role_column_grants where grantee = '$role' and table_schema = '$schema' and table_name='$table' and column_name='$column' order by privilege_type asc" - check_privileges $target_db "column $column on table $schema.$table" $role $expected_privileges "$request" + check_privileges "$target_db" "column $column on table $schema.$table" "$role" "$expected_privileges" "$request" } check_foreign_data_wrapper_privileges(){ @@ -302,7 +265,7 @@ check_foreign_data_wrapper_privileges(){ request="select privilege_type, is_grantable from information_schema.role_usage_grants where grantee = '$role' and object_type = 'FOREIGN DATA WRAPPER' and object_name='$foreign_data_wrapper' order by privilege_type asc" - check_privileges $target_db "foreign data wrapper $foreign_data_wrapper" $role $expected_privileges "$request" + check_privileges "$target_db" "foreign data wrapper $foreign_data_wrapper" "$role" "$expected_privileges" "$request" } check_foreign_server_privileges(){ @@ -313,7 +276,7 @@ check_foreign_server_privileges(){ request="select privilege_type, is_grantable from information_schema.role_usage_grants where grantee = '$role' and object_type = 'FOREIGN SERVER' and object_name='$foreign_server' order by privilege_type asc" - check_privileges $target_db "foreign server $foreign_server" $role $expected_privileges "$request" + check_privileges "$target_db" "foreign server $foreign_server" "$role" "$expected_privileges" "$request" } check_all_privileges_table_grant(){ @@ -326,7 +289,7 @@ check_all_privileges_table_grant(){ table="test_table" role='example-role' - pg_major=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -wtAc \ + pg_major=$(pg_query postgres \ "SELECT current_setting('server_version_num')::int / 10000;" | xargs) if [ "${pg_major}" -ge 17 ]; then @@ -337,14 +300,13 @@ check_all_privileges_table_grant(){ request="select acl.privilege_type, acl.is_grantable from pg_class c inner join pg_namespace n on c.relnamespace = n.oid, aclexplode(c.relacl) as acl inner join pg_roles s on acl.grantee = s.oid where c.relkind = 'r' and n.nspname = '$schema' and s.rolname='$role' and c.relname = '$table' order by acl.privilege_type asc" - check_privileges $target_db "ALL PRIVILEGES on table $schema.$table" $role $expected_privileges "$request" + check_privileges "$target_db" "ALL PRIVILEGES on table $schema.$table" "$role" "$expected_privileges" "$request" } setup_observe_only_database(){ echo_step "create pre-existing database for observe only" - local datname - datname="$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -wtAc "CREATE DATABASE \"db-observe\";")" + pg_query postgres "CREATE DATABASE \"db-observe\";" > /dev/null echo_step_completed } @@ -353,10 +315,10 @@ check_observe_only_database(){ echo_step "check if observe only database is preserved after deletion" # Delete the database kubernetes object, it should not delete the database - "${KUBECTL}" delete database.postgresql.sql.${APIGROUP_SUFFIX}crossplane.io db-observe + "${KUBECTL}" delete "database.postgresql.sql.${APIGROUP_SUFFIX}crossplane.io" db-observe local datname - datname="$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -wtAc "SELECT datname FROM pg_database WHERE datname = 'db-observe';")" + datname="$(pg_query postgres "SELECT datname FROM pg_database WHERE datname = 'db-observe';")" if [[ "$datname" == "db-observe" ]]; then echo "Database db-observe is still present" @@ -367,7 +329,7 @@ check_observe_only_database(){ fi # Clean up - PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -wtAc "DROP DATABASE \"db-observe\";" + pg_query postgres "DROP DATABASE \"db-observe\";" echo_step_completed } @@ -380,7 +342,7 @@ check_wildcard_privileges(){ schema="public" role='all-objects-role' - missing=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -d "$target_db" -wtAc \ + missing=$(pg_query "$target_db" \ "select count(*) from pg_class c join pg_namespace n on c.relnamespace = n.oid where c.relkind in ('r','p','v','m','f') and n.nspname = '$schema' and not has_table_privilege('$role', c.oid, 'SELECT');" | xargs) @@ -392,7 +354,7 @@ check_wildcard_privileges(){ fi # Same for routines, which take EXECUTE rather than SELECT. - missing=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -d "$target_db" -wtAc \ + missing=$(pg_query "$target_db" \ "select count(*) from pg_proc p join pg_namespace n on p.pronamespace = n.oid where n.nspname = '$schema' and not has_function_privilege('$role', p.oid, 'EXECUTE');" | xargs) @@ -425,17 +387,14 @@ delete_postgresdb_resources(){ # uninstall echo_step "uninstalling ${PROJECT_NAME}" - "${KUBECTL}" delete -f "${projectdir}/examples/${API_TYPE}/postgresql/grant.yaml" - "${KUBECTL}" delete --ignore-not-found=true -f "${projectdir}/examples/${API_TYPE}/postgresql/database.yaml" - "${KUBECTL}" delete -f "${projectdir}/examples/${API_TYPE}/postgresql/role.yaml" - "${KUBECTL}" delete -f "${projectdir}/examples/${API_TYPE}/postgresql/schema.yaml" - echo "${PROVIDER_CONFIG_POSTGRES_YAML}" | "${KUBECTL}" delete -f - + "${KUBECTL}" delete -f "${EXAMPLES}/postgresql/grant.yaml" + "${KUBECTL}" delete --ignore-not-found=true -f "${EXAMPLES}/postgresql/database.yaml" + "${KUBECTL}" delete -f "${EXAMPLES}/postgresql/role.yaml" + "${KUBECTL}" delete -f "${EXAMPLES}/postgresql/schema.yaml" + "${KUBECTL}" delete -f "${scriptdir}/postgres.providerconfig.${API_TYPE}.yaml" # ----------- cleaning postgres related resources - echo_step "kill port-forwarding" - kill $PORT_FORWARD_PID - echo_step "uninstalling secret and provider config for postgres" "${KUBECTL}" delete secret postgresdb-creds @@ -450,11 +409,11 @@ setup_extension_test() { # Apply extension resources echo_sub_step "Creating PostgreSQL extensions" - "${KUBECTL}" apply -f "${projectdir}/examples/${API_TYPE}/postgresql/extension.yaml" + "${KUBECTL}" apply -f "${EXAMPLES}/postgresql/extension.yaml" # Wait for extensions to be ready echo_sub_step "Waiting for extensions to be ready" - "${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${projectdir}/examples/${API_TYPE}/postgresql/extension.yaml" > /dev/null + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f "${EXAMPLES}/postgresql/extension.yaml" > /dev/null echo_step_completed } @@ -463,8 +422,8 @@ check_extension_test() { # Check that extensions are ready echo_sub_step "Checking extension status" - hstore_status=$("${KUBECTL}" get extension.postgresql.sql.${APIGROUP_SUFFIX}crossplane.io/hstore-extension-db -n default -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}') - ltree_status=$("${KUBECTL}" get extension.postgresql.sql.${APIGROUP_SUFFIX}crossplane.io/ltree-extension-db -n default -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}') + hstore_status=$("${KUBECTL}" get "extension.postgresql.sql.${APIGROUP_SUFFIX}crossplane.io/hstore-extension-db" -n default -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}') + ltree_status=$("${KUBECTL}" get "extension.postgresql.sql.${APIGROUP_SUFFIX}crossplane.io/ltree-extension-db" -n default -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}') if [[ "$hstore_status" == "True" ]] && [[ "$ltree_status" == "True" ]]; then echo_info "Extensions are Ready as expected" @@ -474,8 +433,8 @@ check_extension_test() { # Verify extensions are installed in the database echo_sub_step "Checking extensions in database" - hstore_installed=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -d example -wtAc "SELECT COUNT(*) FROM pg_extension WHERE extname = 'hstore';") - ltree_installed=$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -d example -wtAc "SELECT COUNT(*) FROM pg_extension WHERE extname = 'ltree';") + hstore_installed=$(pg_query example "SELECT COUNT(*) FROM pg_extension WHERE extname = 'hstore';") + ltree_installed=$(pg_query example "SELECT COUNT(*) FROM pg_extension WHERE extname = 'ltree';") if [[ "$hstore_installed" == "1" ]] && [[ "$ltree_installed" == "1" ]]; then echo_info "Extensions are installed in database as expected" @@ -488,7 +447,7 @@ check_extension_test() { delete_extension_test() { echo_step "Cleaning up PostgreSQL extensions" - "${KUBECTL}" delete --ignore-not-found=true -f "${projectdir}/examples/${API_TYPE}/postgresql/extension.yaml" + "${KUBECTL}" delete --ignore-not-found=true -f "${EXAMPLES}/postgresql/extension.yaml" echo_step_completed } From 17b04e8c2409863f90dc0c530ed9c1116c64ee8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Thu, 8 Oct 2026 23:36:18 +0200 Subject: [PATCH 5/6] test: generate MariaDB TLS certs in a temp dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The certs were written to the current directory and cleanup ran rm -f *.pem there, deleting any unrelated .pem file and leaving keys behind in the repo when a run was aborted. Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- .../yagni/entries/2026-10-08-a035745-ci.md | 18 +++++++++ cluster/local/integration_tests.sh | 39 +++++++++---------- 2 files changed, 37 insertions(+), 20 deletions(-) create mode 100644 .claude/yagni/entries/2026-10-08-a035745-ci.md diff --git a/.claude/yagni/entries/2026-10-08-a035745-ci.md b/.claude/yagni/entries/2026-10-08-a035745-ci.md new file mode 100644 index 00000000..1adad4c8 --- /dev/null +++ b/.claude/yagni/entries/2026-10-08-a035745-ci.md @@ -0,0 +1,18 @@ +--- +commit: a035745 +date: 2026-10-08 +branch: chore/e2e-engine-matrix +files: .github/workflows/ci.yml, Makefile, README.md, cluster/local/.shellcheckrc, cluster/local/integration_tests.sh, cluster/local/mssqldb_functions.sh, cluster/local/postgresdb_functions.sh +gross_deletions: 224 +net_deletions: 51 +deleted_files: +--- +# Removed: ci: run e2e tests per engine in a matrix and clean up test scripts +**Commit:** a035745 +**Branch:** chore/e2e-engine-matrix +**Files changed:** 7 +**Lines removed:** 224 (net 51) +## Restore +```bash +git apply .claude/yagni/entries/2026-10-08-a035745-ci.patch +``` diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index 673f7b92..6d2096dc 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -129,38 +129,37 @@ cleanup_provider() { } setup_tls_certs() { + certdir="$(mktemp -d)" echo_step "generating CA key and certificate" - openssl genrsa -out ca-key.pem 2048 - openssl req -new -x509 -key ca-key.pem -out ca-cert.pem -days 365 -subj "/CN=CA" + openssl genrsa -out "${certdir}/ca-key.pem" 2048 + openssl req -new -x509 -key "${certdir}/ca-key.pem" -out "${certdir}/ca-cert.pem" -days 365 -subj "/CN=CA" echo_step "generating server key and certificate" - openssl genrsa -out server-key.pem 2048 - openssl req -new -key server-key.pem -out server-req.pem -subj "/CN=mariadb.default.svc.cluster.local" - openssl x509 -req -in server-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365 + openssl genrsa -out "${certdir}/server-key.pem" 2048 + openssl req -new -key "${certdir}/server-key.pem" -out "${certdir}/server-req.pem" -subj "/CN=mariadb.default.svc.cluster.local" + openssl x509 -req -in "${certdir}/server-req.pem" -CA "${certdir}/ca-cert.pem" -CAkey "${certdir}/ca-key.pem" -CAcreateserial -out "${certdir}/server-cert.pem" -days 365 echo_step "generating client key and certificate" - openssl genrsa -out client-key.pem 2048 - openssl req -new -key client-key.pem -out client-req.pem -subj "/CN=client" - openssl x509 -req -in client-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365 + openssl genrsa -out "${certdir}/client-key.pem" 2048 + openssl req -new -key "${certdir}/client-key.pem" -out "${certdir}/client-req.pem" -subj "/CN=client" + openssl x509 -req -in "${certdir}/client-req.pem" -CA "${certdir}/ca-cert.pem" -CAkey "${certdir}/ca-key.pem" -CAcreateserial -out "${certdir}/client-cert.pem" -days 365 echo_step "creating secret for the TLS certificates and keys" "${KUBECTL}" create secret generic mariadb-server-tls \ - --from-file=ca-cert.pem \ - --from-file=server-cert.pem \ - --from-file=server-key.pem + --from-file="${certdir}/ca-cert.pem" \ + --from-file="${certdir}/server-cert.pem" \ + --from-file="${certdir}/server-key.pem" echo_step "creating secret for the client TLS certificates and keys" "${KUBECTL}" create secret generic mariadb-client-tls \ - --from-file=ca-cert.pem \ - --from-file=client-cert.pem \ - --from-file=client-key.pem + --from-file="${certdir}/ca-cert.pem" \ + --from-file="${certdir}/client-cert.pem" \ + --from-file="${certdir}/client-key.pem" } cleanup_tls_certs() { echo_step "cleaning up TLS certificate files and secrets" - for file in *.pem *.srl; do - rm -f "$file" - done + rm -rf "${certdir}" "${KUBECTL}" delete secret mariadb-server-tls "${KUBECTL}" delete secret mariadb-client-tls } @@ -201,9 +200,9 @@ setup_mariadb_tls() { --from-literal password="${MARIADB_TEST_PW}" \ --from-literal endpoint="mariadb.default.svc.cluster.local" \ --from-literal port="3306" \ - --from-file=ca-cert.pem \ - --from-file=client-cert.pem \ - --from-file=client-key.pem + --from-file="${certdir}/ca-cert.pem" \ + --from-file="${certdir}/client-cert.pem" \ + --from-file="${certdir}/client-key.pem" # Create init script ConfigMap "${KUBECTL}" create configmap mariadb-init-script --from-literal=init.sql=" From f60fd39c6a79e3fdc1eb584d654ebec7f412aecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Wed, 28 Oct 2026 09:32:37 +0100 Subject: [PATCH 6/6] fix: mssql server cleanup missing PVC delete 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> --- cluster/local/mssqldb_functions.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cluster/local/mssqldb_functions.sh b/cluster/local/mssqldb_functions.sh index 0fb0c50c..c663ce80 100644 --- a/cluster/local/mssqldb_functions.sh +++ b/cluster/local/mssqldb_functions.sh @@ -28,6 +28,8 @@ setup_mssql() { cleanup_mssql() { echo_step "cleaning up MSSQL server" "${KUBECTL}" delete -f "${scriptdir}/mssql.server.yaml" --ignore-not-found=true + # StatefulSet PVCs outlive the StatefulSet; a reused volume keeps the previous run's SA password. + "${KUBECTL}" delete pvc data-mssql-0 --ignore-not-found=true "${KUBECTL}" delete secret mssql-creds --ignore-not-found=true }