diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 0fb53c7b..40b69e11 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -63,23 +63,3 @@ jobs: make test-e2e \ ATLAS_TOKEN=${{ secrets.ATLAS_TOKEN }} \ KIND_CLUSTER=chart-testing - e2e-shell: - runs-on: ubuntu-latest - needs: [unit] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version-file: 'go.mod' - - name: Install Atlas CLI - uses: ariga/setup-atlas@master - - uses: azure/setup-kubectl@v4 - - name: Start minikube - uses: medyagh/setup-minikube@master - - name: Install Skaffold - run: | - curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/v2.3.1/skaffold-linux-amd64 && \ - sudo install skaffold /usr/local/bin/ - - name: Run integration tests - run: | - make docker-build integration-tests diff --git a/.github/workflows/push-chart.yaml b/.github/workflows/push-chart.yaml index 6cfafb9f..6659d2c4 100644 --- a/.github/workflows/push-chart.yaml +++ b/.github/workflows/push-chart.yaml @@ -26,37 +26,23 @@ jobs: name: Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: start minikube - id: minikube - uses: medyagh/setup-minikube@master - - uses: azure/setup-helm@v3 - - name: install atlas-operator + - uses: actions/checkout@v4 + - name: Create k8s Kind Cluster + uses: helm/kind-action@v1 + - name: Setup Helm + uses: azure/setup-helm@v4 + - name: Run e2e tests with Operator run: | - helm install atlas-operator charts/atlas-operator --wait \ - --set image.pullPolicy=Always - - name: apply test resources - run: | - kubectl apply -k config/integration - - name: wait for test resources - run: | - if ! kubectl wait --for=condition=ready --timeout=120s atlasschemas --all; then - kubectl describe atlasschemas - kubectl describe pods -l atlasgo.io/engine=postgres - kubectl describe pods -l atlasgo.io/engine=mysql - kubectl describe deployments - exit 1 - fi + make test-e2e \ + ATLAS_TOKEN=${{ secrets.ATLAS_TOKEN }} \ + KIND_CLUSTER=chart-testing \ + TEST_RUN='(schema|migration)-mysql' + env: + HELM_TEST: "true" - name: test env vars run: | - kubectl apply -k config/integration/env - helm upgrade atlas-operator charts/atlas-operator -f ./config/integration/env/values.yaml --wait - # Find the operator pod - OPERATOR=$(kubectl get pods -o jsonpath='{.items[0].metadata.name}') - # Extract the env from the operator pod - kubectl exec $OPERATOR -- env | grep NORMAL_ENV - kubectl exec $OPERATOR -- env | grep CONFIGMAP_REF_ENV - kubectl exec $OPERATOR -- env | grep SECRET_REF_ENV + helm template atlas-operator charts/atlas-operator \ + --set-json=extraEnvs='[{"name":"NORMAL_ENV","value":"value"}]' | grep NORMAL_ENV helm-push: name: Push to ghcr.io needs: [helm-test] @@ -66,8 +52,8 @@ jobs: run: working-directory: charts/ steps: - - uses: actions/checkout@v3 - - uses: azure/setup-helm@v3 + - uses: actions/checkout@v4 + - uses: azure/setup-helm@v4 - name: get version id: version run: | diff --git a/Makefile b/Makefile index 5f246d29..383fea67 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ test: manifests generate fmt vet envtest ## Run tests. # - CERT_MANAGER_INSTALL_SKIP=true .PHONY: test-e2e test-e2e: manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind. - go test ./test/e2e/ -v -run=^TestOperator/${TEST_RUN} + go test ./test/e2e/ -v -run="^TestOperator/${TEST_RUN}" .PHONY: kind-image kind-image: diff --git a/config/integration/databases/mysql.yaml b/config/integration/databases/mysql.yaml deleted file mode 100644 index 7695fc6d..00000000 --- a/config/integration/databases/mysql.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2023 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: mysql -spec: - selector: - matchLabels: - app: mysql - replicas: 1 - template: - metadata: - labels: - app: mysql - spec: - containers: - - name: mysql - image: mysql:latest - env: - - name: MYSQL_ROOT_PASSWORD - value: pass - - name: MYSQL_DATABASE - value: myapp - ports: - - containerPort: 3306 - name: mysql - readinessProbe: - initialDelaySeconds: 5 - periodSeconds: 2 - timeoutSeconds: 1 - exec: - command: [ "mysql", "-ppass", "-h", "127.0.0.1", "-e", "SELECT 1" ] ---- -apiVersion: v1 -kind: Service -metadata: - name: mysql -spec: - selector: - app: mysql - ports: - - name: mysql - port: 3306 - targetPort: mysql - type: ClusterIP ---- -apiVersion: v1 -kind: Secret -metadata: - name: mysql-credentials -type: Opaque -stringData: - url: "mysql://root:pass@mysql.default:3306/myapp" diff --git a/config/integration/databases/postgres.yaml b/config/integration/databases/postgres.yaml deleted file mode 100644 index d85a0b21..00000000 --- a/config/integration/databases/postgres.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2023 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: postgres -spec: - selector: - matchLabels: - app: postgres - replicas: 1 - template: - metadata: - labels: - app: postgres - spec: - securityContext: - runAsNonRoot: true - runAsUser: 999 - containers: - - name: postgres - image: postgres:15.4 - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - all - env: - - name: POSTGRES_PASSWORD - value: pass - - name: POSTGRES_USER - value: root - ports: - - containerPort: 5432 - name: postgres - readinessProbe: - initialDelaySeconds: 5 - periodSeconds: 2 - timeoutSeconds: 1 - exec: - command: [ "pg_isready", "-U", "postgres" ] ---- -apiVersion: v1 -kind: Service -metadata: - name: postgres -spec: - selector: - app: postgres - ports: - - name: postgres - port: 5432 - targetPort: postgres - type: ClusterIP ---- -apiVersion: v1 -kind: Secret -metadata: - name: postgres-credentials -type: Opaque -stringData: - url: "postgres://root:pass@postgres.default:5432/postgres?sslmode=disable" - password: pass diff --git a/config/integration/env/configmap.yaml b/config/integration/env/configmap.yaml deleted file mode 100644 index 00649dab..00000000 --- a/config/integration/env/configmap.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2024 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -kind: ConfigMap -apiVersion: v1 -metadata: - name: "operator-env-configmap" -data: - CONFIGMAP_REF_ENV: "value" \ No newline at end of file diff --git a/config/integration/env/kustomization.yaml b/config/integration/env/kustomization.yaml deleted file mode 100644 index c80d4836..00000000 --- a/config/integration/env/kustomization.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2023 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -## Append samples you want in your CSV to this file as resources ## -resources: - - configmap.yaml - - secret.yaml -#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/integration/env/secret.yaml b/config/integration/env/secret.yaml deleted file mode 100644 index 667dc73d..00000000 --- a/config/integration/env/secret.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2024 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: v1 -kind: Secret -metadata: - name: "operator-env-secret" -type: Opaque -data: - SECRET_REF_ENV: "dmFsdWU=" \ No newline at end of file diff --git a/config/integration/env/values.yaml b/config/integration/env/values.yaml deleted file mode 100644 index dbab8f2c..00000000 --- a/config/integration/env/values.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2024 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -extraEnvs: - - name: NORMAL_ENV - value: "value" - - name: SECRET_REF_ENV - valueFrom: - secretKeyRef: - key: SECRET_REF_ENV - name: operator-env-secret - - name: CONFIGMAP_REF_ENV - valueFrom: - configMapKeyRef: - key: CONFIGMAP_REF_ENV - name: operator-env-configmap \ No newline at end of file diff --git a/config/integration/kustomization.yaml b/config/integration/kustomization.yaml deleted file mode 100644 index 4c61388f..00000000 --- a/config/integration/kustomization.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2023 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -## Append samples you want in your CSV to this file as resources ## -resources: - - databases/mysql.yaml - - databases/postgres.yaml - - schema/mysql_schema.yaml - - schema/postgres_schema.yaml - - schema/configmap.yaml -#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/integration/migration/mysql-migrations/20230316085611.sql b/config/integration/migration/mysql-migrations/20230316085611.sql deleted file mode 100644 index 2cca9dfc..00000000 --- a/config/integration/migration/mysql-migrations/20230316085611.sql +++ /dev/null @@ -1,7 +0,0 @@ --- Create "users" table -CREATE TABLE `users` ( - `id` int NOT NULL, - `user_name` varchar(255) NOT NULL, - `email` varchar(255) NOT NULL, - PRIMARY KEY (`id`) -) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci; diff --git a/config/integration/migration/mysql-migrations/20230316090502.sql b/config/integration/migration/mysql-migrations/20230316090502.sql deleted file mode 100644 index 6163eb22..00000000 --- a/config/integration/migration/mysql-migrations/20230316090502.sql +++ /dev/null @@ -1,10 +0,0 @@ --- Create "posts" table -CREATE TABLE `posts` ( - `id` int NOT NULL, - `user_id` int NOT NULL, - `title` varchar(255) NOT NULL, - `body` text NOT NULL, - PRIMARY KEY (`id`), - INDEX `user_id` (`user_id`), - CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE -) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci; diff --git a/config/integration/migration/mysql-migrations/atlas.sum b/config/integration/migration/mysql-migrations/atlas.sum deleted file mode 100644 index a69ed610..00000000 --- a/config/integration/migration/mysql-migrations/atlas.sum +++ /dev/null @@ -1,3 +0,0 @@ -h1:XBXbh+rzLis8gknjlIqnxXLBkOZ+sN2v2p7KjyVFYYM= -20230316085611.sql h1:br6W6LPEnnsejlz/7hRm9zthwStCzjN2vZkqVPxlmvo= -20230316090502.sql h1:GfeRjkSeoCt3JVRtLQNa/r50lRfpAPXS7AqTU2ZNFgY= diff --git a/config/integration/migration/mysql_migrate_down.yaml b/config/integration/migration/mysql_migrate_down.yaml deleted file mode 100644 index 8c17709d..00000000 --- a/config/integration/migration/mysql_migrate_down.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2024 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: db.atlasgo.io/v1alpha1 -kind: AtlasMigration -spec: - protectedFlows: - migrateDown: - allow: true - autoApprove: true diff --git a/config/integration/migration/mysql_migration.yaml b/config/integration/migration/mysql_migration.yaml deleted file mode 100644 index 839703da..00000000 --- a/config/integration/migration/mysql_migration.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2023 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: db.atlasgo.io/v1alpha1 -kind: AtlasMigration -metadata: - labels: - app.kubernetes.io/name: atlasmigration - app.kubernetes.io/instance: atlasmigration-sample - app.kubernetes.io/part-of: atlas-operator - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: atlas-operator - name: atlasmigration-sample -spec: - urlFrom: - secretKeyRef: - key: url - name: mysql-credentials - dir: - configMapRef: - name: "migration-dir" \ No newline at end of file diff --git a/config/integration/schema/configmap.yaml b/config/integration/schema/configmap.yaml deleted file mode 100644 index 8e3cbc4d..00000000 --- a/config/integration/schema/configmap.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2023 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -kind: ConfigMap -apiVersion: v1 -metadata: - name: mysql-schema -data: - schema.sql: | - create table users ( - id int not null auto_increment, - name varchar(255) not null, - email varchar(255) unique not null, - short_bio varchar(255) not null, - primary key (id) - ); diff --git a/config/integration/schema/mysql/schema.sql b/config/integration/schema/mysql/schema.sql deleted file mode 100644 index db10dae0..00000000 --- a/config/integration/schema/mysql/schema.sql +++ /dev/null @@ -1,8 +0,0 @@ -create table users ( - id int not null auto_increment, - name varchar(255) not null, - email varchar(255) unique not null, - short_bio varchar(255) not null, - phone varchar(255) not null, - primary key (id) -); diff --git a/config/integration/schema/mysql_schema.yaml b/config/integration/schema/mysql_schema.yaml deleted file mode 100644 index eb314d94..00000000 --- a/config/integration/schema/mysql_schema.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2023 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: db.atlasgo.io/v1alpha1 -kind: AtlasSchema -metadata: - labels: - app.kubernetes.io/name: atlasschema - app.kubernetes.io/instance: atlasschema-sample - app.kubernetes.io/part-of: atlas-operator - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: atlas-operator - name: atlasschema-mysql -spec: - urlFrom: - secretKeyRef: - key: url - name: mysql-credentials - policy: - lint: - destructive: - error: true - diff: - skip: - drop_column: true - schema: - configMapKeyRef: - key: schema.sql - name: mysql-schema - exclude: - - ignore_me diff --git a/config/integration/schema/postgres_schema.yaml b/config/integration/schema/postgres_schema.yaml deleted file mode 100644 index 5e979b3b..00000000 --- a/config/integration/schema/postgres_schema.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2023 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -apiVersion: db.atlasgo.io/v1alpha1 -kind: AtlasSchema -metadata: - labels: - app.kubernetes.io/name: atlasschema - app.kubernetes.io/instance: atlasschema-sample - app.kubernetes.io/part-of: atlas-operator - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: atlas-operator - name: atlasschema-postgres -spec: - credentials: - scheme: postgres - host: postgres.default - user: root - passwordFrom: - secretKeyRef: - key: password - name: postgres-credentials - database: postgres - port: 5432 - parameters: - sslmode: disable - schema: - sql: | - create table users2 ( - id int not null, - primary key (id) - ); diff --git a/scripts/integration-tests.sh b/scripts/integration-tests.sh deleted file mode 100755 index 4492060e..00000000 --- a/scripts/integration-tests.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash -e -# Copyright 2024 The Atlas Operator Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -mysql_exec() { - if [ -z "$1" ]; then - echo "Usage: mysql_exec " - exit 1 - fi - _mysql_pod=$(kubectl get pods -l app=mysql -o jsonpath='{.items[0].metadata.name}') - kubectl exec $_mysql_pod -- \ - mysql -uroot -h 127.0.0.1 -ppass -e "$1" -} - -mysql_reset() { - if [ -z "$1" ]; then - echo "Usage: mysql_reset " - exit 1 - fi - echo "" - echo "---------------------------------" - echo "$1" - echo "---------------------------------" - echo "" - # Delete the pods to reset the database. - kubectl delete pods -l app=mysql 1>/dev/null - # Wait for the pods to be ready. - kubectl wait --for condition=ready pods -l app=mysql --timeout=60s 1>/dev/null -} - -k8s_dircfg() { - if [ -z "$1" ] || [ -z "$2" ]; then - echo "Usage: k8s_dircfg " - exit 1 - fi - _ns="${3:-default}" - kubectl create configmap $2 --from-file=$1 \ - --dry-run=client -o yaml | kubectl apply -n $_ns -f - -} - -# Reset the environment to ensure a clean state. -kubectl set env -n atlas-operator-system deployment/atlas-operator-controller-manager \ - PREWARM_DEVDB=true - -cd ./config/integration - -# Bring up the database resources -kubectl apply -f ./databases - -mysql_reset "Test prewarm_devdb flag" -# SET PREWARM_DEVDB to false -kubectl set env -n atlas-operator-system deployment/atlas-operator-controller-manager \ - PREWARM_DEVDB=false -# Apply the desired schema and wait for it to be ready. -kubectl apply -f ./schema -kubectl wait --for=condition=ready --timeout=120s atlasschemas --all -echo "" -echo "Expect the devdb deployment is scaled to 0" -kubectl get deployment atlasschema-mysql-atlas-dev-db \ - -o=jsonpath='{.spec.replicas}' | grep -q '0' -kubectl delete -f ./schema - -cd ./migration - -mysql_reset "Test the atlas migration controller" -k8s_dircfg ./mysql-migrations migration-dir -kubectl apply -f ./mysql_migration.yaml -kubectl wait --for=condition=ready --timeout=120s atlasmigrations --all -echo "" -echo "Expected the atlas_schema_revisions table to be present" -mysql_exec "describe myapp.atlas_schema_revisions" -echo "Add a new column to the table" -EDITOR="echo 'ALTER TABLE posts ADD COLUMN created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP;' >" \ - atlas migrate new --dir=file://./mysql-migrations --edit -k8s_dircfg ./mysql-migrations migration-dir -kubectl wait --for=condition=ready --timeout=120s atlasmigrations --all -echo "" -echo "Expected the new column to be present" -mysql_exec "SHOW COLUMNS FROM myapp.posts LIKE 'created_at';" | grep -q 'created_at' -echo "" - -mysql_reset "Test migrate down" -k8s_dircfg ./mysql-migrations migration-dir -kubectl delete -f ./mysql_migration.yaml -kubectl apply -f ./mysql_migration.yaml -kubectl wait --timeout=120s --for=condition=ready \ - AtlasMigration/atlasmigration-sample -if ! mysql_exec "SHOW COLUMNS FROM myapp.posts LIKE 'created_at';" | grep -q 'created_at'; then - echo "The column created_at should be present at this point" - exit 1 -fi -atlas migrate rm --dir=file://./mysql-migrations -echo "Removed the last migration, which have the column created_at" -k8s_dircfg ./mysql-migrations migration-dir -# Expect migration is failured -kubectl wait --timeout=120s \ - --for=jsonpath='{.status.conditions[*].message}'="Migrate down is not allowed" \ - AtlasMigration/atlasmigration-sample -# Patch the migration to allow down migration -kubectl patch AtlasMigration/atlasmigration-sample \ - --type merge --patch-file ./mysql_migrate_down.yaml -kubectl wait --timeout=120s --for=condition=ready \ - AtlasMigration/atlasmigration-sample -if mysql_exec "SHOW COLUMNS FROM myapp.posts LIKE 'created_at';" | grep -q 'created_at'; then - echo "The column created_at should not be present at this point" - exit 1 -else - echo "The column created_at is not present" -fi diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index ff409c60..79c58d21 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -17,6 +17,7 @@ package e2e_test import ( "fmt" "io" + "io/fs" "os" "os/exec" "path/filepath" @@ -30,7 +31,6 @@ import ( const ( nsController = "atlas-operator-system" - controller = "deployment/atlas-operator-controller-manager" ) func TestOperator(t *testing.T) { @@ -40,7 +40,7 @@ func TestOperator(t *testing.T) { } // Creating kubeconfig for the kind cluster kubeconfig := filepath.Join(t.TempDir(), "kubeconfig") - require.NoError(t, pipeFile(kubeconfig, func(f io.Writer) error { + require.NoError(t, pipeFile(0600, kubeconfig, func(f io.Writer) error { cmd := exec.Command("kind", "get", "kubeconfig", "--name", kindCluster) cmd.Stdout, cmd.Stderr = f, os.Stderr return cmd.Run() @@ -60,21 +60,41 @@ func TestOperator(t *testing.T) { } return string(output), nil } - // Deploying the controller-manager - _, err = kind("skaffold", "run", "--wait-for-connection=true", "-p", "integration") - require.NoError(t, err) - // Installing the CRDs - _, err = kind("make", "install") - require.NoError(t, err) - t.Cleanup(func() { - _, err = kind("make", "undeploy", "ignore-not-found=true") + if os.Getenv("HELM_TEST") != "" { + release := "atlas-operator" + // Deploying the controller-manager using helm + _, err = kind("helm", "install", + "-n", nsController, release, + "charts/atlas-operator", + "--create-namespace", + "--set", "image.tag=nightly", + "--set", "image.pullPolicy=Always", + "--set-json", `extraEnvs=[{"name":"MSSQL_ACCEPT_EULA","value":"Y"},{"name":"MSSQL_PID","value":"Developer"}]`, + "--wait") require.NoError(t, err) - }) - // Accept the EULA and set the PID - _, err = kind("kubectl", "set", "env", - "-n", nsController, controller, - "MSSQL_ACCEPT_EULA=Y", "MSSQL_PID=Developer") - require.NoError(t, err) + t.Cleanup(func() { + _, err = kind("helm", "uninstall", + "-n", nsController, release, + "--wait") + require.NoError(t, err) + }) + } else { + // Deploying the controller-manager + _, err = kind("skaffold", "run", "--wait-for-connection=true", "-p", "integration") + require.NoError(t, err) + // Installing the CRDs + _, err = kind("make", "install") + require.NoError(t, err) + t.Cleanup(func() { + _, err = kind("make", "undeploy", "ignore-not-found=true") + require.NoError(t, err) + }) + // Accept the EULA and set the PID + _, err = kind("kubectl", "set", "env", + "-n", nsController, "deployment/atlas-operator-controller-manager", + "MSSQL_ACCEPT_EULA=Y", "MSSQL_PID=Developer") + require.NoError(t, err) + } var controllerPod string for range 10 { // Getting the controller-manager pod name @@ -177,8 +197,8 @@ func TestOperator(t *testing.T) { }) } -func pipeFile(p string, fn func(w io.Writer) error) error { - fs, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, 0644) +func pipeFile(perm fs.FileMode, p string, fn func(w io.Writer) error) error { + fs, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, perm) if err != nil { return err } diff --git a/test/e2e/testscript/migration-mysql.txtar b/test/e2e/testscript/migration-mysql.txtar new file mode 100644 index 00000000..d1316a01 --- /dev/null +++ b/test/e2e/testscript/migration-mysql.txtar @@ -0,0 +1,270 @@ +env DB_URL=mysql://root:pass@mysql.${NAMESPACE}:3306/myapp +kubectl apply -f database.yaml +kubectl create secret generic mysql-credentials --from-literal=url=${DB_URL} +# Wait for the DB ready before creating the schema +kubectl wait --for=condition=ready --timeout=60s -l app=mysql pods + +# Create configmap to store the migrations directory +kubectl create configmap migration-dir --from-file=migrations-v1 + +# Create the resource +kubectl apply -f migration.yaml +kubectl wait --for=condition=ready --timeout=120s AtlasMigration/sample + +# Inspect the schema to ensure it's correct +atlas schema inspect -u ${DB_URL} --exclude=atlas_schema_revisions +cmp stdout schema-v1.hcl + +# Update the configmap with the new migrations +kubectl create configmap migration-dir --from-file=migrations-v2 --dry-run=client -o yaml +stdin stdout +kubectl apply -f - +# Ensure the controller is aware of the change +kubectl wait --for=condition=ready=false --timeout=60s AtlasMigration/sample +kubectl wait --for=condition=ready --timeout=120s AtlasMigration/sample + +# Inspect the schema to ensure it's correct +atlas schema inspect -u ${DB_URL} --exclude=atlas_schema_revisions +cmp stdout schema-v2.hcl + +# Update the configmap with v1 migrations, it will trigger migrate down +kubectl create configmap migration-dir --from-file=migrations-v1 --dry-run=client -o yaml +stdin stdout +kubectl apply -f - +# Expect migration is failured +kubectl wait --timeout=120s --for=jsonpath='{.status.conditions[*].message}'='"Migrate down is not allowed"' AtlasMigration/sample +# Patch the migration to allow down migration +kubectl patch AtlasMigration/sample --type merge --patch-file ./migration-patch-down.yaml +kubectl wait --timeout=120s --for=condition=ready AtlasMigration/sample + +# Inspect the schema to ensure it's correct after down migration +atlas schema inspect -u ${DB_URL} --exclude=atlas_schema_revisions +cmp stdout schema-v1.hcl +-- schema-v1.hcl -- +table "posts" { + schema = schema.myapp + column "id" { + null = false + type = int + } + column "user_id" { + null = false + type = int + } + column "title" { + null = false + type = varchar(255) + } + column "body" { + null = false + type = text + } + primary_key { + columns = [column.id] + } + foreign_key "posts_ibfk_1" { + columns = [column.user_id] + ref_columns = [table.users.column.id] + on_update = NO_ACTION + on_delete = CASCADE + } + index "user_id" { + columns = [column.user_id] + } +} +table "users" { + schema = schema.myapp + column "id" { + null = false + type = int + } + column "user_name" { + null = false + type = varchar(255) + } + column "email" { + null = false + type = varchar(255) + } + primary_key { + columns = [column.id] + } +} +schema "myapp" { + charset = "utf8mb4" + collate = "utf8mb4_0900_ai_ci" +} +-- schema-v2.hcl -- +table "posts" { + schema = schema.myapp + column "id" { + null = false + type = int + } + column "user_id" { + null = false + type = int + } + column "title" { + null = false + type = varchar(255) + } + column "body" { + null = false + type = text + } + column "created_at" { + null = false + type = datetime + default = sql("CURRENT_TIMESTAMP") + } + primary_key { + columns = [column.id] + } + foreign_key "posts_ibfk_1" { + columns = [column.user_id] + ref_columns = [table.users.column.id] + on_update = NO_ACTION + on_delete = CASCADE + } + index "user_id" { + columns = [column.user_id] + } +} +table "users" { + schema = schema.myapp + column "id" { + null = false + type = int + } + column "user_name" { + null = false + type = varchar(255) + } + column "email" { + null = false + type = varchar(255) + } + primary_key { + columns = [column.id] + } +} +schema "myapp" { + charset = "utf8mb4" + collate = "utf8mb4_0900_ai_ci" +} +-- migrations-v1/atlas.sum -- +h1:XBXbh+rzLis8gknjlIqnxXLBkOZ+sN2v2p7KjyVFYYM= +20230316085611.sql h1:br6W6LPEnnsejlz/7hRm9zthwStCzjN2vZkqVPxlmvo= +20230316090502.sql h1:GfeRjkSeoCt3JVRtLQNa/r50lRfpAPXS7AqTU2ZNFgY= +-- migrations-v1/20230316085611.sql -- +-- Create "users" table +CREATE TABLE `users` ( + `id` int NOT NULL, + `user_name` varchar(255) NOT NULL, + `email` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci; +-- migrations-v1/20230316090502.sql -- +-- Create "posts" table +CREATE TABLE `posts` ( + `id` int NOT NULL, + `user_id` int NOT NULL, + `title` varchar(255) NOT NULL, + `body` text NOT NULL, + PRIMARY KEY (`id`), + INDEX `user_id` (`user_id`), + CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE +) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci; +-- migrations-v2/atlas.sum -- +h1:clhmXbPkM1agi3QjNRsUkfHXCQxdtNT1x70QI5x7nns= +20230316085611.sql h1:br6W6LPEnnsejlz/7hRm9zthwStCzjN2vZkqVPxlmvo= +20230316090502.sql h1:GfeRjkSeoCt3JVRtLQNa/r50lRfpAPXS7AqTU2ZNFgY= +20241013090259.sql h1:0049ULgDeVTr2RSapOCwICgpUGLP6QgRfanqVSuRxd8= +-- migrations-v2/20230316085611.sql -- +-- Create "users" table +CREATE TABLE `users` ( + `id` int NOT NULL, + `user_name` varchar(255) NOT NULL, + `email` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci; +-- migrations-v2/20230316090502.sql -- +-- Create "posts" table +CREATE TABLE `posts` ( + `id` int NOT NULL, + `user_id` int NOT NULL, + `title` varchar(255) NOT NULL, + `body` text NOT NULL, + PRIMARY KEY (`id`), + INDEX `user_id` (`user_id`), + CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE +) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci; +-- migrations-v2/20241013090259.sql -- +ALTER TABLE posts ADD COLUMN created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP; +-- migration.yaml -- +apiVersion: db.atlasgo.io/v1alpha1 +kind: AtlasMigration +metadata: + name: sample +spec: + dir: + configMapRef: + name: "migration-dir" + urlFrom: + secretKeyRef: + key: url + name: mysql-credentials +-- migration-patch-down.yaml -- +apiVersion: db.atlasgo.io/v1alpha1 +kind: AtlasMigration +spec: + protectedFlows: + migrateDown: + allow: true + autoApprove: true +-- database.yaml -- +apiVersion: v1 +kind: Service +metadata: + name: mysql +spec: + selector: + app: mysql + ports: + - name: mysql + port: 3306 + targetPort: mysql + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysql +spec: + selector: + matchLabels: + app: mysql + replicas: 1 + template: + metadata: + labels: + app: mysql + spec: + containers: + - name: mysql + image: mysql:latest + env: + - name: MYSQL_ROOT_PASSWORD + value: pass + - name: MYSQL_DATABASE + value: myapp + ports: + - containerPort: 3306 + name: mysql + readinessProbe: + initialDelaySeconds: 5 + periodSeconds: 2 + timeoutSeconds: 1 + exec: + command: [ "mysql", "-ppass", "-h", "127.0.0.1", "-e", "SELECT 1" ]