From a5fd59b9ec8d9300979c269984fb2254b4a210e0 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Thu, 6 Mar 2025 16:57:39 +0100 Subject: [PATCH 01/16] [DPE-6771] Add sniff_timeout Currently, we are using default sniff_timeout, which is 100ms. That is not enough for the opensearchpy to a remote cluster. This PR adds sniff_timeout and extends it to 60s. Closes #577 --- tests/integration/ha/continuous_writes.py | 16 +++++++++++++++- tests/integration/helpers.py | 5 +++-- tox.ini | 4 ++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/integration/ha/continuous_writes.py b/tests/integration/ha/continuous_writes.py index 33e95b5fc2..e44c4b41dd 100644 --- a/tests/integration/ha/continuous_writes.py +++ b/tests/integration/ha/continuous_writes.py @@ -64,12 +64,13 @@ async def start( """Run continuous writes in the background.""" if not self._is_stopped: await self.clear() - # create index if custom conf needed if repl_mode == ReplicationMode.WITH_AT_LEAST_1_REPL: await self._create_fully_replicated_index() elif repl_mode == ReplicationMode.WITH_AT_LEAST_0_REPL: await self._create_index_with_0_all_replicas() + elif repl_mode == ReplicationMode.DEFAULT: + await self._create_default_index() # create process self._create_process(is_bulk=is_bulk) @@ -141,6 +142,19 @@ async def max_stored_id(self) -> int: finally: client.close() + async def _create_default_index(self): + """Create index with 1 p_shard and an r_shard on each node.""" + client = await self._client() + try: + # create index with a replica shard on every node + client.indices.create( + index=ContinuousWrites.INDEX_NAME, + ) + except Exception as e: + print(e) + finally: + client.close() + async def _create_fully_replicated_index(self): """Create index with 1 p_shard and an r_shard on each node.""" client = await self._client() diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 685a57c678..ca7b4da762 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -114,7 +114,7 @@ async def run_action( continue ping = subprocess.call( - f"ping -c 1 {unit.ip}".split(), + f"nc -zv {unit.ip} 9200".split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) @@ -436,7 +436,8 @@ def opensearch_client( http_compress=True, sniff_on_start=True, # sniff before doing anything sniff_on_connection_fail=True, # refresh nodes after a node fails to respond - sniffer_timeout=60, # and also every 60 seconds + sniffer_timeout=60.0, # and also every 60 seconds + sniff_timeout=60.0, # and also every 60 seconds use_ssl=True, # turn on ssl verify_certs=True, # make sure we verify SSL certificates ssl_assert_hostname=False, diff --git a/tox.ini b/tox.ini index e510a3d622..a89ce1cb53 100644 --- a/tox.ini +++ b/tox.ini @@ -69,11 +69,15 @@ allowlist_externals = # Set the testing host before starting the lxd cloud sudo sysctl + apt + nc commands_pre = poetry install --only main,charm-libs,integration # Set the testing host before starting the lxd cloud sudo sysctl -w vm.max_map_count=262144 vm.swappiness=0 net.ipv4.tcp_retries2=5 + sudo apt update + sudo apt install -y netcat-openbsd commands = poetry run pytest -v --tb native --log-cli-level=INFO -s --ignore={[vars]tests_path}/unit/ {posargs} From c75ea519ce1c6b0169bf799b1639c8eefdc907d6 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Thu, 6 Mar 2025 17:06:15 +0100 Subject: [PATCH 02/16] Roll back the changes in continuous write --- tests/integration/ha/continuous_writes.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/tests/integration/ha/continuous_writes.py b/tests/integration/ha/continuous_writes.py index e44c4b41dd..33e95b5fc2 100644 --- a/tests/integration/ha/continuous_writes.py +++ b/tests/integration/ha/continuous_writes.py @@ -64,13 +64,12 @@ async def start( """Run continuous writes in the background.""" if not self._is_stopped: await self.clear() + # create index if custom conf needed if repl_mode == ReplicationMode.WITH_AT_LEAST_1_REPL: await self._create_fully_replicated_index() elif repl_mode == ReplicationMode.WITH_AT_LEAST_0_REPL: await self._create_index_with_0_all_replicas() - elif repl_mode == ReplicationMode.DEFAULT: - await self._create_default_index() # create process self._create_process(is_bulk=is_bulk) @@ -142,19 +141,6 @@ async def max_stored_id(self) -> int: finally: client.close() - async def _create_default_index(self): - """Create index with 1 p_shard and an r_shard on each node.""" - client = await self._client() - try: - # create index with a replica shard on every node - client.indices.create( - index=ContinuousWrites.INDEX_NAME, - ) - except Exception as e: - print(e) - finally: - client.close() - async def _create_fully_replicated_index(self): """Create index with 1 p_shard and an r_shard on each node.""" client = await self._client() From 6f0f8af1a85e9d8cf0dfd55ac24bd80e545d6bfe Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Fri, 7 Mar 2025 10:04:28 +0100 Subject: [PATCH 03/16] Add first batches to make the CI indepedent from clouds --- tests/integration/ha/test_ha.py | 23 ++++++++++++++++-- tests/integration/ha/test_ha_networking.py | 6 +++++ .../ha/test_scale_to_one_and_back.py | 24 ++++++++++++++++--- tests/integration/helpers.py | 15 ++++++++++++ tox.ini | 1 + 5 files changed, 64 insertions(+), 5 deletions(-) diff --git a/tests/integration/ha/test_ha.py b/tests/integration/ha/test_ha.py index 7df76531e9..1c25cb26bb 100644 --- a/tests/integration/ha/test_ha.py +++ b/tests/integration/ha/test_ha.py @@ -4,6 +4,8 @@ import asyncio import logging +import os +import subprocess import time import pytest @@ -63,8 +65,25 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(my_charm, num_units=NUM_HA_UNITS, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + my_charm, + application_name="opensearch", + num_units=NUM_HA_UNITS, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} opensearch", + shell=True, ) # Relate it to OpenSearch to set up TLS. diff --git a/tests/integration/ha/test_ha_networking.py b/tests/integration/ha/test_ha_networking.py index 0934860fda..b1399b6c1f 100644 --- a/tests/integration/ha/test_ha_networking.py +++ b/tests/integration/ha/test_ha_networking.py @@ -27,6 +27,7 @@ SERIES, app_name, check_cluster_formation_successful, + ci_only, get_application_unit_ids_hostnames, get_application_unit_ids_ips, get_application_unit_names, @@ -42,6 +43,7 @@ logger = logging.getLogger(__name__) +@ci_only() @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail @@ -72,6 +74,7 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: assert len(ops_test.model.applications[APP_NAME].units) == 3 +@ci_only() @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail @@ -175,6 +178,7 @@ async def test_full_network_cut_with_ip_change_node_with_elected_cm( await assert_continuous_writes_consistency(ops_test, c_writes, [app]) +@ci_only() @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail @@ -294,6 +298,7 @@ async def test_full_network_cut_with_ip_change_node_with_primary_shard( await assert_continuous_writes_consistency(ops_test, c_writes, [app]) +@ci_only() @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail @@ -383,6 +388,7 @@ async def test_full_network_cut_without_ip_change_node_with_elected_cm( await assert_continuous_writes_consistency(ops_test, c_writes, [app]) +@ci_only() @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail diff --git a/tests/integration/ha/test_scale_to_one_and_back.py b/tests/integration/ha/test_scale_to_one_and_back.py index 74f86d27dc..ead3324703 100644 --- a/tests/integration/ha/test_scale_to_one_and_back.py +++ b/tests/integration/ha/test_scale_to_one_and_back.py @@ -2,6 +2,8 @@ # Copyright 2024 Canonical Ltd. # See LICENSE file for licensing details. +import os +import subprocess import asyncio import logging @@ -43,7 +45,7 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: if await app_name(ops_test): return - my_charm = await ops_test.build_charm(".") + my_charm = "./opensearch_ubuntu@22.04-amd64.charm" # await ops_test.build_charm(".") # This test will manually issue update-status hooks, as we want to see the change in behavior # when applying `settle_voting` during start/stop and during update-status. MODEL_CONFIG["update-status-hook-interval"] = "360m" @@ -53,8 +55,24 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(my_charm, num_units=3, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + my_charm, + num_units=3, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} opensearch", + shell=True, ) # Relate it to OpenSearch to set up TLS. diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index ca7b4da762..3bd7707f3d 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 # Copyright 2024 Canonical Ltd. # See LICENSE file for licensing details. + import json import logging +import os import random import shlex import subprocess @@ -12,6 +14,7 @@ from types import SimpleNamespace from typing import Dict, List, Optional, Union +import pytest import requests import yaml from charms.opensearch.v0.helper_networking import is_reachable @@ -638,3 +641,15 @@ async def is_each_unit_restarted( return True except RetryError: return False + + +def ci_only(): + is_ci = os.environ.get("CI", "false").lower() == "true" + + if not is_ci: + logger.info(f"Skipping test as not running in CI") + + return pytest.mark.skipif( + not is_ci, + reason="Skipping test as not running in CI", + ) diff --git a/tox.ini b/tox.ini index a89ce1cb53..88cbe521f4 100644 --- a/tox.ini +++ b/tox.ini @@ -64,6 +64,7 @@ pass_env = GITHUB_OUTPUT S3_INTEGRATOR_CHARMPATH SECRETS_FROM_GITHUB + TEST_CONSTRAINTS allowlist_externals = {[testenv]allowlist_externals} # Set the testing host before starting the lxd cloud From b9d88c5c7ad53ae1f72bd9c0a293025cfdd72f9b Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Fri, 7 Mar 2025 10:09:26 +0100 Subject: [PATCH 04/16] Fix lint --- tests/integration/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 3bd7707f3d..1979f45a40 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -647,7 +647,7 @@ def ci_only(): is_ci = os.environ.get("CI", "false").lower() == "true" if not is_ci: - logger.info(f"Skipping test as not running in CI") + logger.info("Skipping test as not running in CI") return pytest.mark.skipif( not is_ci, From c3c15bc74ebcbe062818e29283ae295e996a8bb7 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Fri, 7 Mar 2025 15:03:36 +0100 Subject: [PATCH 05/16] Move to SUBSTRATE and cloud filter --- tests/integration/ha/test_backups.py | 108 ++++++++++++++++-- tests/integration/ha/test_ha_networking.py | 12 +- .../ha/test_scale_to_one_and_back.py | 4 +- tests/integration/helpers.py | 17 ++- tox.ini | 1 + 5 files changed, 117 insertions(+), 25 deletions(-) diff --git a/tests/integration/ha/test_backups.py b/tests/integration/ha/test_backups.py index d71ceca34e..28f9d5aa07 100644 --- a/tests/integration/ha/test_backups.py +++ b/tests/integration/ha/test_backups.py @@ -17,6 +17,7 @@ import asyncio import logging +import os import random import string import subprocess @@ -327,9 +328,29 @@ async def test_small_deployment_build_and_deploy( ) await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(backup_integrator, channel=backup_integrator_channel), - ops_test.model.deploy(charm, num_units=3, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + backup_integrator, + channel=backup_integrator_channel, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, + num_units=3, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) # Relate it to OpenSearch to set up TLS. @@ -383,14 +404,24 @@ async def test_large_deployment_build_and_deploy( ) await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=tls_config), - ops_test.model.deploy(backup_integrator, channel=backup_integrator_channel), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=tls_config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + backup_integrator, + channel=backup_integrator_channel, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), ops_test.model.deploy( charm, application_name="main", num_units=1, series=SERIES, config=main_orchestrator_conf | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( charm, @@ -398,6 +429,7 @@ async def test_large_deployment_build_and_deploy( num_units=2, series=SERIES, config=failover_orchestrator_conf | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( charm, @@ -405,9 +437,23 @@ async def test_large_deployment_build_and_deploy( num_units=1, series=SERIES, config=data_hot_conf | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} main", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} failover", + shell=True, + ) + # Large deployment setup await ops_test.model.integrate("main:peer-cluster-orchestrator", "failover:peer-cluster") await ops_test.model.integrate("main:peer-cluster-orchestrator", f"{APP_NAME}:peer-cluster") @@ -689,9 +735,29 @@ async def test_restore_to_new_cluster( config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(backup_integrator, channel=backup_integrator_channel), - ops_test.model.deploy(charm, num_units=3, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + backup_integrator, + channel=backup_integrator_channel, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, + num_units=3, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) # Relate it to OpenSearch to set up TLS. @@ -793,9 +859,29 @@ async def test_build_deploy_and_test_status(ops_test: OpsTest, charm) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(S3_INTEGRATOR, channel=S3_INTEGRATOR_CHANNEL), - ops_test.model.deploy(charm, num_units=3, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + S3_INTEGRATOR, + channel=S3_INTEGRATOR_CHANNEL, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, + num_units=3, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) # Relate it to OpenSearch to set up TLS. diff --git a/tests/integration/ha/test_ha_networking.py b/tests/integration/ha/test_ha_networking.py index b1399b6c1f..664af32317 100644 --- a/tests/integration/ha/test_ha_networking.py +++ b/tests/integration/ha/test_ha_networking.py @@ -27,7 +27,7 @@ SERIES, app_name, check_cluster_formation_successful, - ci_only, + filter_cloud, get_application_unit_ids_hostnames, get_application_unit_ids_ips, get_application_unit_names, @@ -43,7 +43,7 @@ logger = logging.getLogger(__name__) -@ci_only() +@filter_cloud(["lxd"]) @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail @@ -74,7 +74,7 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: assert len(ops_test.model.applications[APP_NAME].units) == 3 -@ci_only() +@filter_cloud(["lxd"]) @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail @@ -178,7 +178,7 @@ async def test_full_network_cut_with_ip_change_node_with_elected_cm( await assert_continuous_writes_consistency(ops_test, c_writes, [app]) -@ci_only() +@filter_cloud(["lxd"]) @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail @@ -298,7 +298,7 @@ async def test_full_network_cut_with_ip_change_node_with_primary_shard( await assert_continuous_writes_consistency(ops_test, c_writes, [app]) -@ci_only() +@filter_cloud(["lxd"]) @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail @@ -388,7 +388,7 @@ async def test_full_network_cut_without_ip_change_node_with_elected_cm( await assert_continuous_writes_consistency(ops_test, c_writes, [app]) -@ci_only() +@filter_cloud(["lxd"]) @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail diff --git a/tests/integration/ha/test_scale_to_one_and_back.py b/tests/integration/ha/test_scale_to_one_and_back.py index ead3324703..7c095076a2 100644 --- a/tests/integration/ha/test_scale_to_one_and_back.py +++ b/tests/integration/ha/test_scale_to_one_and_back.py @@ -2,10 +2,10 @@ # Copyright 2024 Canonical Ltd. # See LICENSE file for licensing details. -import os -import subprocess import asyncio import logging +import os +import subprocess import pytest from pytest_operator.plugin import OpsTest diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 1979f45a40..03f620c7e7 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -643,13 +643,18 @@ async def is_each_unit_restarted( return False -def ci_only(): - is_ci = os.environ.get("CI", "false").lower() == "true" +def filter_cloud(allowed_clouds: List[str]) -> "pytest.mark.skipif": + if not (chosen_cloud := os.environ.get("SUBSTRATE", "").lower()): + # Assume we are running in LXD if not specified + chosen_cloud = "lxd" - if not is_ci: - logger.info("Skipping test as not running in CI") + if not allowed_clouds: + allowed_clouds = ["aws", "azure", "maas", "manual"] + + if chosen_cloud not in allowed_clouds: + logger.info(f"Skipping test as substrate:{chosen_cloud} not in {allowed_clouds}") return pytest.mark.skipif( - not is_ci, - reason="Skipping test as not running in CI", + chosen_cloud not in allowed_clouds, + reason=f"Skipping test as substrate:{chosen_cloud} not in {allowed_clouds}", ) diff --git a/tox.ini b/tox.ini index 88cbe521f4..058e30529a 100644 --- a/tox.ini +++ b/tox.ini @@ -65,6 +65,7 @@ pass_env = S3_INTEGRATOR_CHARMPATH SECRETS_FROM_GITHUB TEST_CONSTRAINTS + SUBSTRATE allowlist_externals = {[testenv]allowlist_externals} # Set the testing host before starting the lxd cloud From cedd2629eddb003032cc41b7071bae43a02a2ffd Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Fri, 7 Mar 2025 15:05:21 +0100 Subject: [PATCH 06/16] Rollback to build_charm --- tests/integration/ha/test_scale_to_one_and_back.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/ha/test_scale_to_one_and_back.py b/tests/integration/ha/test_scale_to_one_and_back.py index 7c095076a2..ede7a68ccb 100644 --- a/tests/integration/ha/test_scale_to_one_and_back.py +++ b/tests/integration/ha/test_scale_to_one_and_back.py @@ -45,7 +45,7 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: if await app_name(ops_test): return - my_charm = "./opensearch_ubuntu@22.04-amd64.charm" # await ops_test.build_charm(".") + my_charm = await ops_test.build_charm(".") # This test will manually issue update-status hooks, as we want to see the change in behavior # when applying `settle_voting` during start/stop and during update-status. MODEL_CONFIG["update-status-hook-interval"] = "360m" From 036ec60dac6c8b2f7dbbbdd7156427d2d47c80f6 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Mon, 10 Mar 2025 08:21:50 +0100 Subject: [PATCH 07/16] Move away from build_charm and use the new TEST_CONSTRAINTS whenever needed --- tests/integration/ha/test_ha.py | 5 ++-- .../integration/ha/test_ha_multi_clusters.py | 22 +++++++++++++--- .../integration/ha/test_horizontal_scaling.py | 16 ++++++++++-- ..._deployments_cluster_manager_only_nodes.py | 20 +++++++++----- ..._large_deployments_inherit_cluster_name.py | 26 +++++++++---------- .../ha/test_large_deployments_relations.py | 23 +++++++++++----- .../integration/ha/test_roles_managements.py | 19 +++++++++++--- .../ha/test_scale_to_one_and_back.py | 5 ++-- tests/integration/ha/test_storage.py | 25 ++++++++++++------ 9 files changed, 112 insertions(+), 49 deletions(-) diff --git a/tests/integration/ha/test_ha.py b/tests/integration/ha/test_ha.py index 1c25cb26bb..3d6a5abbd2 100644 --- a/tests/integration/ha/test_ha.py +++ b/tests/integration/ha/test_ha.py @@ -53,14 +53,13 @@ @pytest.mark.group(1) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy(ops_test: OpsTest) -> None: +async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" # it is possible for users to provide their own cluster for HA testing. # Hence, check if there is a pre-existing cluster. if await app_name(ops_test): return - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} @@ -72,7 +71,7 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name="opensearch", num_units=NUM_HA_UNITS, series=SERIES, diff --git a/tests/integration/ha/test_ha_multi_clusters.py b/tests/integration/ha/test_ha_multi_clusters.py index 44a50110f5..ffd79ae668 100644 --- a/tests/integration/ha/test_ha_multi_clusters.py +++ b/tests/integration/ha/test_ha_multi_clusters.py @@ -4,6 +4,7 @@ import asyncio import logging +import os import pytest from pytest_operator.plugin import OpsTest @@ -42,8 +43,19 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(charm, num_units=2, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, + num_units=2, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), ) # Relate it to OpenSearch to set up TLS. @@ -73,7 +85,11 @@ async def test_multi_clusters_db_isolation( # deploy new cluster await ops_test.model.deploy( - charm, num_units=1, application_name=SECOND_APP_NAME, config=CONFIG_OPTS + charm, + num_units=1, + application_name=SECOND_APP_NAME, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ) await ops_test.model.integrate(SECOND_APP_NAME, TLS_CERTIFICATES_APP_NAME) diff --git a/tests/integration/ha/test_horizontal_scaling.py b/tests/integration/ha/test_horizontal_scaling.py index 4dc99d258d..76c6ce3b90 100644 --- a/tests/integration/ha/test_horizontal_scaling.py +++ b/tests/integration/ha/test_horizontal_scaling.py @@ -4,6 +4,7 @@ import asyncio import logging +import os import time import pytest @@ -57,8 +58,19 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(my_charm, num_units=1, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + my_charm, + num_units=1, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), ) # Relate it to OpenSearch to set up TLS. diff --git a/tests/integration/ha/test_large_deployments_cluster_manager_only_nodes.py b/tests/integration/ha/test_large_deployments_cluster_manager_only_nodes.py index f6cb647067..a8550479a7 100644 --- a/tests/integration/ha/test_large_deployments_cluster_manager_only_nodes.py +++ b/tests/integration/ha/test_large_deployments_cluster_manager_only_nodes.py @@ -4,6 +4,7 @@ import asyncio import logging +import os import time import pytest @@ -35,39 +36,46 @@ @pytest.mark.group(1) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy(ops_test: OpsTest) -> None: +async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" # it is possible for users to provide their own cluster for HA testing. # Hence, check if there is a pre-existing cluster. - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), ops_test.model.deploy( - my_charm, + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, application_name=MAIN_APP, num_units=1, series=SERIES, config={"cluster_name": CLUSTER_NAME, "roles": "cluster_manager"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=FAILOVER_APP, num_units=1, series=SERIES, config={"cluster_name": CLUSTER_NAME, "init_hold": True, "roles": "cluster_manager"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=DATA_APP, num_units=2, series=SERIES, config={"cluster_name": CLUSTER_NAME, "init_hold": True, "roles": "data"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) diff --git a/tests/integration/ha/test_large_deployments_inherit_cluster_name.py b/tests/integration/ha/test_large_deployments_inherit_cluster_name.py index 5851007138..6c5785c2a7 100644 --- a/tests/integration/ha/test_large_deployments_inherit_cluster_name.py +++ b/tests/integration/ha/test_large_deployments_inherit_cluster_name.py @@ -4,6 +4,7 @@ import asyncio import logging +import os import time import pytest @@ -47,11 +48,8 @@ @pytest.mark.group("Cluster name not autogenerated") @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy_not_autogen(ops_test: OpsTest) -> None: +async def test_build_and_deploy_not_autogen(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch without autogenerated cluster name.""" - # it is possible for users to provide their own cluster for HA testing. - # Hence, check if there is a pre-existing cluster. - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) # Deploy TLS Certificates operator. @@ -59,18 +57,20 @@ async def test_build_and_deploy_not_autogen(ops_test: OpsTest) -> None: await asyncio.gather( ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), ops_test.model.deploy( - my_charm, + charm, application_name=MAIN_APP_NOT_AUTOGEN, num_units=1, series=SERIES, config={"cluster_name": CLUSTER_NAME} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=INVALID_FAILOVER_APP, num_units=1, series=SERIES, config={"init_hold": True, "roles": "cluster_manager"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) @@ -113,11 +113,8 @@ async def test_build_and_deploy_not_autogen(ops_test: OpsTest) -> None: @pytest.mark.group("Cluster name autogenerated") @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy_autogen(ops_test: OpsTest) -> None: +async def test_build_and_deploy_autogen(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch with autogenerated cluster name.""" - # it is possible for users to provide their own cluster for HA testing. - # Hence, check if there is a pre-existing cluster. - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) # Deploy TLS Certificates operator. @@ -125,25 +122,28 @@ async def test_build_and_deploy_autogen(ops_test: OpsTest) -> None: await asyncio.gather( ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), ops_test.model.deploy( - my_charm, + charm, application_name=MAIN_APP_AUTOGEN, num_units=1, series=SERIES, + constraints=os.environ.get("TEST_CONSTRAINTS"), config={"roles": "cluster_manager"} | CONFIG_OPTS, ), ops_test.model.deploy( - my_charm, + charm, application_name=FAILOVER_APP_AUTOGEN, num_units=1, series=SERIES, config={"init_hold": True, "roles": "cluster_manager"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=DATA_APP_AUTOGEN, num_units=2, series=SERIES, config={"init_hold": True, "roles": "data"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) diff --git a/tests/integration/ha/test_large_deployments_relations.py b/tests/integration/ha/test_large_deployments_relations.py index eace6035cb..85981ee71d 100644 --- a/tests/integration/ha/test_large_deployments_relations.py +++ b/tests/integration/ha/test_large_deployments_relations.py @@ -4,6 +4,7 @@ import asyncio import logging +import os import time import pytest @@ -37,46 +38,54 @@ @pytest.mark.group(1) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy(ops_test: OpsTest) -> None: +async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" # it is possible for users to provide their own cluster for HA testing. # Hence, check if there is a pre-existing cluster. - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), ops_test.model.deploy( - my_charm, + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, application_name=MAIN_APP, num_units=3, series=SERIES, config={"cluster_name": CLUSTER_NAME} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=FAILOVER_APP, num_units=3, series=SERIES, config={"cluster_name": CLUSTER_NAME, "init_hold": True} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=DATA_APP, num_units=2, series=SERIES, config={"cluster_name": CLUSTER_NAME, "init_hold": True, "roles": "data.hot,ml"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=INVALID_APP, num_units=1, series=SERIES, config={"cluster_name": INVALID_CLUSTER_NAME, "init_hold": True, "roles": "data.cold"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) diff --git a/tests/integration/ha/test_roles_managements.py b/tests/integration/ha/test_roles_managements.py index d62049832f..8b1a68a0c4 100644 --- a/tests/integration/ha/test_roles_managements.py +++ b/tests/integration/ha/test_roles_managements.py @@ -4,6 +4,7 @@ import asyncio import logging +import os import pytest from charms.opensearch.v0.constants_charm import PClusterWrongNodesCountForQuorum @@ -33,20 +34,30 @@ @pytest.mark.group(1) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy(ops_test: OpsTest) -> None: +async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" # it is possible for users to provide their own cluster for HA testing. # Hence, check if there is a pre-existing cluster. if await app_name(ops_test): return - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(my_charm, num_units=3, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, + num_units=3, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), ) # Relate it to OpenSearch to set up TLS. diff --git a/tests/integration/ha/test_scale_to_one_and_back.py b/tests/integration/ha/test_scale_to_one_and_back.py index ede7a68ccb..854cdd7c07 100644 --- a/tests/integration/ha/test_scale_to_one_and_back.py +++ b/tests/integration/ha/test_scale_to_one_and_back.py @@ -38,14 +38,13 @@ @pytest.mark.group(1) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy(ops_test: OpsTest) -> None: +async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" # it is possible for users to provide their own cluster for HA testing. # Hence, check if there is a pre-existing cluster. if await app_name(ops_test): return - my_charm = await ops_test.build_charm(".") # This test will manually issue update-status hooks, as we want to see the change in behavior # when applying `settle_voting` during start/stop and during update-status. MODEL_CONFIG["update-status-hook-interval"] = "360m" @@ -62,7 +61,7 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, num_units=3, series=SERIES, config=CONFIG_OPTS, diff --git a/tests/integration/ha/test_storage.py b/tests/integration/ha/test_storage.py index 8c8ea695ee..e56f2ca4a9 100644 --- a/tests/integration/ha/test_storage.py +++ b/tests/integration/ha/test_storage.py @@ -4,6 +4,7 @@ import asyncio import logging +import os import subprocess import time @@ -34,14 +35,13 @@ @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy", "xlarge"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail -async def test_build_and_deploy(ops_test: OpsTest) -> None: +async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" # it is possible for users to provide their own cluster for HA testing. # Hence, check if there is a pre-existing cluster. if await app_name(ops_test): return - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) # this assumes the test is run on a lxd cloud await ops_test.model.create_storage_pool("opensearch-pool", "lxd") @@ -49,9 +49,19 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), ops_test.model.deploy( - my_charm, num_units=1, series=SERIES, storage=storage, config=CONFIG_OPTS + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, + num_units=1, + series=SERIES, + storage=storage, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) @@ -66,7 +76,7 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: idle_period=IDLE_PERIOD, wait_for_exact_units={ TLS_CERTIFICATES_APP_NAME: 1, - my_charm: 1, + charm: 1, }, ) assert len(ops_test.model.applications[APP_NAME].units) == 1 @@ -225,7 +235,7 @@ async def test_storage_reuse_after_scale_to_zero( @pytest.mark.group(1) @pytest.mark.abort_on_fail async def test_storage_reuse_in_new_cluster_after_app_removal( - ops_test: OpsTest, c_writes: ContinuousWrites, c_balanced_writes_runner + ops_test: OpsTest, charm, c_writes: ContinuousWrites, c_balanced_writes_runner ): """Check storage is reused and data accessible after removing app and deploying new cluster.""" app = (await app_name(ops_test)) or APP_NAME @@ -288,9 +298,8 @@ async def test_storage_reuse_in_new_cluster_after_app_removal( await ops_test.model.remove_application(app, block_until_done=True) # deploy new cluster, attaching the storage from the previous leader to the new leader - my_charm = await ops_test.build_charm(".") deploy_cluster_with_storage_cmd = ( - f"deploy {my_charm} --model={ops_test.model.info.name} --attach-storage={storage_ids[0]}" + f"deploy {charm} --model={ops_test.model.info.name} --attach-storage={storage_ids[0]}" " --config profile=testing" ) return_code, _, _ = await ops_test.juju(*deploy_cluster_with_storage_cmd.split()) From 67ae9a783941df9a0488f483b2571dc89cf5b6bc Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Mon, 10 Mar 2025 14:39:38 +0100 Subject: [PATCH 08/16] Move the test away from build_charm --- tests/integration/ha/test_horizontal_scaling.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/integration/ha/test_horizontal_scaling.py b/tests/integration/ha/test_horizontal_scaling.py index 76c6ce3b90..6f24369ab8 100644 --- a/tests/integration/ha/test_horizontal_scaling.py +++ b/tests/integration/ha/test_horizontal_scaling.py @@ -46,14 +46,13 @@ @pytest.mark.group(1) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy(ops_test: OpsTest) -> None: +async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" # it is possible for users to provide their own cluster for HA testing. # Hence, check if there is a pre-existing cluster. if await app_name(ops_test): return - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} @@ -65,7 +64,7 @@ async def test_build_and_deploy(ops_test: OpsTest) -> None: constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, num_units=1, series=SERIES, config=CONFIG_OPTS, From 14418121227390d64384ca2c92ba6d3d1b39126f Mon Sep 17 00:00:00 2001 From: phvalguima Date: Mon, 10 Mar 2025 15:41:42 +0100 Subject: [PATCH 09/16] Update helpers.py --- tests/integration/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index ca7b4da762..eb02b71e15 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -114,7 +114,7 @@ async def run_action( continue ping = subprocess.call( - f"nc -zv {unit.ip} 9200".split(), + f"nc -zv {unit.ip} 22".split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) From 69d362c8c1d50a18481133200cf19479a9fe48d3 Mon Sep 17 00:00:00 2001 From: phvalguima Date: Mon, 10 Mar 2025 15:42:05 +0100 Subject: [PATCH 10/16] Update helpers.py --- tests/integration/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index eb02b71e15..0ec7c862af 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -437,7 +437,7 @@ def opensearch_client( sniff_on_start=True, # sniff before doing anything sniff_on_connection_fail=True, # refresh nodes after a node fails to respond sniffer_timeout=60.0, # and also every 60 seconds - sniff_timeout=60.0, # and also every 60 seconds + sniff_timeout=5.0, # and also every 60 seconds use_ssl=True, # turn on ssl verify_certs=True, # make sure we verify SSL certificates ssl_assert_hostname=False, From fdc38fe1a2bc65b85d1728e2a72a8d7cb978db78 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Mon, 10 Mar 2025 20:10:47 +0100 Subject: [PATCH 11/16] Move scaling and upgrade tests to new CI model --- .../integration/ha/test_horizontal_scaling.py | 6 ++++ .../test_small_deployment_upgrades.py | 31 ++++++++++--------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/tests/integration/ha/test_horizontal_scaling.py b/tests/integration/ha/test_horizontal_scaling.py index 6f24369ab8..ca2d26aa70 100644 --- a/tests/integration/ha/test_horizontal_scaling.py +++ b/tests/integration/ha/test_horizontal_scaling.py @@ -5,6 +5,7 @@ import asyncio import logging import os +import subprocess import time import pytest @@ -72,6 +73,11 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, + ) + # Relate it to OpenSearch to set up TLS. await ops_test.model.integrate(APP_NAME, TLS_CERTIFICATES_APP_NAME) await ops_test.model.wait_for_idle( diff --git a/tests/integration/upgrades/test_small_deployment_upgrades.py b/tests/integration/upgrades/test_small_deployment_upgrades.py index ffd23faba1..64c42615e9 100644 --- a/tests/integration/upgrades/test_small_deployment_upgrades.py +++ b/tests/integration/upgrades/test_small_deployment_upgrades.py @@ -3,6 +3,8 @@ # See LICENSE file for licensing details. import logging +import os +import subprocess import pytest from pytest_operator.plugin import OpsTest @@ -73,11 +75,22 @@ async def _build_env(ops_test: OpsTest, version: str) -> None: channel=OPENSEARCH_CHANNEL, revision=VERSION_TO_REVISION[version], series=SERIES, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} opensearch", + shell=True, ) # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} - await ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config) + await ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) # Relate it to OpenSearch to set up TLS. await ops_test.model.integrate(APP_NAME, TLS_CERTIFICATES_APP_NAME) @@ -178,11 +191,10 @@ async def test_upgrade_between_versions( @pytest.mark.group("happy_path_upgrade") @pytest.mark.abort_on_fail async def test_upgrade_to_local( - ops_test: OpsTest, c_writes: ContinuousWrites, c_writes_runner + ops_test: OpsTest, charm, c_writes: ContinuousWrites, c_writes_runner ) -> None: """Test upgrade from usptream to currently locally built version.""" logger.info("Build charm locally") - charm = await ops_test.build_charm(".") await assert_upgrade_to_local(ops_test, c_writes, charm) @@ -209,7 +221,7 @@ async def test_deploy_from_version(ops_test: OpsTest, version) -> None: @pytest.mark.parametrize("version", UPGRADE_INITIAL_VERSION) @pytest.mark.abort_on_fail async def test_upgrade_rollback_from_local( - ops_test: OpsTest, c_writes: ContinuousWrites, c_writes_runner, version + ops_test: OpsTest, charm, c_writes: ContinuousWrites, c_writes_runner, version ) -> None: """Test upgrade and rollback to each version available.""" app = (await app_name(ops_test)) or APP_NAME @@ -224,11 +236,6 @@ async def test_upgrade_rollback_from_local( ) assert action.status == "completed" - logger.info("Build charm locally") - global charm - if not charm: - charm = await ops_test.build_charm(".") - async with ops_test.fast_forward(): logger.info("Refresh the charm") await refresh(ops_test, app, path=charm, config={"profile": "testing"}) @@ -291,11 +298,7 @@ async def test_upgrade_rollback_from_local( @pytest.mark.parametrize("version", UPGRADE_INITIAL_VERSION) @pytest.mark.abort_on_fail async def test_upgrade_from_version_to_local( - ops_test: OpsTest, c_writes: ContinuousWrites, c_writes_runner, version + ops_test: OpsTest, charm, c_writes: ContinuousWrites, c_writes_runner, version ) -> None: """Test upgrade from usptream to currently locally built version.""" - logger.info("Build charm locally") - global charm - if not charm: - charm = await ops_test.build_charm(".") await assert_upgrade_to_local(ops_test, c_writes, charm) From 8a8188b27ff6a649d31a99de4223b327ec09f867 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Tue, 11 Mar 2025 21:35:27 +0100 Subject: [PATCH 12/16] Moving the reminder of the CI --- .../integration/ha/test_ha_multi_clusters.py | 6 ++ tests/integration/ha/test_ha_networking.py | 22 +++++- ..._deployments_cluster_manager_only_nodes.py | 14 ++++ ..._large_deployments_inherit_cluster_name.py | 39 +++++++++- .../ha/test_large_deployments_relations.py | 18 +++++ .../integration/ha/test_roles_managements.py | 6 ++ .../ha/test_scale_to_one_and_back.py | 2 +- tests/integration/ha/test_storage.py | 5 ++ tests/integration/plugins/test_plugins.py | 71 +++++++++++++++---- .../relations/test_opensearch_provider.py | 23 +++++- tests/integration/test_charm.py | 25 +++++-- tests/integration/tls/test_ca_rotation.py | 46 +++++++++--- tests/integration/tls/test_manual_tls.py | 14 +++- tests/integration/tls/test_tls.py | 37 +++++++--- 14 files changed, 281 insertions(+), 47 deletions(-) diff --git a/tests/integration/ha/test_ha_multi_clusters.py b/tests/integration/ha/test_ha_multi_clusters.py index ffd79ae668..ba21c1d3a7 100644 --- a/tests/integration/ha/test_ha_multi_clusters.py +++ b/tests/integration/ha/test_ha_multi_clusters.py @@ -5,6 +5,7 @@ import asyncio import logging import os +import subprocess import pytest from pytest_operator.plugin import OpsTest @@ -58,6 +59,11 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, + ) + # Relate it to OpenSearch to set up TLS. await ops_test.model.integrate(APP_NAME, TLS_CERTIFICATES_APP_NAME) await ops_test.model.wait_for_idle( diff --git a/tests/integration/ha/test_ha_networking.py b/tests/integration/ha/test_ha_networking.py index 664af32317..1dff0f1640 100644 --- a/tests/integration/ha/test_ha_networking.py +++ b/tests/integration/ha/test_ha_networking.py @@ -4,6 +4,8 @@ import asyncio import logging +import os +import subprocess import pytest from pytest_operator.plugin import OpsTest @@ -59,8 +61,24 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), - ops_test.model.deploy(charm, num_units=3, series=SERIES, config=CONFIG_OPTS), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, + num_units=3, + series=SERIES, + config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) # Relate it to OpenSearch to set up TLS. diff --git a/tests/integration/ha/test_large_deployments_cluster_manager_only_nodes.py b/tests/integration/ha/test_large_deployments_cluster_manager_only_nodes.py index a8550479a7..967cd0b262 100644 --- a/tests/integration/ha/test_large_deployments_cluster_manager_only_nodes.py +++ b/tests/integration/ha/test_large_deployments_cluster_manager_only_nodes.py @@ -5,6 +5,7 @@ import asyncio import logging import os +import subprocess import time import pytest @@ -79,6 +80,19 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {MAIN_APP}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {FAILOVER_APP}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {DATA_APP}", + shell=True, + ) + # wait until the TLS operator is ready await wait_until( ops_test, diff --git a/tests/integration/ha/test_large_deployments_inherit_cluster_name.py b/tests/integration/ha/test_large_deployments_inherit_cluster_name.py index 6c5785c2a7..b6e74ef9a8 100644 --- a/tests/integration/ha/test_large_deployments_inherit_cluster_name.py +++ b/tests/integration/ha/test_large_deployments_inherit_cluster_name.py @@ -5,6 +5,7 @@ import asyncio import logging import os +import subprocess import time import pytest @@ -55,7 +56,12 @@ async def test_build_and_deploy_not_autogen(ops_test: OpsTest, charm) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), ops_test.model.deploy( charm, application_name=MAIN_APP_NOT_AUTOGEN, @@ -74,6 +80,15 @@ async def test_build_and_deploy_not_autogen(ops_test: OpsTest, charm) -> None: ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {MAIN_APP_NOT_AUTOGEN}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {INVALID_FAILOVER_APP}", + shell=True, + ) + # wait until the TLS operator is ready await wait_until( ops_test, @@ -120,14 +135,19 @@ async def test_build_and_deploy_autogen(ops_test: OpsTest, charm) -> None: # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), ops_test.model.deploy( charm, application_name=MAIN_APP_AUTOGEN, num_units=1, series=SERIES, - constraints=os.environ.get("TEST_CONSTRAINTS"), config={"roles": "cluster_manager"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( charm, @@ -147,6 +167,19 @@ async def test_build_and_deploy_autogen(ops_test: OpsTest, charm) -> None: ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {MAIN_APP_AUTOGEN}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {FAILOVER_APP_AUTOGEN}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {DATA_APP_AUTOGEN}", + shell=True, + ) + # wait until the TLS operator is ready await wait_until( ops_test, diff --git a/tests/integration/ha/test_large_deployments_relations.py b/tests/integration/ha/test_large_deployments_relations.py index 85981ee71d..28f91d90b1 100644 --- a/tests/integration/ha/test_large_deployments_relations.py +++ b/tests/integration/ha/test_large_deployments_relations.py @@ -5,6 +5,7 @@ import asyncio import logging import os +import subprocess import time import pytest @@ -89,6 +90,23 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {MAIN_APP}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {FAILOVER_APP}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {DATA_APP}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {INVALID_APP}", + shell=True, + ) + # wait until the TLS operator is ready await wait_until( ops_test, diff --git a/tests/integration/ha/test_roles_managements.py b/tests/integration/ha/test_roles_managements.py index 8b1a68a0c4..ce9f87684e 100644 --- a/tests/integration/ha/test_roles_managements.py +++ b/tests/integration/ha/test_roles_managements.py @@ -5,6 +5,7 @@ import asyncio import logging import os +import subprocess import pytest from charms.opensearch.v0.constants_charm import PClusterWrongNodesCountForQuorum @@ -60,6 +61,11 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, + ) + # Relate it to OpenSearch to set up TLS. await ops_test.model.integrate(APP_NAME, TLS_CERTIFICATES_APP_NAME) await wait_until( diff --git a/tests/integration/ha/test_scale_to_one_and_back.py b/tests/integration/ha/test_scale_to_one_and_back.py index 854cdd7c07..b2ffe8d712 100644 --- a/tests/integration/ha/test_scale_to_one_and_back.py +++ b/tests/integration/ha/test_scale_to_one_and_back.py @@ -70,7 +70,7 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ) subprocess.call( - f"juju expose -m {ops_test.model.name} opensearch", + f"juju expose -m {ops_test.model.name} {APP_NAME}", shell=True, ) diff --git a/tests/integration/ha/test_storage.py b/tests/integration/ha/test_storage.py index e56f2ca4a9..aad5a45067 100644 --- a/tests/integration/ha/test_storage.py +++ b/tests/integration/ha/test_storage.py @@ -65,6 +65,11 @@ async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, + ) + # Relate it to OpenSearch to set up TLS. await ops_test.model.integrate(APP_NAME, TLS_CERTIFICATES_APP_NAME) await wait_until( diff --git a/tests/integration/plugins/test_plugins.py b/tests/integration/plugins/test_plugins.py index d62ed03381..418bd86817 100644 --- a/tests/integration/plugins/test_plugins.py +++ b/tests/integration/plugins/test_plugins.py @@ -5,6 +5,7 @@ import asyncio import json import logging +import os import subprocess import pytest @@ -166,13 +167,13 @@ async def _wait_for_units( @pytest.mark.parametrize("deploy_type", SMALL_DEPLOYMENTS) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy_small_deployment(ops_test: OpsTest, deploy_type: str) -> None: +async def test_build_and_deploy_small_deployment( + ops_test: OpsTest, charm, deploy_type: str +) -> None: """Build and deploy an OpenSearch cluster.""" if await app_name(ops_test): return - my_charm = await ops_test.build_charm(".") - model_conf = MODEL_CONFIG.copy() # Make it more regular as COS relation-broken really happens on the # next hook call in each opensearch unit. @@ -185,12 +186,23 @@ async def test_build_and_deploy_small_deployment(ops_test: OpsTest, deploy_type: config = {"ca-common-name": "CN_CA"} await asyncio.gather( ops_test.model.deploy( - my_charm, + charm, num_units=3, series=SERIES, config={"plugin_opensearch_knn": False} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) await wait_until( @@ -247,7 +259,12 @@ async def test_prometheus_exporter_enabled_by_default(ops_test, deploy_type: str @pytest.mark.parametrize("deploy_type", SMALL_DEPLOYMENTS) @pytest.mark.abort_on_fail async def test_small_deployments_prometheus_exporter_cos_relation(ops_test, deploy_type: str): - await ops_test.model.deploy(COS_APP_NAME, channel="edge", series=SERIES), + await ops_test.model.deploy( + COS_APP_NAME, + channel="edge", + series=SERIES, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), await ops_test.model.integrate(APP_NAME, COS_APP_NAME) await _wait_for_units(ops_test, deploy_type, wait_for_cos=True) @@ -275,14 +292,14 @@ async def test_small_deployments_prometheus_exporter_cos_relation(ops_test, depl @pytest.mark.parametrize("deploy_type", LARGE_DEPLOYMENTS) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_large_deployment_build_and_deploy(ops_test: OpsTest, deploy_type: str) -> None: +async def test_large_deployment_build_and_deploy( + ops_test: OpsTest, charm, deploy_type: str +) -> None: """Build and deploy a large deployment for OpenSearch.""" await ops_test.model.set_config(MODEL_CONFIG) # Deploy TLS Certificates operator. tls_config = {"ca-common-name": "CN_CA"} - my_charm = await ops_test.build_charm(".") - main_orchestrator_conf = { "cluster_name": "plugins-test", "init_hold": False, @@ -296,30 +313,51 @@ async def test_large_deployment_build_and_deploy(ops_test: OpsTest, deploy_type: data_hot_conf = {"cluster_name": "plugins-test", "init_hold": True, "roles": "data.hot,ml"} await asyncio.gather( - ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=tls_config), ops_test.model.deploy( - my_charm, + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=tls_config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), + ops_test.model.deploy( + charm, application_name=MAIN_ORCHESTRATOR_NAME, num_units=1, series=SERIES, config=main_orchestrator_conf | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=FAILOVER_ORCHESTRATOR_NAME, num_units=2, series=SERIES, config=failover_orchestrator_conf | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=APP_NAME, num_units=1, series=SERIES, config=data_hot_conf | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {MAIN_ORCHESTRATOR_NAME}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {FAILOVER_ORCHESTRATOR_NAME}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, + ) + # Large deployment setup await ops_test.model.integrate("main:peer-cluster-orchestrator", "failover:peer-cluster") await ops_test.model.integrate("main:peer-cluster-orchestrator", f"{APP_NAME}:peer-cluster") @@ -340,7 +378,12 @@ async def test_large_deployment_build_and_deploy(ops_test: OpsTest, deploy_type: @pytest.mark.abort_on_fail async def test_large_deployment_prometheus_exporter_cos_relation(ops_test, deploy_type: str): # Check that the correct settings were successfully communicated to grafana-agent - await ops_test.model.deploy(COS_APP_NAME, channel="edge", series=SERIES), + await ops_test.model.deploy( + COS_APP_NAME, + channel="edge", + series=SERIES, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ), await ops_test.model.integrate(FAILOVER_ORCHESTRATOR_NAME, COS_APP_NAME) await ops_test.model.integrate(MAIN_ORCHESTRATOR_NAME, COS_APP_NAME) await ops_test.model.integrate(APP_NAME, COS_APP_NAME) diff --git a/tests/integration/relations/test_opensearch_provider.py b/tests/integration/relations/test_opensearch_provider.py index 8ba7d83d6d..fc4b181972 100644 --- a/tests/integration/relations/test_opensearch_provider.py +++ b/tests/integration/relations/test_opensearch_provider.py @@ -4,7 +4,9 @@ import asyncio import json import logging +import os import re +import subprocess import time import pytest @@ -66,19 +68,26 @@ async def test_create_relation(ops_test: OpsTest, application_charm, opensearch_ new_model_conf["update-status-hook-interval"] = "1m" config = {"ca-common-name": "CN_CA"} - await ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config) + await ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) await ops_test.model.set_config(new_model_conf) await asyncio.gather( ops_test.model.deploy( application_charm, application_name=CLIENT_APP_NAME, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( DASHBOARDS_APP_NAME, application_name=DASHBOARDS_APP_NAME, channel="2/edge", series=SERIES, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( opensearch_charm, @@ -86,8 +95,19 @@ async def test_create_relation(ops_test: OpsTest, application_charm, opensearch_ num_units=NUM_UNITS, series=SERIES, config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {DASHBOARDS_APP_NAME}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {OPENSEARCH_APP_NAME}", + shell=True, + ) + await ops_test.model.integrate(OPENSEARCH_APP_NAME, TLS_CERTIFICATES_APP_NAME) await ops_test.model.wait_for_idle( apps=[TLS_CERTIFICATES_APP_NAME, OPENSEARCH_APP_NAME], status="active", timeout=1600 @@ -369,6 +389,7 @@ async def test_multiple_relations(ops_test: OpsTest, application_charm): application_charm, num_units=1, application_name=SECONDARY_CLIENT_APP_NAME, + constraints=os.environ.get("TEST_CONSTRAINTS"), ) # Relate the new application and wait for them to exchange connection data. diff --git a/tests/integration/test_charm.py b/tests/integration/test_charm.py index 748f021a41..9ff6a5fdd8 100644 --- a/tests/integration/test_charm.py +++ b/tests/integration/test_charm.py @@ -4,6 +4,7 @@ import asyncio import logging +import os import shlex import subprocess @@ -46,17 +47,23 @@ @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy", "large"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail -async def test_deploy_and_remove_single_unit(ops_test: OpsTest) -> None: +async def test_deploy_and_remove_single_unit(ops_test: OpsTest, charm) -> None: """Build and deploy OpenSearch with a single unit and remove it.""" - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) await ops_test.model.deploy( - my_charm, + charm, num_units=1, series=SERIES, config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, + ) + # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} await ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config) @@ -84,20 +91,26 @@ async def test_deploy_and_remove_single_unit(ops_test: OpsTest) -> None: @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy", "large"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail -async def test_build_and_deploy(ops_test: OpsTest) -> None: +async def test_build_and_deploy(ops_test: OpsTest, charm) -> None: """Build and deploy a couple of OpenSearch units.""" - my_charm = await ops_test.build_charm(".") model_config = MODEL_CONFIG model_config["update-status-hook-interval"] = "1m" await ops_test.model.set_config(MODEL_CONFIG) await ops_test.model.deploy( - my_charm, + charm, num_units=DEFAULT_NUM_UNITS, series=SERIES, config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, + ) + await wait_until( ops_test, apps=[APP_NAME], diff --git a/tests/integration/tls/test_ca_rotation.py b/tests/integration/tls/test_ca_rotation.py index 988bf0ab67..55e6fd004b 100644 --- a/tests/integration/tls/test_ca_rotation.py +++ b/tests/integration/tls/test_ca_rotation.py @@ -4,6 +4,8 @@ import asyncio import logging +import os +import subprocess import pytest import requests @@ -66,21 +68,31 @@ @pytest.mark.group(SMALL_DEPLOYMENT) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy_active(ops_test: OpsTest) -> None: +async def test_build_and_deploy_active(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) await ops_test.model.deploy( - my_charm, + charm, num_units=len(UNIT_IDS), series=SERIES, config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} - await ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config) + await ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) await wait_until(ops_test, apps=[TLS_CERTIFICATES_APP_NAME], apps_statuses=["active"]) # Relate it to OpenSearch to set up TLS. @@ -98,20 +110,20 @@ async def test_build_and_deploy_active(ops_test: OpsTest) -> None: @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy", "xlarge"]) @pytest.mark.group(LARGE_DEPLOYMENT) @pytest.mark.abort_on_fail -async def test_build_large_deployment(ops_test: OpsTest) -> None: +async def test_build_large_deployment(ops_test: OpsTest, charm) -> None: """Setup a large deployments cluster.""" # deploy new cluster - my_charm = await ops_test.build_charm(".") await asyncio.gather( ops_test.model.deploy( - my_charm, + charm, application_name=MAIN_APP, num_units=3, series=SERIES, config={"cluster_name": CLUSTER_NAME, "roles": "cluster_manager,data"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=FAILOVER_APP, num_units=1, series=SERIES, @@ -121,22 +133,38 @@ async def test_build_large_deployment(ops_test: OpsTest) -> None: "roles": "cluster_manager,data", } | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( - my_charm, + charm, application_name=DATA_APP, num_units=1, series=SERIES, config={"cluster_name": CLUSTER_NAME, "init_hold": True, "roles": "data"} | CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ops_test.model.deploy( TLS_CERTIFICATES_APP_NAME, channel="stable", config={"ca-common-name": "CN_CA"}, + constraints=os.environ.get("TEST_CONSTRAINTS"), ), ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {MAIN_APP}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {FAILOVER_APP}", + shell=True, + ) + subprocess.call( + f"juju expose -m {ops_test.model.name} {DATA_APP}", + shell=True, + ) + # integrate TLS to all applications for app in [MAIN_APP, FAILOVER_APP, DATA_APP]: await ops_test.model.integrate(app, TLS_CERTIFICATES_APP_NAME) diff --git a/tests/integration/tls/test_manual_tls.py b/tests/integration/tls/test_manual_tls.py index a510cab815..b1d9aa7e93 100644 --- a/tests/integration/tls/test_manual_tls.py +++ b/tests/integration/tls/test_manual_tls.py @@ -3,6 +3,8 @@ # See LICENSE file for licensing details. import logging +import os +import subprocess import pytest from juju.application import Application @@ -19,23 +21,29 @@ @pytest.mark.group(1) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy_with_manual_tls(ops_test: OpsTest) -> None: +async def test_build_and_deploy_with_manual_tls(ops_test: OpsTest, charm) -> None: """Build and deploy prod cluster of OpenSearch with Manual TLS Operator integration.""" - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) os_app: Application = await ops_test.model.deploy( - my_charm, + charm, num_units=len(UNIT_IDS), series=SERIES, application_name=APP_NAME, config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) # Deploy TLS Certificates operator. tls_app: Application = await ops_test.model.deploy( MANUAL_TLS_CERTIFICATES_APP_NAME, channel="stable", + constraints=os.environ.get("TEST_CONSTRAINTS"), ) await wait_until( ops_test, diff --git a/tests/integration/tls/test_tls.py b/tests/integration/tls/test_tls.py index 4f876be3d6..a5e22ce539 100644 --- a/tests/integration/tls/test_tls.py +++ b/tests/integration/tls/test_tls.py @@ -3,6 +3,7 @@ # See LICENSE file for licensing details. import logging +import os import subprocess import time @@ -46,21 +47,31 @@ @pytest.mark.group(1) @pytest.mark.abort_on_fail @pytest.mark.skip_if_deployed -async def test_build_and_deploy_active(ops_test: OpsTest) -> None: +async def test_build_and_deploy_active(ops_test: OpsTest, charm) -> None: """Build and deploy one unit of OpenSearch.""" - my_charm = await ops_test.build_charm(".") await ops_test.model.set_config(MODEL_CONFIG) await ops_test.model.deploy( - my_charm, + charm, num_units=len(UNIT_IDS), series=SERIES, config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) # Deploy TLS Certificates operator. config = {"ca-common-name": "CN_CA"} - await ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config) + await ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) await wait_until(ops_test, apps=[TLS_CERTIFICATES_APP_NAME], apps_statuses=["active"]) # Relate it to OpenSearch to set up TLS. @@ -168,7 +179,7 @@ async def test_tls_renewal(ops_test: OpsTest) -> None: @pytest.mark.runner(["self-hosted", "linux", "X64", "jammy", "large"]) @pytest.mark.group(1) @pytest.mark.abort_on_fail -async def test_tls_expiration(ops_test: OpsTest) -> None: +async def test_tls_expiration(ops_test: OpsTest, charm) -> None: """Test that expiring TLS certificates are renewed.""" # before we can run this test, need to clean up and deploy with different config if APP_NAME in ops_test.model.applications: @@ -181,19 +192,29 @@ async def test_tls_expiration(ops_test: OpsTest) -> None: # Deploy TLS Certificates operator logger.info("Deploying TLS Certificates operator") config = {"ca-common-name": "CN_CA", "certificate-validity": "1"} - await ops_test.model.deploy(TLS_CERTIFICATES_APP_NAME, channel="stable", config=config) + await ops_test.model.deploy( + TLS_CERTIFICATES_APP_NAME, + channel="stable", + config=config, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) await wait_until(ops_test, apps=[TLS_CERTIFICATES_APP_NAME], apps_statuses=["active"]) # Deploy Opensearch operator await ops_test.model.set_config(MODEL_CONFIG) - my_charm = await ops_test.build_charm(".") logger.info("Deploying OpenSearch") await ops_test.model.deploy( - my_charm, + charm, num_units=1, series=SERIES, config=CONFIG_OPTS, + constraints=os.environ.get("TEST_CONSTRAINTS"), + ) + + subprocess.call( + f"juju expose -m {ops_test.model.name} {APP_NAME}", + shell=True, ) await wait_until( From 90a8c712ac82f49dd540a9e006efba9c7e317aa6 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Tue, 11 Mar 2025 21:56:49 +0100 Subject: [PATCH 13/16] Move the charm as a generic fixture --- tests/integration/conftest.py | 13 +++++++++++++ tests/integration/ha/conftest.py | 8 -------- 2 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 tests/integration/conftest.py diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py new file mode 100644 index 0000000000..37df4e6327 --- /dev/null +++ b/tests/integration/conftest.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# Copyright 2025 Canonical Ltd. +# See LICENSE file for licensing details. + +import pytest + + +@pytest.fixture +def charm(): + # Return str instead of pathlib.Path since python-libjuju's model.deploy(), juju deploy, and + # juju bundle files expect local charms to begin with `./` or `/` to distinguish them from + # Charmhub charms. + return "./opensearch_ubuntu@22.04-amd64.charm" diff --git a/tests/integration/ha/conftest.py b/tests/integration/ha/conftest.py index 40ad315786..0e45df4e14 100644 --- a/tests/integration/ha/conftest.py +++ b/tests/integration/ha/conftest.py @@ -14,14 +14,6 @@ logger = logging.getLogger(__name__) -@pytest.fixture -def charm(): - # Return str instead of pathlib.Path since python-libjuju's model.deploy(), juju deploy, and - # juju bundle files expect local charms to begin with `./` or `/` to distinguish them from - # Charmhub charms. - return "./opensearch_ubuntu@22.04-amd64.charm" - - @pytest.fixture(scope="function") async def reset_restart_delay(ops_test: OpsTest): """Resets service file delay on all units.""" From bf9e1d38c5c4ef944a211da683bdc8c49968a768 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Wed, 12 Mar 2025 22:08:25 +0100 Subject: [PATCH 14/16] Make the upgrade check for an existing opensearch --- tests/integration/upgrades/test_small_deployment_upgrades.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration/upgrades/test_small_deployment_upgrades.py b/tests/integration/upgrades/test_small_deployment_upgrades.py index 64c42615e9..14500b9229 100644 --- a/tests/integration/upgrades/test_small_deployment_upgrades.py +++ b/tests/integration/upgrades/test_small_deployment_upgrades.py @@ -118,6 +118,8 @@ async def _build_env(ops_test: OpsTest, version: str) -> None: @pytest.mark.skip_if_deployed async def test_deploy_latest_from_channel(ops_test: OpsTest) -> None: """Deploy OpenSearch.""" + if await app_name(ops_test): + return await _build_env(ops_test, STARTING_VERSION) @@ -214,6 +216,8 @@ async def test_upgrade_to_local( @pytest.mark.skip_if_deployed async def test_deploy_from_version(ops_test: OpsTest, version) -> None: """Deploy OpenSearch.""" + if await app_name(ops_test): + return await _build_env(ops_test, version) From f8448a2c9e15dc1358f00ef0fce658646bebab5e Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Mon, 24 Mar 2025 10:37:09 +0100 Subject: [PATCH 15/16] Add first trial to skip microceph testing --- tests/integration/ha/test_backups.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/integration/ha/test_backups.py b/tests/integration/ha/test_backups.py index 28f9d5aa07..beae0f08f2 100644 --- a/tests/integration/ha/test_backups.py +++ b/tests/integration/ha/test_backups.py @@ -132,6 +132,14 @@ async def force_clear_cwrites_index(): pass +def skip_microceph() -> "pytest.mark.skipif": + """Skip tests that require microceph.""" + return pytest.mark.skipif( + "CI" not in os.environ or os.environ["CI"] != "true", + reason=f"Skipping test as substrate:{chosen_cloud} not in {allowed_clouds}", + ) + + @pytest.fixture(scope="session") def cloud_configs( github_secrets: Dict[str, str], microceph: Dict[str, str] From b473fefaa72ca984ce6e2401e2d2df1921ec69e7 Mon Sep 17 00:00:00 2001 From: Pedro Guimaraes Date: Mon, 24 Mar 2025 10:39:16 +0100 Subject: [PATCH 16/16] Revert "Add first trial to skip microceph testing" This reverts commit f8448a2c9e15dc1358f00ef0fce658646bebab5e. --- tests/integration/ha/test_backups.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/integration/ha/test_backups.py b/tests/integration/ha/test_backups.py index beae0f08f2..28f9d5aa07 100644 --- a/tests/integration/ha/test_backups.py +++ b/tests/integration/ha/test_backups.py @@ -132,14 +132,6 @@ async def force_clear_cwrites_index(): pass -def skip_microceph() -> "pytest.mark.skipif": - """Skip tests that require microceph.""" - return pytest.mark.skipif( - "CI" not in os.environ or os.environ["CI"] != "true", - reason=f"Skipping test as substrate:{chosen_cloud} not in {allowed_clouds}", - ) - - @pytest.fixture(scope="session") def cloud_configs( github_secrets: Dict[str, str], microceph: Dict[str, str]