Skip to content

Commit

Permalink
Merge branch 'dev/data-plane' into data-plane-units-upgraded
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielcocenza committed Mar 14, 2024
2 parents 26292e6 + f929e62 commit f2e88c8
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 68 deletions.
56 changes: 51 additions & 5 deletions cou/apps/auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from cou.utils.openstack import (
OPENSTACK_TO_TRACK_MAPPING,
TRACK_TO_OPENSTACK_MAPPING,
OpenStackCodenameLookup,
OpenStackRelease,
)

Expand Down Expand Up @@ -231,10 +232,55 @@ class MysqlInnodbCluster(AuxiliaryApplication):
wait_timeout = LONG_IDLE_TIMEOUT


# NOTE (gabrielcocenza): Although CephOSD class is empty now, it will be
# necessary to add post upgrade plan to set require-osd-release. Registering on
# AuxiliaryApplication can be easily forgot and ceph-osd can't be instantiated
# as a normal OpenStackApplication.
@AppFactory.register_application(["ceph-osd"])
class CephOSD(AuxiliaryApplication):
class CephOsd(AuxiliaryApplication):
"""Application for ceph-osd."""

def pre_upgrade_steps(
self, target: OpenStackRelease, units: Optional[list[COUUnit]]
) -> list[PreUpgradeStep]:
"""Pre Upgrade steps planning.
:param target: OpenStack release as target to upgrade.
:type target: OpenStackRelease
:param units: Units to generate upgrade plan
:type units: Optional[list[COUUnit]]
:return: List of pre upgrade steps.
:rtype: list[PreUpgradeStep]
"""
steps = [
PreUpgradeStep(
description="Check if all nova-compute units had been upgraded",
coro=self._verify_nova_compute(target),
)
]
steps.extend(super().pre_upgrade_steps(target, units))
return steps

async def _verify_nova_compute(self, target: OpenStackRelease) -> None:
"""Check if a nova-compute application has upgraded its workload version.
:param target: OpenStack release as target to upgrade.
:type target: OpenStackRelease
:raises ApplicationError: When any nova-compute app workload version isn't reached.
"""
units_not_upgraded = []
apps = await self.model.get_applications()

for app in apps:
if app.charm != "nova-compute":
logger.debug("skipping application %s", app.name)
continue

for unit in app.units.values():
compatible_os_versions = OpenStackCodenameLookup.find_compatible_versions(
app.charm, unit.workload_version
)

if target not in compatible_os_versions:
units_not_upgraded.append(unit.name)

