From ee5d2ff6d936df56ff49d923644cd1db0e2e9715 Mon Sep 17 00:00:00 2001 From: Carl Csaposs Date: Wed, 3 Jul 2024 14:15:01 +0000 Subject: [PATCH] Run integration tests on arm64 (#278) --- .github/workflows/ci.yaml | 16 ++++++-- tests/integration/architecture.py | 7 ++++ tests/integration/helpers.py | 11 +++--- tests/integration/markers.py | 8 +++- tests/integration/test_exporter.py | 5 +++ tests/integration/test_exporter_with_tls.py | 44 +++++++++++++-------- tests/integration/test_node_port.py | 9 ++++- tests/integration/test_tls.py | 32 +++++++++------ 8 files changed, 93 insertions(+), 39 deletions(-) create mode 100644 tests/integration/architecture.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 295cd6e2c..5559f3921 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -75,10 +75,17 @@ jobs: juju: - agent: 2.9.49 # renovate: juju-agent-pin-minor libjuju: ^2 - allure: false + allure_on_amd64: false - agent: 3.4.3 # renovate: juju-agent-pin-minor - allure: true - name: Integration test charm | ${{ matrix.juju.agent }} + 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 @@ -86,10 +93,11 @@ jobs: 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' }} permissions: contents: write # Needed for Allure Report beta diff --git a/tests/integration/architecture.py b/tests/integration/architecture.py new file mode 100644 index 000000000..b0fbb3447 --- /dev/null +++ b/tests/integration/architecture.py @@ -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() diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 91d07d24d..9c9f2eadd 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -4,6 +4,7 @@ import itertools import json import logging +import pathlib import subprocess import tempfile from typing import Dict, List, Optional @@ -205,13 +206,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, @@ -240,10 +241,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, @@ -351,7 +352,7 @@ async def rotate_mysqlrouter_logs(ops_test: OpsTest, unit_name: str) -> None: subprocess.run( [ - "kubectl", + "microk8s.kubectl", "exec", "-n", ops_test.model.info.name, diff --git a/tests/integration/markers.py b/tests/integration/markers.py index 5f152a908..46d84271d 100644 --- a/tests/integration/markers.py +++ b/tests/integration/markers.py @@ -3,9 +3,15 @@ import pytest -from . import juju_ +from . import architecture, juju_ skip_if_lower_than_3_1 = pytest.mark.skipif( not juju_.is_3_1_or_higher, reason="Skips juju <3.1.x as we have a dependency for self-signed-certificates", ) +amd64_only = pytest.mark.skipif( + architecture.architecture != "amd64", reason="Requires amd64 architecture" +) +arm64_only = pytest.mark.skipif( + architecture.architecture != "arm64", reason="Requires arm64 architecture" +) diff --git a/tests/integration/test_exporter.py b/tests/integration/test_exporter.py index 5a733b560..e59e089f1 100644 --- a/tests/integration/test_exporter.py +++ b/tests/integration/test_exporter.py @@ -12,6 +12,7 @@ import yaml from pytest_operator.plugin import OpsTest +from . import markers from .helpers import ( APPLICATION_DEFAULT_APP_NAME, MYSQL_DEFAULT_APP_NAME, @@ -32,6 +33,10 @@ @pytest.mark.group(1) +# TODO: remove amd64_only after these issues fixed: +# https://github.com/canonical/mysql-router-k8s-operator/issues/282 +# https://github.com/canonical/grafana-agent-k8s-operator/issues/309 +@markers.amd64_only @pytest.mark.abort_on_fail async def test_exporter_endpoint(ops_test: OpsTest) -> None: """Test that exporter endpoint is functional.""" diff --git a/tests/integration/test_exporter_with_tls.py b/tests/integration/test_exporter_with_tls.py index ef6a81171..a9c43b845 100644 --- a/tests/integration/test_exporter_with_tls.py +++ b/tests/integration/test_exporter_with_tls.py @@ -12,7 +12,7 @@ import yaml from pytest_operator.plugin import OpsTest -from . import juju_ +from . import architecture, juju_, markers from .helpers import ( APPLICATION_DEFAULT_APP_NAME, MYSQL_DEFAULT_APP_NAME, @@ -33,14 +33,26 @@ RETRY_TIMEOUT = 3 * 60 if juju_.is_3_or_higher: - TLS_APP_NAME = "self-signed-certificates" - TLS_CONFIG = {"ca-common-name": "Test CA"} + tls_app_name = "self-signed-certificates" + if architecture.architecture == "arm64": + tls_channel = "latest/edge" + else: + tls_channel = "latest/stable" + tls_config = {"ca-common-name": "Test CA"} else: - TLS_APP_NAME = "tls-certificates-operator" - TLS_CONFIG = {"generate-self-signed-certificates": "true", "ca-common-name": "Test CA"} + tls_app_name = "tls-certificates-operator" + if architecture.architecture == "arm64": + tls_channel = "legacy/edge" + else: + tls_channel = "legacy/stable" + tls_config = {"generate-self-signed-certificates": "true", "ca-common-name": "Test CA"} @pytest.mark.group(1) +# TODO: remove amd64_only after these issues fixed: +# https://github.com/canonical/mysql-router-k8s-operator/issues/282 +# https://github.com/canonical/grafana-agent-k8s-operator/issues/309 +@markers.amd64_only @pytest.mark.abort_on_fail async def test_exporter_endpoint(ops_test: OpsTest) -> None: """Test that the exporter endpoint works when related with TLS""" @@ -125,21 +137,21 @@ async def test_exporter_endpoint(ops_test: OpsTest) -> None: "Issuer: CN = MySQL_Router_Auto_Generated_CA_Certificate" in issuer ), "Expected mysqlrouter autogenerated certificate" - logger.info(f"Deploying {TLS_APP_NAME}") + logger.info(f"Deploying {tls_app_name}") await ops_test.model.deploy( - TLS_APP_NAME, - application_name=TLS_APP_NAME, - channel="stable", - config=TLS_CONFIG, + tls_app_name, + application_name=tls_app_name, + channel=tls_channel, + config=tls_config, series="jammy", ) - await ops_test.model.wait_for_idle([TLS_APP_NAME], status="active", timeout=SLOW_TIMEOUT) + await ops_test.model.wait_for_idle([tls_app_name], status="active", timeout=SLOW_TIMEOUT) - logger.info(f"Relating mysqlrouter with {TLS_APP_NAME}") + logger.info(f"Relating mysqlrouter with {tls_app_name}") await ops_test.model.relate( - f"{MYSQL_ROUTER_APP_NAME}:certificates", f"{TLS_APP_NAME}:certificates" + f"{MYSQL_ROUTER_APP_NAME}:certificates", f"{tls_app_name}:certificates" ) unit_address = await get_unit_address(ops_test, mysql_router_app.units[0].name) @@ -198,7 +210,7 @@ async def test_exporter_endpoint(ops_test: OpsTest) -> None: ) assert ( "CN = Test CA" in issuer - ), f"Expected mysqlrouter certificate from {TLS_APP_NAME}" + ), f"Expected mysqlrouter certificate from {tls_app_name}" logger.info("Removing relation between mysqlrouter and grafana agent") await mysql_router_app.remove_relation( @@ -220,9 +232,9 @@ async def test_exporter_endpoint(ops_test: OpsTest) -> None: else: assert False, "❌ can connect to metrics endpoint without relation with cos" - logger.info(f"Removing relation between mysqlrouter and {TLS_APP_NAME}") + logger.info(f"Removing relation between mysqlrouter and {tls_app_name}") await mysql_router_app.remove_relation( - f"{MYSQL_ROUTER_APP_NAME}:certificates", f"{TLS_APP_NAME}:certificates" + f"{MYSQL_ROUTER_APP_NAME}:certificates", f"{tls_app_name}:certificates" ) for attempt in tenacity.Retrying( diff --git a/tests/integration/test_node_port.py b/tests/integration/test_node_port.py index dc4370ed6..f6529bfaf 100644 --- a/tests/integration/test_node_port.py +++ b/tests/integration/test_node_port.py @@ -11,7 +11,7 @@ import yaml from pytest_operator.plugin import OpsTest -from . import markers +from . import architecture, markers from .helpers import ( APPLICATION_DEFAULT_APP_NAME, MYSQL_DEFAULT_APP_NAME, @@ -35,6 +35,11 @@ DATA_INTEGRATOR = "data-integrator" SLOW_TIMEOUT = 15 * 60 MODEL_CONFIG = {"logging-config": "=INFO;unit=DEBUG"} +if architecture.architecture == "arm64": + tls_channel = "latest/edge" +else: + tls_channel = "latest/stable" +TLS_CONFIG = {"ca-common-name": "Test CA"} @pytest.mark.group(1) @@ -86,7 +91,9 @@ async def test_build_and_deploy(ops_test: OpsTest): ), ops_test.model.deploy( SELF_SIGNED_CERTIFICATE_NAME, + channel=tls_channel, application_name=SELF_SIGNED_CERTIFICATE_NAME, + config=TLS_CONFIG, series="jammy", num_units=1, ), diff --git a/tests/integration/test_tls.py b/tests/integration/test_tls.py index 155b1c4de..e46285cac 100644 --- a/tests/integration/test_tls.py +++ b/tests/integration/test_tls.py @@ -10,7 +10,7 @@ import yaml from pytest_operator.plugin import OpsTest -from . import juju_ +from . import architecture, juju_ from .helpers import ( APPLICATION_DEFAULT_APP_NAME, MYSQL_DEFAULT_APP_NAME, @@ -29,11 +29,19 @@ RETRY_TIMEOUT = 2 * 60 if juju_.is_3_or_higher: - TLS_APP_NAME = "self-signed-certificates" - TLS_CONFIG = {"ca-common-name": "Test CA"} + tls_app_name = "self-signed-certificates" + if architecture.architecture == "arm64": + tls_channel = "latest/edge" + else: + tls_channel = "latest/stable" + tls_config = {"ca-common-name": "Test CA"} else: - TLS_APP_NAME = "tls-certificates-operator" - TLS_CONFIG = {"generate-self-signed-certificates": "true", "ca-common-name": "Test CA"} + tls_app_name = "tls-certificates-operator" + if architecture.architecture == "arm64": + tls_channel = "legacy/edge" + else: + tls_channel = "legacy/stable" + tls_config = {"generate-self-signed-certificates": "true", "ca-common-name": "Test CA"} @pytest.mark.group(1) @@ -71,10 +79,10 @@ async def test_build_deploy_and_relate(ops_test: OpsTest) -> None: trust=True, ), ops_test.model.deploy( - TLS_APP_NAME, - application_name=TLS_APP_NAME, - channel="stable", - config=TLS_CONFIG, + tls_app_name, + application_name=tls_app_name, + channel=tls_channel, + config=tls_config, series="jammy", ), ops_test.model.deploy( @@ -121,7 +129,7 @@ async def test_connected_encryption(ops_test: OpsTest) -> None: ), "Expected mysqlrouter autogenerated certificate" logger.info("Relating TLS with mysqlrouter") - await ops_test.model.relate(TLS_APP_NAME, MYSQL_ROUTER_APP_NAME) + await ops_test.model.relate(tls_app_name, MYSQL_ROUTER_APP_NAME) logger.info("Getting certificate issuer after relating with tls operator") for attempt in tenacity.Retrying( @@ -138,11 +146,11 @@ async def test_connected_encryption(ops_test: OpsTest) -> None: ) assert ( "CN = Test CA" in issuer - ), f"Expected mysqlrouter certificate from {TLS_APP_NAME}" + ), f"Expected mysqlrouter certificate from {tls_app_name}" logger.info("Removing relation TLS with mysqlrouter") await ops_test.model.applications[MYSQL_ROUTER_APP_NAME].remove_relation( - f"{TLS_APP_NAME}:certificates", f"{MYSQL_ROUTER_APP_NAME}:certificates" + f"{tls_app_name}:certificates", f"{MYSQL_ROUTER_APP_NAME}:certificates" ) for attempt in tenacity.Retrying(