From 3845b9fe266cbe15a6a745375c355e935719dac2 Mon Sep 17 00:00:00 2001 From: Robert Gildein Date: Thu, 11 Jan 2024 16:40:49 +0100 Subject: [PATCH] add first draft of pseudo code for data plane upgrade --- cou/apps/base.py | 37 ++++++++++++++++++++++ cou/apps/data_plane.py | 72 ++++++++++++++++++++++++++++++++++++++++++ cou/steps/analyze.py | 11 ++++++- pyproject.toml | 8 ++++- 4 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 cou/apps/data_plane.py diff --git a/cou/apps/base.py b/cou/apps/base.py index a612f97d..1b91fd6a 100644 --- a/cou/apps/base.py +++ b/cou/apps/base.py @@ -58,6 +58,16 @@ class ApplicationUnit: machine: str = "" +@dataclass +class ApplicationMachine: + """Representation of single machine of application.""" + + id: str + hostname: str + az: str + apps: list[OpenStackApplication] + + @dataclass class OpenStackApplication: """Representation of a charmed OpenStack application in the deployment. @@ -83,6 +93,12 @@ class OpenStackApplication: :type channel: str, defaults to "" :param units: Units representation of an application. :type units: list[ApplicationUnit] + :param machines: Machines representation of an application. + :type machines: list[ApplicationMachine] + :param wait_timeout: Waiting time for application/model status + :type wait_timeout: int + :param wait_for_model: Wait for app itself or for all OpenStack related applications + :type wait_for_model: bool :raises ApplicationError: When there are no compatible OpenStack release for the workload version. :raises MismatchedOpenStackVersions: When units part of this application are running mismatched @@ -173,6 +189,11 @@ def _populate_units(self) -> None: ) ) + @property + def is_data_plane(self) -> bool: + """Check if applications belong to data plane.""" + raise NotImplementedError + @property def is_subordinate(self) -> bool: """Check if application is subordinate. @@ -225,6 +246,11 @@ def is_from_charm_store(self) -> bool: """ return self.charm_origin == "cs" + @property + def machines(self) -> list[ApplicationMachine]: + """Return list of machines.""" + raise NotImplementedError + def is_valid_track(self, charm_channel: str) -> bool: """Check if the channel track is valid. @@ -390,6 +416,17 @@ def can_upgrade_current_channel(self) -> bool: """ return bool(self.status.can_upgrade_to) + async def populate_units(self) -> None: + """Populate units and filtered them. + + This function is responsible for configuring the units for the application and at the same + time filtering them. e.g. Use only the machines that are required by user. + + In specific applications such as nova-compute, it can be used to filter out non-empty + hypervisors. + """ + raise NotImplementedError + def new_origin(self, target: OpenStackRelease) -> str: """Return the new openstack-origin or source configuration. diff --git a/cou/apps/data_plane.py b/cou/apps/data_plane.py new file mode 100644 index 00000000..018d92f5 --- /dev/null +++ b/cou/apps/data_plane.py @@ -0,0 +1,72 @@ +# Copyright 2024 Canonical Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Data plane application class.""" +import logging +from typing import Optional + +from cou.apps.base import OpenStackApplication +from cou.apps.factory import AppFactory + +logger = logging.getLogger(__name__) + + +class BaseDataPlaneApplication(OpenStackApplication): + """Base data plane application.""" + + async def _check_control_plane_was_upgraded(self) -> bool: + """Check that all control plane apps was upgraded. + + This function is part of required pre-checks for all data plane apps. + """ + raise NotImplementedError + + async def populate_units( + self, + hostname: Optional[str] = None, + machine_id: Optional[str] = None, + az: Optional[str] = None, + ) -> None: + """Populate units and filtered specific machine, hostname or az. + + :param hostname: machine hostname + :type hostname: str + :param machine_id: machine id + :type machine_id: str + :param az: az of machine + :type az: str + """ + raise NotImplementedError + + +@AppFactory.register_application(["nova-compute"]) +class NovaCompute(BaseDataPlaneApplication): + """Nova-compute application.""" + + wait_timeout = 30 * 60 # 30 min + wait_for_model = True + + async def instance_count(self) -> int: + """Get number of instances running on hypervisor.""" + raise NotImplementedError + + async def populate_units(self, *args: Optional[str], **kwargs: Optional[str]) -> None: + """Populate units and filtered specific machine, hostname or az. + + :param args: arguments parser + :type args: Any + :param kwargs: named argument parser + :type kwargs: Any + """ + raise NotImplementedError diff --git a/cou/steps/analyze.py b/cou/steps/analyze.py index f8517884..71708930 100644 --- a/cou/steps/analyze.py +++ b/cou/steps/analyze.py @@ -55,6 +55,15 @@ def __post_init__(self) -> None: self.current_cloud_os_release = self._get_minimum_cloud_os_release() self.current_cloud_series = self._get_minimum_cloud_series() + @staticmethod + def _sort_apps(apps: list[OpenStackApplication]) -> list[OpenStackApplication]: + """Sort apps in order relevant to upgrade. + + :param apps: List of applications to split. + :type apps: list[OpenStackApplication] + """ + raise NotImplementedError + @staticmethod def _split_apps( apps: list[OpenStackApplication], @@ -62,7 +71,7 @@ def _split_apps( """Split applications to control plane and data plane apps. :param apps: List of applications to split. - :type apps: Iterable[OpenStackApplication] + :type apps: list[OpenStackApplication] :return: Control plane and data plane application lists. :rtype: tuple[list[OpenStackApplication], list[OpenStackApplication]] """ diff --git a/pyproject.toml b/pyproject.toml index 82399639..b473c890 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,9 @@ ignore-paths = [ "tests", "docs" ] +disable = [ + "W0223", +] no-docstring-rgx = "__.*__" default-docstring-type = "sphinx" accept-no-param-doc = false @@ -80,11 +83,14 @@ exclude = [ relative_files = true concurrency = ["gevent"] source = ["."] -omit = ["tests/**", "docs/**", "lib/**", "snap/**", "build/**", "setup.py"] +omit = ["tests/**", "docs/**", "lib/**", "snap/**", "build/**", "setup.py", "cou/apps/data_plane.py"] [tool.coverage.report] fail_under = 100 show_missing = true +exclude_also = [ + "raise NotImplementedError" +] [tool.coverage.html] directory = "tests/unit/report/html"