X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FN2VC.git;a=blobdiff_plain;f=n2vc%2Flibjuju.py;h=aa7afa10ea2938940a5d70906c17efeeb61a3b23;hp=a457309cf61de5c4235cb5760e77f237ca5478f8;hb=667696ef11356f3267df58f2a81c6ecebb0e94b9;hpb=5ef42a14f766aa00a5917845ba1b3e04cc3c15f7 diff --git a/n2vc/libjuju.py b/n2vc/libjuju.py index a457309..aa7afa1 100644 --- a/n2vc/libjuju.py +++ b/n2vc/libjuju.py @@ -81,9 +81,12 @@ class Libjuju: self.log = log or logging.getLogger("Libjuju") self.db = db db_endpoints = self._get_api_endpoints_db() - self.endpoints = db_endpoints or [endpoint] - if db_endpoints is None: + self.endpoints = None + if (db_endpoints and endpoint not in db_endpoints) or not db_endpoints: + self.endpoints = [endpoint] self._update_api_endpoints_db(self.endpoints) + else: + self.endpoints = db_endpoints self.api_proxy = api_proxy self.username = username self.password = password @@ -104,7 +107,10 @@ class Libjuju: self.models = set() self.log.debug("Libjuju initialized!") - self.health_check_task = self.loop.create_task(self.health_check()) + self.health_check_task = self._create_health_check_task() + + def _create_health_check_task(self): + return self.loop.create_task(self.health_check()) async def get_controller(self, timeout: float = 5.0) -> Controller: """ @@ -159,7 +165,8 @@ class Libjuju: :param: controller: Controller that will be disconnected """ - await controller.disconnect() + if controller: + await controller.disconnect() async def add_model(self, model_name: str, cloud_name: str, credential_name=None): """ @@ -485,6 +492,28 @@ class Libjuju: return machine_id + async def deploy( + self, uri: str, model_name: str, wait: bool = True, timeout: float = 3600 + ): + """ + Deploy bundle or charm: Similar to the juju CLI command `juju deploy` + + :param: uri: Path or Charm Store uri in which the charm or bundle can be found + :param: model_name: Model name + :param: wait: Indicates whether to wait or not until all applications are active + :param: timeout: Time in seconds to wait until all applications are active + """ + controller = await self.get_controller() + model = await self.get_model(controller, model_name) + try: + await model.deploy(uri) + if wait: + await JujuModelWatcher.wait_for_model(model, timeout=timeout) + self.log.debug("All units active in model {}".format(model_name)) + finally: + await self.disconnect_model(model) + await self.disconnect_controller(controller) + async def deploy_charm( self, application_name: str, @@ -817,6 +846,10 @@ class Libjuju: self.log.debug("Destroying model {}".format(model_name)) uuid = model.info.uuid + # Destroy machines that are manually provisioned + # and still are in pending state + await self._destroy_pending_machines(model, only_manual=True) + # Disconnect model await self.disconnect_model(model) @@ -864,6 +897,23 @@ class Libjuju: else: self.log.warning("Application not found: {}".format(application_name)) + async def _destroy_pending_machines(self, model: Model, only_manual: bool = False): + """ + Destroy pending machines in a given model + + :param: only_manual: Bool that indicates only manually provisioned + machines should be destroyed (if True), or that + all pending machines should be destroyed + """ + status = await model.get_status() + for machine_id in status.machines: + machine_status = status.machines[machine_id] + if machine_status.agent_status.status == "pending": + if only_manual and not machine_status.instance_id.startswith("manual:"): + break + machine = model.machines[machine_id] + await machine.destroy(force=True) + # async def destroy_machine( # self, model: Model, machine_id: str, total_timeout: float = 3600 # ): @@ -974,6 +1024,7 @@ class Libjuju: :param: interval: Time in seconds between checks """ + controller = None while True: try: controller = await self.get_controller() @@ -1114,7 +1165,7 @@ class Libjuju: auth_type = "certificate" else: raise JujuInvalidK8sConfiguration("authentication method not supported") - return client.CloudCredential(auth_type=auth_type, attrs=attrs,) + return client.CloudCredential(auth_type=auth_type, attrs=attrs) async def add_cloud( self,