From 4074f8aba930b6ca80eb119ea7b11bfb32b7878d Mon Sep 17 00:00:00 2001 From: quilesj Date: Thu, 12 Dec 2019 16:10:54 +0000 Subject: [PATCH] Changes in NS and operation status Change-Id: I649c19f13e2679163f5ea993f91368cc1c433208 Signed-off-by: quilesj (cherry picked from commit 776ab399e7a5468ab8ae08ac54af96b795a15457) --- n2vc/juju_observer.py | 20 +++++++++++++------- n2vc/n2vc_conn.py | 35 +++++++++++++++++++++++++++++++---- n2vc/n2vc_juju_conn.py | 35 +++++++++++++++++++++-------------- 3 files changed, 65 insertions(+), 25 deletions(-) diff --git a/n2vc/juju_observer.py b/n2vc/juju_observer.py index 25c1c1f..10efa98 100644 --- a/n2vc/juju_observer.py +++ b/n2vc/juju_observer.py @@ -57,7 +57,7 @@ class JujuModelObserver(ModelObserver): except Exception as e: # no entity_id aatribute, try machine attribute entity_id = machine.machine - self.n2vc.debug(msg='Registering machine for changes notifications: {}'.format(entity_id)) + # self.n2vc.debug(msg='Registering machine for change notifications: {}'.format(entity_id)) entity = _Entity(entity_id=entity_id, entity_type='machine', obj=machine, db_dict=db_dict) self.machines[entity_id] = entity @@ -70,7 +70,7 @@ class JujuModelObserver(ModelObserver): def register_application(self, application: Application, db_dict: dict): entity_id = application.entity_id - self.n2vc.debug(msg='Registering application for changes notifications: {}'.format(entity_id)) + # self.n2vc.debug(msg='Registering application for change notifications: {}'.format(entity_id)) entity = _Entity(entity_id=entity_id, entity_type='application', obj=application, db_dict=db_dict) self.applications[entity_id] = entity @@ -83,7 +83,7 @@ class JujuModelObserver(ModelObserver): def register_action(self, action: Action, db_dict: dict): entity_id = action.entity_id - self.n2vc.debug(msg='Registering action for changes notifications: {}'.format(entity_id)) + # self.n2vc.debug(msg='Registering action for changes notifications: {}'.format(entity_id)) entity = _Entity(entity_id=entity_id, entity_type='action', obj=action, db_dict=db_dict) self.actions[entity_id] = entity @@ -103,6 +103,8 @@ class JujuModelObserver(ModelObserver): if not self.is_machine_registered(machine_id): return + self.n2vc.debug('Waiting for machine completed: {}'.format(machine_id)) + # wait for a final state entity = self.machines[machine_id] return await self._wait_for_entity( @@ -121,6 +123,8 @@ class JujuModelObserver(ModelObserver): if not self.is_application_registered(application_id): return + self.n2vc.debug('Waiting for application completed: {}'.format(application_id)) + # application statuses: unknown, active, waiting # wait for a final state entity = self.applications[application_id] @@ -140,6 +144,8 @@ class JujuModelObserver(ModelObserver): if not self.is_action_registered(action_id): return + self.n2vc.debug('Waiting for action completed: {}'.format(action_id)) + # action statuses: pending, running, completed, failed, cancelled # wait for a final state entity = self.actions[action_id] @@ -193,8 +199,8 @@ class JujuModelObserver(ModelObserver): .format(progress_timeout, entity.entity_type, entity.entity_id) self.n2vc.debug(message) raise N2VCTimeoutException(message=message, timeout='progress') - self.n2vc.debug('End of wait. Final state: {}, retries: {}' - .format(entity.obj.__getattribute__(field_to_check), retries)) + # self.n2vc.debug('End of wait. Final state: {}, retries: {}' + # .format(entity.obj.__getattribute__(field_to_check), retries)) return retries async def on_change(self, delta, old, new, model): @@ -203,8 +209,8 @@ class JujuModelObserver(ModelObserver): return # log - self.n2vc.debug('on_change(): type: {}, entity: {}, id: {}' - .format(delta.type, delta.entity, new.entity_id)) + # self.n2vc.debug('on_change(): type: {}, entity: {}, id: {}' + # .format(delta.type, delta.entity, new.entity_id)) if delta.entity == 'machine': diff --git a/n2vc/n2vc_conn.py b/n2vc/n2vc_conn.py index 8f6c3ef..6ed9aec 100644 --- a/n2vc/n2vc_conn.py +++ b/n2vc/n2vc_conn.py @@ -31,6 +31,7 @@ from enum import Enum from http import HTTPStatus from n2vc.loggable import Loggable from n2vc.exceptions import N2VCBadArgumentsException +import yaml from osm_common.dbmongo import DbException @@ -111,10 +112,11 @@ class N2VCConnector(abc.ABC, Loggable): self.get_public_key() @abc.abstractmethod - async def get_status(self, namespace: str): + async def get_status(self, namespace: str, yaml_format: bool = True): """Get namespace status :param namespace: we obtain ns from namespace + :param yaml_format: returns a yaml string """ # TODO: review which public key @@ -132,7 +134,10 @@ class N2VCConnector(abc.ABC, Loggable): public_key = '' # Find the path where we expect our key lives (~/.ssh) - homedir = os.environ['HOME'] + homedir = os.environ.get('HOME') + if not homedir: + self.warning('No HOME environment variable, using /tmp') + homedir = '/tmp' sshdir = "{}/.ssh".format(homedir) if not os.path.exists(sshdir): os.mkdir(sshdir) @@ -397,8 +402,8 @@ class N2VCConnector(abc.ABC, Loggable): self.debug('No db_dict => No database write') return - self.debug('status={} / detailed-status={} / VCA-status={} / entity_type={}' - .format(str(status.value), detailed_status, vca_status, entity_type)) + # self.debug('status={} / detailed-status={} / VCA-status={} / entity_type={}' + # .format(str(status.value), detailed_status, vca_status, entity_type)) try: @@ -464,3 +469,25 @@ def juju_status_2_osm_status(type: str, status: str) -> N2VCDeploymentStatus: return N2VCDeploymentStatus.UNKNOWN return N2VCDeploymentStatus.FAILED + + +def obj_to_yaml(obj: object) -> str: + # dump to yaml + dump_text = yaml.dump(obj, default_flow_style=False, indent=2) + # split lines + lines = dump_text.splitlines() + # remove !!python/object tags + yaml_text = '' + for line in lines: + index = line.find('!!python/object') + if index >= 0: + line = line[:index] + yaml_text += line + '\n' + return yaml_text + + +def obj_to_dict(obj: object) -> dict: + # convert obj to yaml + yaml_text = obj_to_yaml(obj) + # parse to dict + return yaml.load(yaml_text, Loader=yaml.Loader) diff --git a/n2vc/n2vc_juju_conn.py b/n2vc/n2vc_juju_conn.py index 7c55af7..ad001f2 100644 --- a/n2vc/n2vc_juju_conn.py +++ b/n2vc/n2vc_juju_conn.py @@ -29,6 +29,7 @@ import binascii import re from n2vc.n2vc_conn import N2VCConnector +from n2vc.n2vc_conn import obj_to_dict, obj_to_yaml from n2vc.exceptions \ import N2VCBadArgumentsException, N2VCException, N2VCConnectionException, \ N2VCExecutionException, N2VCInvalidCertificate @@ -171,8 +172,9 @@ class N2VCJujuConnector(N2VCConnector): self.info('N2VC juju connector initialized') - async def get_status(self, namespace: str): - self.info('Getting NS status. namespace: {}'.format(namespace)) + async def get_status(self, namespace: str, yaml_format: bool = True): + + # self.info('Getting NS status. namespace: {}'.format(namespace)) if not self._authenticated: await self._juju_login() @@ -190,7 +192,10 @@ class N2VCJujuConnector(N2VCConnector): status = await model.get_status() - return status + if yaml_format: + return obj_to_yaml(status) + else: + return obj_to_dict(status) async def create_execution_environment( self, @@ -508,7 +513,6 @@ class N2VCJujuConnector(N2VCConnector): nsi_id, ns_id, vnf_id, vdu_id, vdu_count = self._get_namespace_components(namespace=namespace) if ns_id is not None: - self.debug('Deleting model {}'.format(ns_id)) try: await self._juju_destroy_model( model_name=ns_id, @@ -653,7 +657,7 @@ class N2VCJujuConnector(N2VCConnector): if not the_path[-1] == '.': the_path = the_path + '.' update_dict = {the_path + 'ee_id': ee_id} - self.debug('Writing ee_id to database: {}'.format(the_path)) + # self.debug('Writing ee_id to database: {}'.format(the_path)) self.db.set_one( table=the_table, q_filter=the_filter, @@ -985,18 +989,16 @@ class N2VCJujuConnector(N2VCConnector): application = await self._juju_get_application(model_name=model_name, application_name=application_name) - self.debug('trying to execute action {}'.format(action_name)) unit = application.units[0] if unit is not None: actions = await application.get_actions() if action_name in actions: - self.debug('executing action {} with params {}'.format(action_name, kwargs)) + self.debug('executing action "{}" using params: {}'.format(action_name, kwargs)) action = await unit.run_action(action_name, **kwargs) # register action with observer observer.register_action(action=action, db_dict=db_dict) - self.debug(' waiting for action completed or error...') await observer.wait_for_action( action_id=action.entity_id, progress_timeout=progress_timeout, @@ -1220,23 +1222,26 @@ class N2VCJujuConnector(N2VCConnector): model = await self._juju_get_model(model_name=model_name) uuid = model.info.uuid - self.debug('disconnecting model {}...'.format(model_name)) await self._juju_disconnect_model(model_name=model_name) self.juju_models[model_name] = None self.juju_observers[model_name] = None self.debug('destroying model {}...'.format(model_name)) await self.controller.destroy_model(uuid) + self.debug('model destroy requested {}'.format(model_name)) # wait for model is completely destroyed end = time.time() + total_timeout while time.time() < end: - self.debug('waiting for model is destroyed...') + self.debug('Waiting for model is destroyed...') try: - await self.controller.get_model(uuid) - except Exception: - self.debug('model destroyed') - return + # await self.controller.get_model(uuid) + models = await self.controller.list_models() + if model_name not in models: + self.debug('The model {} ({}) was destroyed'.format(model_name, uuid)) + return + except Exception as e: + pass await asyncio.sleep(1.0) async def _juju_login(self): @@ -1316,6 +1321,8 @@ class N2VCJujuConnector(N2VCConnector): await self.juju_models[model_name].disconnect() self.juju_models[model_name] = None self.juju_observers[model_name] = None + else: + self.warning('Cannot disconnect model: {}'.format(model_name)) def _create_juju_public_key(self): """Recreate the Juju public key on lcm container, if needed -- 2.25.1