Skip to content

Commit

Permalink
Introducing Machine for OpenStackApplication (#298)
Browse files Browse the repository at this point in the history
In data-plane upgrade, we will need to have Machine object, which will
be used during hypervisor upgrade.

---------

Co-authored-by: Gabriel Cocenza <[email protected]>
Co-authored-by: TQ X <[email protected]>
  • Loading branch information
3 people authored Mar 18, 2024
1 parent 3e5b433 commit 594919b
Show file tree
Hide file tree
Showing 14 changed files with 877 additions and 550 deletions.
21 changes: 8 additions & 13 deletions cou/apps/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
UpgradeStep,
)
from cou.utils.app_utils import upgrade_packages
from cou.utils.juju_utils import COUModel
from cou.utils.juju_utils import COUModel, Machine
from cou.utils.openstack import (
DISTRO_TO_OPENSTACK_MAPPING,
OpenStackCodenameLookup,
Expand All @@ -59,8 +59,8 @@ class ApplicationUnit:

name: str
os_version: OpenStackRelease
machine: Machine
workload_version: str = ""
machine: str = ""


@dataclass
Expand All @@ -77,6 +77,8 @@ class OpenStackApplication:
:type model: COUModel
:param charm: Name of the charm.
:type charm: str
:param machines: dictionary with Machine
:type machines: dict[str, Machine]
:param units: Units representation of an application.
:type units: list[ApplicationUnit]
:raises ApplicationError: When there are no compatible OpenStack release for the
Expand All @@ -95,6 +97,7 @@ class OpenStackApplication:
config: dict
model: COUModel
charm: str
machines: dict[str, Machine]
units: list[ApplicationUnit] = field(default_factory=lambda: [])
packages_to_hold: Optional[list] = field(default=None, init=False)
wait_timeout: int = field(default=STANDARD_IDLE_TIMEOUT, init=False)
Expand Down Expand Up @@ -177,7 +180,7 @@ def _populate_units(self) -> None:
name=name,
workload_version=unit.workload_version,
os_version=compatible_os_version,
machine=unit.machine,
machine=self.machines[unit.machine],
)
)

Expand Down Expand Up @@ -390,16 +393,8 @@ def channel_codename(self) -> OpenStackRelease:
:return: OpenStackRelease object
:rtype: OpenStackRelease
"""
try:
# get the OpenStack release from the channel track of the application.
os_track_release_channel = OpenStackRelease(self._get_track_from_channel(self.channel))
except ValueError:
logger.debug(
"The current channel of '%s' does not exist or is unexpectedly formatted",
self.name,
)
os_track_release_channel = self.current_os_release
return os_track_release_channel
# get the OpenStack release from the channel track of the application.
return OpenStackRelease(self._get_track_from_channel(self.channel))

@property
def can_upgrade_current_channel(self) -> bool:
Expand Down
14 changes: 12 additions & 2 deletions cou/apps/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from juju.client._definitions import ApplicationStatus

from cou.apps.base import OpenStackApplication
from cou.utils.juju_utils import COUModel
from cou.utils.juju_utils import COUModel, Machine
from cou.utils.openstack import is_charm_supported

logger = logging.getLogger(__name__)
Expand All @@ -41,13 +41,16 @@ def create(
config: dict,
model: COUModel,
charm: str,
machines: dict[str, Machine],
) -> Optional[OpenStackApplication]:
"""Create the OpenStackApplication or registered subclasses.
Applications Subclasses registered with the "register_application"
decorator can be instantiated and used with their customized methods.
:param name: Name of the application
:type name: str
:param machines: Machines in the model
:type machines: dict[str, Machine]
:param status: Status of the application
:type status: ApplicationStatus
:param config: Configuration of the application
Expand All @@ -62,7 +65,14 @@ def create(
# pylint: disable=too-many-arguments
if is_charm_supported(charm):
app_class = cls.charms.get(charm, OpenStackApplication)
return app_class(name=name, status=status, config=config, model=model, charm=charm)
return app_class(
name=name,
status=status,
config=config,
model=model,
charm=charm,
machines=machines,
)
logger.debug(
"'%s' is not a supported OpenStack related application and will be ignored.",
name,
Expand Down
5 changes: 5 additions & 0 deletions cou/steps/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,18 @@ async def _populate(cls, model: juju_utils.COUModel) -> list[OpenStackApplicatio
:rtype: List[OpenStackApplication]
"""
juju_status = await model.get_status()
juju_machines = await model.get_machines()
apps = {
AppFactory.create(
name=app,
status=app_status,
config=await model.get_application_config(app),
model=model,
charm=await model.get_charm_name(app),
machines={
unit_status.machine: juju_machines[unit_status.machine]
for unit_status in app_status.units.values()
},
)
for app, app_status in juju_status.applications.items()
if app_status
Expand Down
31 changes: 31 additions & 0 deletions cou/utils/juju_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import asyncio
import logging
import os
from dataclasses import dataclass
from datetime import datetime
from typing import Any, Callable, Optional

Expand Down Expand Up @@ -129,6 +130,15 @@ async def wrapper(*args: Any, **kwargs: Any) -> Any: # pylint: disable=W9011
return _wrapper


@dataclass(frozen=True)
class Machine:
"""Representation of a juju machine."""

machine_id: str
apps: tuple[str]
az: Optional[str] = None # simple deployments may not have azs


class COUModel:
"""COU model object.
Expand Down Expand Up @@ -499,3 +509,24 @@ async def _wait_for_active_idle() -> None:
apps = await self._get_supported_apps()

await _wait_for_active_idle()

async def get_machines(self) -> dict[str, Machine]:
"""Get all the machines in the model.
:return: Dictionary of the machines found in the model. E.g: {'0': Machine0}
:rtype: dict[str, Machine]
"""
model = await self._get_model()

return {
machine.id: Machine(
machine_id=machine.id,
apps=tuple(
unit.application
for unit in self._model.units.values()
if unit.machine.id == machine.id
),
az=machine.hardware_characteristics.get("availability-zone"),
)
for machine in model.machines.values()
}
Loading

0 comments on commit 594919b

Please sign in to comment.