diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index d4e095ab..86bd536a 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -51,6 +51,7 @@ 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 # cleanup on exit if [ "$skipcleanup" != true ]; then @@ -74,6 +75,13 @@ if [ $? -ne 0 ]; then 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 + integration_tests_end() { echo_step "--- CLEAN-UP ---" cleanup_provider @@ -450,4 +458,8 @@ TLS=false API_TYPE="cluster" run_test integration_tests_mariadb TLS=false API_TYPE="cluster" run_test integration_tests_postgres TLS=false API_TYPE="namespaced" run_test integration_tests_postgres +# 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 + integration_tests_end diff --git a/cluster/local/mssql.providerconfig.cluster.yaml b/cluster/local/mssql.providerconfig.cluster.yaml new file mode 100644 index 00000000..0368dab9 --- /dev/null +++ b/cluster/local/mssql.providerconfig.cluster.yaml @@ -0,0 +1,10 @@ +apiVersion: mssql.sql.crossplane.io/v1alpha1 +kind: ProviderConfig +metadata: + name: default +spec: + credentials: + source: MSSQLConnectionSecret + connectionSecretRef: + namespace: default + name: mssql-creds diff --git a/cluster/local/mssql.providerconfig.namespaced.yaml b/cluster/local/mssql.providerconfig.namespaced.yaml new file mode 100644 index 00000000..b5e7ad60 --- /dev/null +++ b/cluster/local/mssql.providerconfig.namespaced.yaml @@ -0,0 +1,10 @@ +apiVersion: mssql.sql.m.crossplane.io/v1alpha1 +kind: ProviderConfig +metadata: + name: default + namespace: default +spec: + credentials: + source: MSSQLConnectionSecret + connectionSecretRef: + name: mssql-creds diff --git a/cluster/local/mssql.server.yaml b/cluster/local/mssql.server.yaml new file mode 100644 index 00000000..9168416b --- /dev/null +++ b/cluster/local/mssql.server.yaml @@ -0,0 +1,72 @@ +apiVersion: v1 +kind: Service +metadata: + name: mssql + namespace: default +spec: + ports: + - port: 1433 + targetPort: 1433 + selector: + app: mssql +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: mssql + namespace: default +spec: + serviceName: mssql + replicas: 1 + selector: + matchLabels: + app: mssql + template: + metadata: + labels: + app: mssql + spec: + containers: + - name: mssql + image: mcr.microsoft.com/mssql/server:2019-CU32-ubuntu-20.04 + env: + - name: SA_PASSWORD + valueFrom: + secretKeyRef: + name: mssql-creds + key: password + - name: ACCEPT_EULA + value: "Y" + - name: MSSQL_PID + value: "Developer" + ports: + - containerPort: 1433 + volumeMounts: + - name: data + mountPath: /var/opt/mssql + readinessProbe: + exec: + command: + - /bin/bash + - -c + - '/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -C -Q "SELECT 1"' + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + livenessProbe: + exec: + command: + - /bin/bash + - -c + - '/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -C -Q "SELECT 1"' + initialDelaySeconds: 60 + periodSeconds: 30 + timeoutSeconds: 5 + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 2Gi diff --git a/cluster/local/mssqldb_functions.sh b/cluster/local/mssqldb_functions.sh new file mode 100644 index 00000000..33b7a271 --- /dev/null +++ b/cluster/local/mssqldb_functions.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +set -e + +setup_mssql() { + echo_step "installing MSSQL Server" + + "${KUBECTL}" create secret generic mssql-creds \ + --from-literal username="sa" \ + --from-literal password="${MSSQL_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 + + "${KUBECTL}" apply -f ${scriptdir}/mssql.server.yaml + + echo_step "Waiting for MSSQL Server to be ready" + "${KUBECTL}" wait --for=create pod mssql-0 + "${KUBECTL}" wait --for=condition=ready pod -l app=mssql --timeout=300s + + # Wait a bit more for MSSQL to be fully ready for connections + sleep 30 +} + +cleanup_mssql() { + echo_step "cleaning up MSSQL server" + "${KUBECTL}" delete -f ${scriptdir}/mssql.server.yaml --ignore-not-found=true + "${KUBECTL}" delete secret mssql-creds --ignore-not-found=true +} + +setup_mssql_provider_config() { + echo_step "setting up MSSQL provider config" + "${KUBECTL}" apply -f "${scriptdir}/mssql.providerconfig.${API_TYPE}.yaml" +} + +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 +} + +test_create_mssql_database() { + echo_step "test creating MSSQL Database resource" + "${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 + + echo_step_completed +} + +test_create_mssql_user() { + echo_step "test creating MSSQL User resource (traditional)" + # 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 + + echo_step "Waiting for MSSQL User to be ready" + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/${API_TYPE}/mssql/user.yaml + + echo_step_completed +} + +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)'"}}' + + # Force reconcile by adding annotation + "${KUBECTL}" annotate -f ${projectdir}/examples/${API_TYPE}/mssql/user.yaml reconcile=now + + # Wait a bit for password update + sleep 10 + + echo_step_completed +} + +test_create_mssql_grant() { + echo_step "test creating MSSQL Grant resource" + "${KUBECTL}" apply -f ${projectdir}/examples/${API_TYPE}/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 + + echo_step_completed +} + +test_mssql_all() { + test_create_mssql_database + test_create_mssql_user + test_update_mssql_user_password + test_create_mssql_grant +} + +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 ${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 ${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 + + echo_step "deleting example password secret" + "${KUBECTL}" delete secret example-pw --ignore-not-found=true +} + +integration_tests_mssql() { + setup_mssql + setup_mssql_provider_config + + test_mssql_all + + cleanup_mssql_test_resources + cleanup_mssql_provider_config + cleanup_mssql +} diff --git a/examples/namespaced/mssql/database.yaml b/examples/namespaced/mssql/database.yaml index e8959c50..847fa210 100644 --- a/examples/namespaced/mssql/database.yaml +++ b/examples/namespaced/mssql/database.yaml @@ -3,4 +3,7 @@ kind: Database metadata: name: example-db namespace: default -spec: {} +spec: + providerConfigRef: + kind: ProviderConfig + name: default diff --git a/examples/namespaced/mssql/grant.yaml b/examples/namespaced/mssql/grant.yaml index b5978ba5..86f0ef65 100644 --- a/examples/namespaced/mssql/grant.yaml +++ b/examples/namespaced/mssql/grant.yaml @@ -4,6 +4,9 @@ metadata: name: example-grant namespace: default spec: + providerConfigRef: + kind: ProviderConfig + name: default forProvider: permissions: # CONNECT permission is added by default when user created. So, make sure diff --git a/examples/namespaced/mssql/user.yaml b/examples/namespaced/mssql/user.yaml index c7d83528..75fd9957 100644 --- a/examples/namespaced/mssql/user.yaml +++ b/examples/namespaced/mssql/user.yaml @@ -4,6 +4,9 @@ metadata: name: example-user namespace: default spec: + providerConfigRef: + kind: ProviderConfig + name: default forProvider: databaseRef: name: example-db