Skip to content

Commit

Permalink
Run integration tests on arm64 (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
carlcsaposs-canonical authored Jul 3, 2024
1 parent 8b1d2cb commit 2c14db4
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 63 deletions.
20 changes: 14 additions & 6 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,32 @@ jobs:
fail-fast: false
matrix:
juju:
- agent: 2.9.49
- agent: 2.9.49 # renovate: juju-agent-pin-minor
libjuju: ^2
allure: false
- agent: 3.4.3
allure: true
name: Integration test charm | ${{ matrix.juju.agent }}
allure_on_amd64: false
- agent: 3.4.3 # renovate: juju-agent-pin-minor
allure_on_amd64: true
architecture:
- amd64
include:
- juju:
agent: 3.4.3 # renovate: juju-agent-pin-minor
allure_on_amd64: true
architecture: arm64
name: Integration test charm | ${{ matrix.juju.agent }} | ${{ matrix.architecture }}
needs:
- lint
- unit-test
- build
uses: canonical/data-platform-workflows/.github/workflows/integration_test_charm.yaml@v16.2.1
with:
artifact-prefix: ${{ needs.build.outputs.artifact-prefix }}
architecture: ${{ matrix.architecture }}
cloud: microk8s
microk8s-snap-channel: 1.28-strict/stable
juju-agent-version: ${{ matrix.juju.agent }}
libjuju-version-constraint: ${{ matrix.juju.libjuju }}
_beta_allure_report: ${{ matrix.juju.allure }}
_beta_allure_report: ${{ matrix.juju.allure_on_amd64 && matrix.architecture == 'amd64' }}
secrets:
# GitHub appears to redact each line of a multi-line secret
# Avoid putting `{` or `}` on a line by itself so that it doesn't get redacted in logs
Expand Down
7 changes: 7 additions & 0 deletions tests/integration/architecture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.
import subprocess

architecture = subprocess.run(
["dpkg", "--print-architecture"], capture_output=True, check=True, encoding="utf-8"
).stdout.strip()
9 changes: 5 additions & 4 deletions tests/integration/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import itertools
import json
import pathlib
import secrets
import string
import subprocess
Expand Down Expand Up @@ -556,13 +557,13 @@ async def write_content_to_file_in_unit(
"""
pod_name = unit.name.replace("/", "-")

with tempfile.NamedTemporaryFile(mode="w") as temp_file:
with tempfile.NamedTemporaryFile(mode="w", dir=pathlib.Path.home()) as temp_file:
temp_file.write(content)
temp_file.flush()

subprocess.run(
[
"kubectl",
"microk8s.kubectl",
"cp",
"-n",
ops_test.model.info.name,
Expand Down Expand Up @@ -591,10 +592,10 @@ async def read_contents_from_file_in_unit(
"""
pod_name = unit.name.replace("/", "-")

with tempfile.NamedTemporaryFile(mode="r+") as temp_file:
with tempfile.NamedTemporaryFile(mode="r+", dir=pathlib.Path.home()) as temp_file:
subprocess.run(
[
"kubectl",
"microk8s.kubectl",
"cp",
"-n",
ops_test.model.info.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def deploy_chaos_mesh(namespace: str) -> None:
for attempt in Retrying(stop=stop_after_delay(5 * 60), wait=wait_fixed(10)):
with attempt:
output = subprocess.check_output(
f"kubectl get pods --namespace {namespace} -l app.kubernetes.io/instance=chaos-mesh".split(),
f"microk8s.kubectl get pods --namespace {namespace} -l app.kubernetes.io/instance=chaos-mesh".split(),
env=env,
)
assert output.decode().count("Running") == 4, "Chaos Mesh not ready"
Expand Down Expand Up @@ -528,7 +528,7 @@ def isolate_instance_from_cluster(ops_test: OpsTest, unit_name: str) -> None:
env["KUBECONFIG"] = os.path.expanduser("~/.kube/config")

try:
subprocess.check_output(["kubectl", "apply", "-f", temp_file.name], env=env)
subprocess.check_output(["microk8s.kubectl", "apply", "-f", temp_file.name], env=env)
except subprocess.CalledProcessError as e:
logger.error(e.output)
logger.error(e.stderr)
Expand All @@ -540,7 +540,7 @@ def remove_instance_isolation(ops_test: OpsTest) -> None:
env = os.environ
env["KUBECONFIG"] = os.path.expanduser("~/.kube/config")
subprocess.check_output(
f"kubectl -n {ops_test.model.info.name} delete networkchaos network-loss-primary",
f"microk8s.kubectl -n {ops_test.model.info.name} delete networkchaos network-loss-primary",
shell=True,
env=env,
)
Expand Down
34 changes: 17 additions & 17 deletions tests/integration/high_availability/scripts/destroy_chaos_mesh.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,38 @@ fi

destroy_chaos_mesh() {
echo "deleting api-resources"
for i in $(kubectl api-resources | awk '/chaos-mesh/ {print $1}'); do
timeout 30 kubectl delete "${i}" --all --all-namespaces || true
for i in $(microk8s.kubectl api-resources | awk '/chaos-mesh/ {print $1}'); do
timeout 30 microk8s.kubectl delete "${i}" --all --all-namespaces || true
done

if kubectl get mutatingwebhookconfiguration | grep -q 'chaos-mesh-mutation'; then
timeout 30 kubectl delete mutatingwebhookconfiguration chaos-mesh-mutation || true
if microk8s.kubectl get mutatingwebhookconfiguration | grep -q 'chaos-mesh-mutation'; then
timeout 30 microk8s.kubectl delete mutatingwebhookconfiguration chaos-mesh-mutation || true
fi

if kubectl get validatingwebhookconfiguration | grep -q 'chaos-mesh-validation-auth'; then
timeout 30 kubectl delete validatingwebhookconfiguration chaos-mesh-validation-auth || true
if microk8s.kubectl get validatingwebhookconfiguration | grep -q 'chaos-mesh-validation-auth'; then
timeout 30 microk8s.kubectl delete validatingwebhookconfiguration chaos-mesh-validation-auth || true
fi

if kubectl get validatingwebhookconfiguration | grep -q 'chaos-mesh-validation'; then
timeout 30 kubectl delete validatingwebhookconfiguration chaos-mesh-validation || true
if microk8s.kubectl get validatingwebhookconfiguration | grep -q 'chaos-mesh-validation'; then
timeout 30 microk8s.kubectl delete validatingwebhookconfiguration chaos-mesh-validation || true
fi

if kubectl get clusterrolebinding | grep -q 'chaos-mesh'; then
if microk8s.kubectl get clusterrolebinding | grep -q 'chaos-mesh'; then
echo "deleting clusterrolebindings"
readarray -t args < <(kubectl get clusterrolebinding | awk '/chaos-mesh/ {print $1}')
timeout 30 kubectl delete clusterrolebinding "${args[@]}" || true
readarray -t args < <(microk8s.kubectl get clusterrolebinding | awk '/chaos-mesh/ {print $1}')
timeout 30 microk8s.kubectl delete clusterrolebinding "${args[@]}" || true
fi

if kubectl get clusterrole | grep -q 'chaos-mesh'; then
if microk8s.kubectl get clusterrole | grep -q 'chaos-mesh'; then
echo "deleting clusterroles"
readarray -t args < <(kubectl get clusterrole | awk '/chaos-mesh/ {print $1}')
timeout 30 kubectl delete clusterrole "${args[@]}" || true
readarray -t args < <(microk8s.kubectl get clusterrole | awk '/chaos-mesh/ {print $1}')
timeout 30 microk8s.kubectl delete clusterrole "${args[@]}" || true
fi

if kubectl get crd | grep -q 'chaos-mesh.org'; then
if microk8s.kubectl get crd | grep -q 'chaos-mesh.org'; then
echo "deleting crds"
readarray -t args < <(kubectl get crd | awk '/chaos-mesh.org/ {print $1}')
timeout 30 kubectl delete crd "${args[@]}" || true
readarray -t args < <(microk8s.kubectl get crd | awk '/chaos-mesh.org/ {print $1}')
timeout 30 microk8s.kubectl delete crd "${args[@]}" || true
fi

if [ -n "${chaos_mesh_ns}" ] && sg snap_microk8s -c "microk8s.helm3 repo list --namespace=${chaos_mesh_ns}" | grep -q 'chaos-mesh'; then
Expand Down
56 changes: 35 additions & 21 deletions tests/integration/high_availability/test_async_replication.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@


import logging
import subprocess
from asyncio import gather
from pathlib import Path
from time import sleep
Expand All @@ -14,14 +15,13 @@
from juju.model import Model
from pytest_operator.plugin import OpsTest

from .. import juju_
from .. import architecture, juju_, markers
from ..helpers import (
execute_queries_on_unit,
get_cluster_status,
get_leader_unit,
get_unit_address,
)
from ..markers import juju3
from .high_availability_helpers import (
DATABASE_NAME,
TABLE_NAME,
Expand Down Expand Up @@ -55,6 +55,11 @@ async def second_model(
"""Create and return the second model."""
second_model_name = f"{first_model.info.name}-other"
await ops_test._controller.add_model(second_model_name)
subprocess.run(["juju", "switch", second_model_name], check=True)
subprocess.run(
["juju", "set-model-constraints", f"arch={architecture.architecture}"], check=True
)
subprocess.run(["juju", "switch", first_model.info.name], check=True)
second_model = Model()
await second_model.connect(model_name=second_model_name)
yield second_model # pyright: ignore [reportReturnType]
Expand All @@ -65,9 +70,10 @@ async def second_model(
await ops_test._controller.destroy_model(second_model_name, destroy_storage=True)


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_build_and_deploy(
ops_test: OpsTest, first_model: Model, second_model: Model
) -> None:
Expand Down Expand Up @@ -112,9 +118,10 @@ async def test_build_and_deploy(
)


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_async_relate(first_model: Model, second_model: Model) -> None:
"""Relate the two mysql clusters."""
logger.info("Creating offers in first model")
Expand Down Expand Up @@ -145,9 +152,10 @@ async def test_async_relate(first_model: Model, second_model: Model) -> None:
)


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_create_replication(first_model: Model, second_model: Model) -> None:
"""Run the create replication and wait for the applications to settle."""
logger.info("Running create replication action")
Expand Down Expand Up @@ -175,9 +183,10 @@ async def test_create_replication(first_model: Model, second_model: Model) -> No
)


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_deploy_router_and_app(first_model: Model) -> None:
"""Deploy the router and the test application."""
logger.info("Deploying router and application")
Expand All @@ -193,7 +202,7 @@ async def test_deploy_router_and_app(first_model: Model) -> None:
APPLICATION_APP_NAME,
application_name=APPLICATION_APP_NAME,
series="jammy",
channel="latest/stable",
channel="latest/edge",
num_units=1,
)

Expand All @@ -212,9 +221,10 @@ async def test_deploy_router_and_app(first_model: Model) -> None:
)


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_data_replication(
first_model: Model, second_model: Model, continuous_writes
) -> None:
Expand All @@ -225,9 +235,10 @@ async def test_data_replication(
assert results[0] > 1, "No data was written to the database"


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_standby_promotion(
ops_test: OpsTest, first_model: Model, second_model: Model, continuous_writes
) -> None:
Expand All @@ -253,9 +264,10 @@ async def test_standby_promotion(
), "standby not promoted to primary"


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_failover(ops_test: OpsTest, first_model: Model, second_model: Model) -> None:
"""Test switchover on primary cluster fail."""
logger.info("Freezing mysqld on primary cluster units")
Expand Down Expand Up @@ -291,9 +303,10 @@ async def test_failover(ops_test: OpsTest, first_model: Model, second_model: Mod
)


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_rejoin_invalidated_cluster(
first_model: Model, second_model: Model, continuous_writes
) -> None:
Expand All @@ -311,9 +324,10 @@ async def test_rejoin_invalidated_cluster(
assert results[0] > 1, "No data was written to the database"


@juju3
@pytest.mark.abort_on_fail
@pytest.mark.group(1)
@markers.juju3
@markers.amd64_only # TODO: remove after mysql-router-k8s arm64 stable release
@pytest.mark.abort_on_fail
async def test_remove_relation_and_relate(
first_model: Model, second_model: Model, continuous_writes
) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pytest
from pytest_operator.plugin import OpsTest

from .. import juju_
from .. import juju_, markers
from ..helpers import (
get_leader_unit,
get_primary_unit,
Expand All @@ -31,6 +31,7 @@


@pytest.mark.group(1)
@markers.amd64_only # TODO: remove after arm64 stable release
@pytest.mark.abort_on_fail
async def test_deploy_stable(ops_test: OpsTest) -> None:
"""Simple test to ensure that the mysql and application charms get deployed."""
Expand Down Expand Up @@ -61,6 +62,7 @@ async def test_deploy_stable(ops_test: OpsTest) -> None:


@pytest.mark.group(1)
@markers.amd64_only # TODO: remove after arm64 stable release
@pytest.mark.abort_on_fail
async def test_pre_upgrade_check(ops_test: OpsTest) -> None:
"""Test that the pre-upgrade-check action runs successfully."""
Expand All @@ -87,6 +89,7 @@ async def test_pre_upgrade_check(ops_test: OpsTest) -> None:


@pytest.mark.group(1)
@markers.amd64_only # TODO: remove after arm64 stable release
@pytest.mark.abort_on_fail
async def test_upgrade_from_stable(ops_test: OpsTest):
"""Test updating from stable channel."""
Expand Down
Loading

0 comments on commit 2c14db4

Please sign in to comment.