if units_not_upgraded:
raise ApplicationError(
f"Units '{', '.join(units_not_upgraded)}' did not reach {target}."
)
12 changes: 1 addition & 11 deletions cou/steps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,11 @@ def compare_step_coroutines(coro1: Optional[Coroutine], coro2: Optional[Coroutin
inspection_coro1 = inspect.getcoroutinelocals(coro1)
inspection_coro2 = inspect.getcoroutinelocals(coro2)

args1 = list(inspection_coro1.get("args", []))
kwargs1_values = list(inspection_coro1.get("kwargs", {}).values())

args2 = list(inspection_coro2.get("args", []))
kwargs2_values = list(inspection_coro2.get("kwargs", {}).values())
return (
# check if same coroutine was used
coro1.cr_code == coro2.cr_code
# check coroutine arguments
and (
inspection_coro1 == inspection_coro2
# with this we can compare for e.g:
# run_action("my_app/0", "pause") with run_action(unit="my_app/0", action_name="pause")
or args1 + kwargs1_values == args2 + kwargs2_values
)
and inspection_coro1 == inspection_coro2
)


Expand Down
1 change: 1 addition & 0 deletions cou/utils/juju_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ async def run_on_unit(

if str(normalize_results["Code"]) != "0":
raise CommandRunFailed(cmd=command, result=normalize_results)

logger.debug(normalize_results["Stdout"])

return normalize_results
Expand Down
180 changes: 172 additions & 8 deletions tests/unit/apps/test_auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
from cou.apps.auxiliary import (
AuxiliaryApplication,
CephMon,
CephOsd,
MysqlInnodbCluster,
OvnPrincipal,
RabbitMQServer,
)
from cou.apps.core import NovaCompute
from cou.exceptions import ApplicationError, HaltUpgradePlanGeneration
from cou.steps import (
ApplicationUpgradePlan,
Expand All @@ -35,7 +37,7 @@
from cou.utils.juju_utils import COUMachine, COUUnit
from cou.utils.openstack import OpenStackRelease
from tests.unit.apps.utils import add_steps
from tests.unit.utils import assert_steps
from tests.unit.utils import assert_steps, dedent_plan, generate_cou_machine


def test_auxiliary_app(model):
Expand Down Expand Up @@ -181,7 +183,7 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria_change_channel(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]
add_steps(expected_plan, upgrade_steps)
Expand Down Expand Up @@ -259,7 +261,7 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]
add_steps(expected_plan, upgrade_steps)
Expand Down Expand Up @@ -343,7 +345,7 @@ def test_auxiliary_upgrade_plan_ussuri_to_victoria_ch_migration(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]
add_steps(expected_plan, upgrade_steps)
Expand Down Expand Up @@ -672,7 +674,7 @@ def test_ceph_mon_upgrade_plan_xena_to_yoga(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]
add_steps(expected_plan, upgrade_steps)
Expand Down Expand Up @@ -756,7 +758,7 @@ def test_ceph_mon_upgrade_plan_ussuri_to_victoria(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]
add_steps(expected_plan, upgrade_steps)
Expand Down Expand Up @@ -939,7 +941,7 @@ def test_ovn_principal_upgrade_plan(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]
add_steps(expected_plan, upgrade_steps)
Expand Down Expand Up @@ -1018,7 +1020,7 @@ def test_mysql_innodb_cluster_upgrade(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]
add_steps(expected_plan, upgrade_steps)
Expand All @@ -1028,6 +1030,64 @@ def test_mysql_innodb_cluster_upgrade(model):
assert_steps(upgrade_plan, expected_plan)


@pytest.mark.parametrize("target", [OpenStackRelease("victoria")])
@patch("cou.apps.auxiliary.AuxiliaryApplication.pre_upgrade_steps")
def test_ceph_osd_pre_upgrade_steps(mock_pre_upgrade_steps, target, model):
"""Test Ceph-osd pre upgrade steps."""
mock_pre_upgrade_steps.return_value = [MagicMock(spec_set=UpgradeStep)()]
app = CephOsd(
name="ceph-osd",
can_upgrade_to="octopus/stable",
charm="ceph-osd",
channel="octopus/stable",
config={"source": {"value": "distro"}},
machines={},
model=model,
origin="ch",
series="focal",
subordinate_to=[],
units={},
workload_version="17.0.1",
)
steps = app.pre_upgrade_steps(target, None)

assert steps == [
PreUpgradeStep(
description="Check if all nova-compute units had been upgraded",
coro=app._verify_nova_compute(target),
),
*mock_pre_upgrade_steps.return_value,
]
mock_pre_upgrade_steps.assert_called_once_with(target, None)


@pytest.mark.asyncio
@patch("cou.utils.openstack.OpenStackCodenameLookup.find_compatible_versions")
async def test_ceph_osd_verify_nova_compute_no_app(mock_lookup, model):
"""Test Ceph-osd verifying all nova computes."""
target = OpenStackRelease("victoria")
app = CephOsd(
name="ceph-osd",
can_upgrade_to="octopus/stable",
charm="ceph-osd",
channel="octopus/stable",
config={"source": {"value": "distro"}},
machines={},
model=model,
origin="ch",
series="focal",
subordinate_to=[],
units={},
workload_version="17.0.1",
)
model.get_applications.return_value = [app]

await app._verify_nova_compute(target)

model.get_applications.assert_awaited_once_with()
mock_lookup.assert_not_called()


@patch("cou.apps.base.OpenStackApplication.generate_upgrade_plan")
def test_auxiliary_upgrade_by_unit(mock_super, model):
"""Test generating plan with units doesn't create unit Upgrade steps."""
Expand Down Expand Up @@ -1074,3 +1134,107 @@ def test_auxiliary_upgrade_by_unit(mock_super, model):
# Parent class was called with units=None even that units were passed to the
# Auxiliary app, meaning that will create all-in-one upgrade strategy
mock_super.assert_called_with(target, False, None)


@pytest.mark.asyncio
@patch("cou.utils.openstack.OpenStackCodenameLookup.find_compatible_versions")
async def test_ceph_osd_verify_nova_compute_pass(mock_lookup, model):
"""Test Ceph-osd verifying all nova computes."""
target = OpenStackRelease("victoria")
mock_lookup.return_value = [target]
nova_compute = MagicMock(spec_set=NovaCompute)()
nova_compute.charm = "nova-compute"
nova_compute.units = {"nova-compute/0": COUUnit("nova-compute/0", None, "22.0.0")}
app = CephOsd(
name="ceph-osd",
can_upgrade_to="octopus/stable",
charm="ceph-osd",
channel="octopus/stable",
config={"source": {"value": "distro"}},
machines={},
model=model,
origin="ch",
series="focal",
subordinate_to=[],
units={},
workload_version="17.0.1",
)
model.get_applications.return_value = [app, nova_compute]

await app._verify_nova_compute(target)

model.get_applications.assert_awaited_once_with()
mock_lookup.assert_called_once_with("nova-compute", "22.0.0")


@pytest.mark.asyncio
@patch("cou.utils.openstack.OpenStackCodenameLookup.find_compatible_versions")
async def test_ceph_osd_verify_nova_compute_fail(mock_lookup, model):
"""Test Ceph-osd verifying all nova computes."""
mock_lookup.return_value = [OpenStackRelease("ussuri")]
target = OpenStackRelease("victoria")
nova_compute = MagicMock(spec_set=NovaCompute)()
nova_compute.charm = "nova-compute"
nova_compute.units = {"nova-compute/0": COUUnit("nova-compute/0", None, "22.0.0")}
app = CephOsd(
name="ceph-osd",
can_upgrade_to="octopus/stable",
charm="ceph-osd",
channel="octopus/stable",
config={"source": {"value": "distro"}},
machines={},
model=model,
origin="ch",
series="focal",
subordinate_to=[],
units={},
workload_version="17.0.1",
)
model.get_applications.return_value = [app, nova_compute]

with pytest.raises(ApplicationError, match=f"Units 'nova-compute/0' did not reach {target}."):
await app._verify_nova_compute(target)


def test_ceph_osd_upgrade_plan(model):
"""Testing generating ceph-osd upgrade plan."""
exp_plan = dedent_plan(
"""\
Upgrade plan for 'ceph-osd' to victoria
Check if all nova-compute units had been upgraded
Upgrade software packages of 'ceph-osd' from the current APT repositories
Upgrade software packages on unit ceph-osd/0
Upgrade software packages on unit ceph-osd/1
Upgrade software packages on unit ceph-osd/2
Change charm config of 'ceph-osd' 'source' to 'cloud:focal-victoria'
Wait 300s for app ceph-osd to reach the idle state.
Check if the workload of 'ceph-osd' has been upgraded on units: ceph-osd/0, ceph-osd/1, ceph-osd/2
""" # noqa: E501 line too long
)
target = OpenStackRelease("victoria")
machines = {f"{i}": generate_cou_machine(f"{i}", f"az-{i}") for i in range(3)}
ceph_osd = CephOsd(
name="ceph-osd",
can_upgrade_to="octopus/stable",
charm="ceph-osd",
channel="octopus/stable",
config={"source": {"value": "distro"}},
machines=machines,
model=model,
origin="ch",
series="focal",
subordinate_to=[],
units={
f"ceph-osd/{i}": COUUnit(
name=f"ceph-osd/{i}",
workload_version="17.0.1",
machine=machines[f"{i}"],
)
for i in range(3)
},
workload_version="17.0.1",
)

plan = ceph_osd.generate_upgrade_plan(target, False)

assert str(plan) == exp_plan
4 changes: 2 additions & 2 deletions tests/unit/apps/test_channel_based.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ def test_application_gnocchi_upgrade_plan_ussuri_to_victoria(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]

Expand Down Expand Up @@ -401,7 +401,7 @@ def test_application_designate_bind_upgrade_plan_ussuri_to_victoria(model):
f"{', '.join([unit for unit in app.units.keys()])}"
),
parallel=False,
coro=app._verify_workload_upgrade(target, app.units.values()),
coro=app._verify_workload_upgrade(target, list(app.units.values())),
),
]

Expand Down
Loading

0 comments on commit f2e88c8

Please sign in to comment.