X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=n2vc%2Flibjuju.py;h=9dd8f3ba725469ea5b3efca858d17d46a81093f2;hb=820b38ac89e41311e441f76f7d037d5b1a6a6d9e;hp=a6fd8fe48dd7f299f3a00a0ac30b1c6228c0fa64;hpb=eb8943a887e2fb8cce0240382811f9e504f3c7fb;p=osm%2FN2VC.git diff --git a/n2vc/libjuju.py b/n2vc/libjuju.py index a6fd8fe..9dd8f3b 100644 --- a/n2vc/libjuju.py +++ b/n2vc/libjuju.py @@ -18,7 +18,7 @@ import typing import time -from juju.errors import JujuAPIError +import juju.errors from juju.model import Model from juju.machine import Machine from juju.application import Application @@ -174,7 +174,7 @@ class Libjuju: cloud_name=cloud.name, credential_name=cloud.credential_name, ) - except JujuAPIError as e: + except juju.errors.JujuAPIError as e: if "already exists" in e.message: pass else: @@ -273,7 +273,9 @@ class Libjuju: """ return await controller.get_model(model_name) - async def model_exists(self, model_name: str, controller: Controller = None) -> bool: + async def model_exists( + self, model_name: str, controller: Controller = None + ) -> bool: """ Check if model exists @@ -343,7 +345,7 @@ class Libjuju: db_dict: dict = None, progress_timeout: float = None, total_timeout: float = None, - series: str = "xenial", + series: str = "bionic", wait: bool = True, ) -> (Machine, bool): """ @@ -661,6 +663,83 @@ class Libjuju: return application + async def scale_application( + self, + model_name: str, + application_name: str, + scale: int = 1, + total_timeout: float = None, + ): + """ + Scale application (K8s) + + :param: model_name: Model name + :param: application_name: Application name + :param: scale: Scale to which to set this application + :param: total_timeout: Timeout for the entity to be active + """ + + model = None + controller = await self.get_controller() + try: + model = await self.get_model(controller, model_name) + + self.log.debug( + "Scaling application {} in model {}".format( + application_name, model_name + ) + ) + application = self._get_application(model, application_name) + if application is None: + raise JujuApplicationNotFound("Cannot scale application") + await application.scale(scale=scale) + # Wait until application is scaled in model + self.log.debug( + "Waiting for application {} to be scaled in model {}...".format( + application_name, model_name + ) + ) + if total_timeout is None: + total_timeout = 1800 + end = time.time() + total_timeout + while time.time() < end: + application_scale = self._get_application_count(model, application_name) + # Before calling wait_for_model function, + # wait until application unit count and scale count are equal. + # Because there is a delay before scaling triggers in Juju model. + if application_scale == scale: + await JujuModelWatcher.wait_for_model( + model=model, timeout=total_timeout + ) + self.log.debug( + "Application {} is scaled in model {}".format( + application_name, model_name + ) + ) + return + await asyncio.sleep(5) + raise Exception( + "Timeout waiting for application {} in model {} to be scaled".format( + application_name, model_name + ) + ) + finally: + if model: + await self.disconnect_model(model) + await self.disconnect_controller(controller) + + def _get_application_count(self, model: Model, application_name: str) -> int: + """Get number of units of the application + + :param: model: Model object + :param: application_name: Application name + + :return: int (or None if application doesn't exist) + """ + application = self._get_application(model, application_name) + if application is not None: + return len(application.units) + def _get_application(self, model: Model, application_name: str) -> Application: """Get application @@ -680,7 +759,7 @@ class Libjuju: db_dict: dict = None, progress_timeout: float = None, total_timeout: float = None, - **kwargs + **kwargs, ): """Execute action @@ -842,7 +921,7 @@ class Libjuju: # Add relation try: await model.add_relation(endpoint_1, endpoint_2) - except JujuAPIError as e: + except juju.errors.JujuAPIError as e: if "not found" in e.message: self.log.warning("Relation not found: {}".format(e.message)) return @@ -1215,6 +1294,11 @@ class Libjuju: controller = await self.get_controller() try: await controller.remove_cloud(name) + except juju.errors.JujuError as e: + if len(e.errors) == 1 and f'cloud "{name}" not found' == e.errors[0]: + self.log.warning(f"Cloud {name} not found, so it could not be deleted.") + else: + raise e finally: await self.disconnect_controller(controller)