Skip to content
This repository has been archived by the owner on Aug 9, 2024. It is now read-only.

Commit

Permalink
Merge pull request #14 from canonical/upgrade-jammy
Browse files Browse the repository at this point in the history
Add support for Ubuntu 22.04: part 2
  • Loading branch information
jaimesouza authored May 16, 2023
2 parents 5740860 + ba47e39 commit a5bdb6a
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 37 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@ jobs:
run: tox -e unit

integration-test:
name: Integration tests (LXD)
strategy:
fail-fast: true
matrix:
bases:
- ubuntu@20.04
- ubuntu@22.04
name: Integration tests (LXD) | ${{ matrix.bases }}
runs-on: ubuntu-latest
needs:
- inclusive-naming-check
Expand All @@ -68,4 +74,4 @@ jobs:
provider: lxd
juju-channel: 3.1/stable
- name: Run tests
run: tox -e integration
run: tox run -e integration -- --charm-base=${{ matrix.bases }}
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ extend-ignore = [
"D409",
"D413",
]
ignore = ["E501"]
ignore = ["E501", "D107"]
extend-exclude = ["__pycache__", "*.egg_info"]
per-file-ignores = {"tests/*" = ["D100","D101","D102","D103","D104"]}

[tool.ruff.mccabe]
max-complexity = 10
17 changes: 15 additions & 2 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,25 @@

import pathlib

import pytest
from _pytest.config.argparsing import Parser
from helpers import ETCD, NHC, VERSION
from pytest import fixture
from pytest_operator.plugin import OpsTest


@fixture(scope="module")
def pytest_addoption(parser: Parser) -> None:
parser.addoption(
"--charm-base", action="store", default="ubuntu@22.04", help="Charm base to test."
)


@pytest.fixture(scope="module")
def charm_base(request) -> str:
"""Get slurmdbd charm base to use."""
return request.config.getoption("--charm-base")


@pytest.fixture(scope="module")
async def slurmd_charm(ops_test: OpsTest):
"""Build slurmd charm to use for integration tests."""
charm = await ops_test.build_charm(".")
Expand Down
23 changes: 20 additions & 3 deletions tests/integration/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from typing import Dict
from urllib import request

from pylxd import Client

logger = logging.getLogger(__name__)

ETCD = "etcd-v3.5.0-linux-amd64.tar.gz"
Expand All @@ -33,13 +35,28 @@
).stdout.strip("\n")


def modify_default_profile() -> None:
"""Modify the default LXD profile.
Notes:
The default profile needs to be modified so that slurmd can
use proctrack/cgroup for process tracking inside an LXD container.
"""
client = Client()
config = {"security.nesting": "true"}
logger.info(f"Updating default LXD profile configuration to {config}")
default = client.profiles.get("default")
default.config.update(config)
default.save()


def get_slurmctld_res() -> Dict[str, pathlib.Path]:
"""Get slurmctld resources needed for charm deployment."""
if not (version := pathlib.Path(VERSION)).exists():
logger.info(f"Setting resource {VERSION} to value {VERSION_NUM}...")
logger.info(f"Setting resource {VERSION} to value {VERSION_NUM}")
version.write_text(VERSION_NUM)
if not (etcd := pathlib.Path(ETCD)).exists():
logger.info(f"Getting resource {ETCD} from {ETCD_URL}...")
logger.info(f"Getting resource {ETCD} from {ETCD_URL}")
request.urlretrieve(ETCD_URL, etcd)

return {"etcd": etcd}
Expand All @@ -48,7 +65,7 @@ def get_slurmctld_res() -> Dict[str, pathlib.Path]:
def get_slurmd_res() -> Dict[str, pathlib.Path]:
"""Get slurmd resources needed for charm deployment."""
if not (nhc := pathlib.Path(NHC)).exists():
logger.info(f"Getting resource {NHC} from {NHC_URL}...")
logger.info(f"Getting resource {NHC} from {NHC_URL}")
request.urlretrieve(NHC_URL, nhc)

return {"nhc": nhc}
49 changes: 28 additions & 21 deletions tests/integration/test_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@
"""Test slurmd charm against other SLURM charms in the latest/edge channel."""

import asyncio
import logging
import pathlib
from typing import Any, Coroutine

import pytest
from helpers import (
get_slurmctld_res,
get_slurmd_res,
)
from helpers import get_slurmctld_res, get_slurmd_res, modify_default_profile
from pytest_operator.plugin import OpsTest

SERIES = ["focal"]
logger = logging.getLogger(__name__)

SLURMD = "slurmd"
SLURMDBD = "slurmdbd"
SLURMCTLD = "slurmctld"
Expand All @@ -33,51 +34,53 @@


@pytest.mark.abort_on_fail
@pytest.mark.parametrize("series", SERIES)
@pytest.mark.skip_if_deployed
async def test_build_and_deploy(ops_test: OpsTest, series: str, slurmd_charm):
"""Test that the slurmd charm can stabilize against slurmctld, slurmdbd and percona."""
@pytest.mark.order(1)
async def test_build_and_deploy(
ops_test: OpsTest, slurmd_charm: Coroutine[Any, Any, pathlib.Path], charm_base: str
) -> None:
"""Test that the slurmd charm can stabilize against slurmctld, slurmdbd and MySQL."""
logger.info(f"Deploying {SLURMD} against {SLURMCTLD}, {SLURMDBD}, and {DATABASE}")
modify_default_profile()
res_slurmd = get_slurmd_res()
res_slurmctld = get_slurmctld_res()

