X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FN2VC.git;a=blobdiff_plain;f=n2vc%2Fjuju_watcher.py;h=e206e060da1b6d3496d4f56415810c6c4cd150c4;hp=842e990b9295e7ecb990801f7df630a83fb1eb87;hb=eb8943a887e2fb8cce0240382811f9e504f3c7fb;hpb=c38a696d168531e3c067451044262ef4d78ef11f diff --git a/n2vc/juju_watcher.py b/n2vc/juju_watcher.py index 842e990..e206e06 100644 --- a/n2vc/juju_watcher.py +++ b/n2vc/juju_watcher.py @@ -35,6 +35,13 @@ def status(application: Application) -> str: def entity_ready(entity: ModelEntity) -> bool: + """ + Check if the entity is ready + + :param: entity: Model entity. It can be a machine, action, or application. + + :returns: boolean saying if the entity is ready or not + """ entity_type = entity.entity_type if entity_type == "machine": return entity.agent_status in ["started"] @@ -42,20 +49,82 @@ def entity_ready(entity: ModelEntity) -> bool: return entity.status in ["completed", "failed", "cancelled"] elif entity_type == "application": # Workaround for bug: https://github.com/juju/python-libjuju/issues/441 - return status(entity) in ["active", "blocked"] + return entity.status in ["active", "blocked"] else: raise EntityInvalidException("Unknown entity type: {}".format(entity_type)) +def application_ready(application: Application) -> bool: + """ + Check if an application has a leader + + :param: application: Application entity. + + :returns: boolean saying if the application has a unit that is a leader. + """ + ready_status_list = ["active", "blocked"] + application_ready = application.status in ready_status_list + units_ready = all( + unit.workload_status in ready_status_list for unit in application.units + ) + return application_ready and units_ready + + class JujuModelWatcher: + @staticmethod + async def wait_for_model( + model: Model, + timeout: float = 3600 + ): + """ + Wait for all entities in model to reach its final state. + + :param: model: Model to observe + :param: timeout: Timeout for the model applications to be active + + :raises: asyncio.TimeoutError when timeout reaches + """ + + if timeout is None: + timeout = 3600.0 + + # Coroutine to wait until the entity reaches the final state + async def wait_until_model_ready(): + wait_for_entity = asyncio.ensure_future( + asyncio.wait_for( + model.block_until( + lambda: all( + application_ready(application) + for application in model.applications.values() + ), + ), + timeout=timeout, + ) + ) + + tasks = [wait_for_entity] + try: + await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + finally: + # Cancel tasks + for task in tasks: + task.cancel() + + await wait_until_model_ready() + # Check model is still ready after 10 seconds + + await asyncio.sleep(10) + await wait_until_model_ready() + @staticmethod async def wait_for( - model, + model: Model, entity: ModelEntity, progress_timeout: float = 3600, total_timeout: float = 3600, db_dict: dict = None, n2vc: N2VCConnector = None, + vca_id: str = None, ): """ Wait for entity to reach its final state. @@ -66,6 +135,7 @@ class JujuModelWatcher: :param: total_timeout: Timeout for the entity to be active :param: db_dict: Dictionary with data of the DB to write the updates :param: n2vc: N2VC Connector objector + :param: vca_id: VCA ID :raises: asyncio.TimeoutError when timeout reaches """ @@ -82,7 +152,8 @@ class JujuModelWatcher: # Coroutine to wait until the entity reaches the final state wait_for_entity = asyncio.ensure_future( asyncio.wait_for( - model.block_until(lambda: entity_ready(entity)), timeout=total_timeout, + model.block_until(lambda: entity_ready(entity)), + timeout=total_timeout, ) ) @@ -95,6 +166,7 @@ class JujuModelWatcher: timeout=progress_timeout, db_dict=db_dict, n2vc=n2vc, + vca_id=vca_id, ) ) @@ -103,8 +175,6 @@ class JujuModelWatcher: # Execute tasks, and stop when the first is finished # The watcher task won't never finish (unless it timeouts) await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - except Exception as e: - raise e finally: # Cancel tasks for task in tasks: @@ -118,6 +188,7 @@ class JujuModelWatcher: timeout: float, db_dict: dict = None, n2vc: N2VCConnector = None, + vca_id: str = None, ): """ Observes the changes related to an specific entity in a model @@ -128,6 +199,7 @@ class JujuModelWatcher: :param: timeout: Maximum time between two updates in the model :param: db_dict: Dictionary with data of the DB to write the updates :param: n2vc: N2VC Connector objector + :param: vca_id: VCA ID :raises: asyncio.TimeoutError when timeout reaches """ @@ -185,6 +257,7 @@ class JujuModelWatcher: detailed_status=status_message, vca_status=vca_status, entity_type=delta_entity, + vca_id=vca_id, ) # Check if timeout if time.time() > timeout_end: