Changes in NS and operation status 56/8456/1
authorquilesj <e.nvi001.tid@telefonica.com>
Thu, 12 Dec 2019 16:10:54 +0000 (16:10 +0000)
committerisraelad <adam.israel@canonical.com>
Mon, 6 Jan 2020 16:41:34 +0000 (17:41 +0100)
Change-Id: I649c19f13e2679163f5ea993f91368cc1c433208
Signed-off-by: quilesj <e.nvi001.tid@telefonica.com>
(cherry picked from commit 776ab399e7a5468ab8ae08ac54af96b795a15457)

n2vc/juju_observer.py
n2vc/n2vc_conn.py
n2vc/n2vc_juju_conn.py

index 25c1c1f..10efa98 100644 (file)
@@ -57,7 +57,7 @@ class JujuModelObserver(ModelObserver):
         except Exception as e:
             # no entity_id aatribute, try machine attribute
             entity_id = machine.machine
         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
 
         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
 
     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
 
         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
 
     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
 
         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
 
         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(
         # 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
 
         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]
         # 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
 
         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]
         # 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')
                     .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):
         return retries
 
     async def on_change(self, delta, old, new, model):
@@ -203,8 +209,8 @@ class JujuModelObserver(ModelObserver):
             return
 
         # log
             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':
 
 
         if delta.entity == 'machine':
 
index 8f6c3ef..6ed9aec 100644 (file)
@@ -31,6 +31,7 @@ from enum import Enum
 from http import HTTPStatus
 from n2vc.loggable import Loggable
 from n2vc.exceptions import N2VCBadArgumentsException
 from http import HTTPStatus
 from n2vc.loggable import Loggable
 from n2vc.exceptions import N2VCBadArgumentsException
+import yaml
 
 from osm_common.dbmongo import DbException
 
 
 from osm_common.dbmongo import DbException
 
@@ -111,10 +112,11 @@ class N2VCConnector(abc.ABC, Loggable):
         self.get_public_key()
 
     @abc.abstractmethod
         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
         """Get namespace status
 
         :param namespace: we obtain ns from namespace
+        :param yaml_format: returns a yaml string
         """
 
     # TODO: review which public key
         """
 
     # 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)
         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)
         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('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:
 
 
         try:
 
@@ -464,3 +469,25 @@ def juju_status_2_osm_status(type: str, status: str) -> N2VCDeploymentStatus:
             return N2VCDeploymentStatus.UNKNOWN
 
     return N2VCDeploymentStatus.FAILED
             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)
index 7c55af7..ad001f2 100644 (file)
@@ -29,6 +29,7 @@ import binascii
 import re
 
 from n2vc.n2vc_conn import N2VCConnector
 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
 from n2vc.exceptions \
     import N2VCBadArgumentsException, N2VCException, N2VCConnectionException, \
     N2VCExecutionException, N2VCInvalidCertificate
@@ -171,8 +172,9 @@ class N2VCJujuConnector(N2VCConnector):
 
         self.info('N2VC juju connector initialized')
 
 
         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()
 
         if not self._authenticated:
             await self._juju_login()
@@ -190,7 +192,10 @@ class N2VCJujuConnector(N2VCConnector):
 
         status = await model.get_status()
 
 
         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,
 
     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:
 
         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,
             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}
             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,
             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)
 
 
         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:
         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)
 
                 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,
                 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
 
         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)
         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:
 
         # 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:
             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):
             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
             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
 
     def _create_juju_public_key(self):
         """Recreate the Juju public key on lcm container, if needed