# Fetch edge from charmhub for slurmctld, slurmdbd and percona and deploy
await asyncio.gather(
ops_test.model.deploy(
SLURMCTLD,
application_name=SLURMCTLD,
channel="edge",
num_units=1,
resources=res_slurmctld,
series=series,
base=charm_base,
),
ops_test.model.deploy(
SLURMDBD,
application_name=SLURMDBD,
channel="edge",
num_units=1,
series=series,
base=charm_base,
),
ops_test.model.deploy(
ROUTER,
application_name=f"{SLURMDBD}-{ROUTER}",
channel="dpe/edge",
num_units=1,
series=series,
num_units=0,
base=charm_base,
),
ops_test.model.deploy(
DATABASE,
application_name=DATABASE,
channel="edge",
channel="8.0/edge",
num_units=1,
series="jammy",
base="ubuntu@22.04",
),
)
# Attach resources to charms.
await ops_test.juju("attach-resource", SLURMCTLD, f"etcd={res_slurmctld['etcd']}")
# Set relations for charmed applications.
await ops_test.model.relate(f"{SLURMDBD}:{SLURMDBD}", f"{SLURMCTLD}:{SLURMDBD}")
await ops_test.model.relate(f"{SLURMDBD}-{ROUTER}:backend-database", f"{DATABASE}:database")
await ops_test.model.relate(f"{SLURMDBD}:database", f"{SLURMDBD}-{ROUTER}:database")
await ops_test.model.integrate(f"{SLURMDBD}:{SLURMDBD}", f"{SLURMCTLD}:{SLURMDBD}")
await ops_test.model.integrate(f"{SLURMDBD}-{ROUTER}:backend-database", f"{DATABASE}:database")
await ops_test.model.integrate(f"{SLURMDBD}:database", f"{SLURMDBD}-{ROUTER}:database")
# IMPORTANT: It's possible for slurmd to be stuck waiting for slurmctld despite slurmctld and slurmdbd
# available. Relation between slurmd and slurmctld has to be added after slurmctld is ready
# otherwise risk running into race-condition type behavior.
Expand All @@ -88,21 +91,23 @@ async def test_build_and_deploy(ops_test: OpsTest, series: str, slurmd_charm):
application_name=SLURMD,
num_units=1,
resources=res_slurmd,
series=series,
base=charm_base,
)
# Attach resources to slurmd application.
await ops_test.juju("attach-resource", SLURMD, f"nhc={res_slurmd['nhc']}")
# Set relations for slurmd application.
await ops_test.model.relate(f"{SLURMD}:{SLURMD}", f"{SLURMCTLD}:{SLURMD}")
await ops_test.model.integrate(f"{SLURMD}:{SLURMD}", f"{SLURMCTLD}:{SLURMD}")
# Reduce the update status frequency to accelerate the triggering of deferred events.
async with ops_test.fast_forward():
await ops_test.model.wait_for_idle(apps=[SLURMD], status="active", timeout=1000)
assert ops_test.model.applications[SLURMD].units[0].workload_status == "active"


@pytest.mark.abort_on_fail
@pytest.mark.order(2)
async def test_munge_is_active(ops_test: OpsTest):
"""Test that munge is active."""
logger.info("Checking that munge is active inside Juju unit")
unit = ops_test.model.applications[SLURMD].units[0]
cmd_res = (await unit.ssh(command="systemctl is-active munge")).strip("\n")
assert cmd_res == "active"
Expand All @@ -112,8 +117,10 @@ async def test_munge_is_active(ops_test: OpsTest):
# systemd service failing.
@pytest.mark.xfail
@pytest.mark.abort_on_fail
@pytest.mark.order(3)
async def test_slurmd_is_active(ops_test: OpsTest):
"""Test that slurmd is active."""
logger.info("Checking that slurmd is active inside Juju unit")
unit = ops_test.model.applications[SLURMD].units[0]
cmd_res = (await unit.ssh(command="systemctl is-active slurmd")).strip("\n")
assert cmd_res == "active"
18 changes: 10 additions & 8 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,16 @@ commands =
description = Run integration tests
deps =
juju==3.1.0.1
pylxd==2.3.1
pytest==7.2.0
pytest-operator==0.22.0
pytest-operator==0.26.0
pytest-order==1.1.0
tenacity==8.2.2
-r{toxinidir}/requirements.txt
commands =
pytest -v \
-s \
--tb native \
--ignore={[vars]tst_path}unit \
--log-cli-level=INFO \
--model controller \
--keep-models \
{posargs}
-s \
--tb native \
--log-cli-level=INFO \
{[vars]tst_path}integration \
{posargs}

0 comments on commit a5bdb6a

Please sign in to comment.