Fix for service primitive execution and status 90/390/1
authorPhilip Joseph <philip.joseph@riftio.com>
Mon, 26 Sep 2016 11:04:58 +0000 (07:04 -0400)
committerPhilip Joseph <philip.joseph@riftio.com>
Mon, 26 Sep 2016 11:04:58 +0000 (07:04 -0400)
Signed-off-by: Philip Joseph <philip.joseph@riftio.com>
common/python/rift/mano/config_agent/operdata.py
common/python/rift/mano/utils/juju_api.py
rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCM_rpc.py
rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py
rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py

index 6bbf7f2..551aea2 100644 (file)
@@ -428,7 +428,10 @@ class ConfigAgentJobMonitor(object):
             for primitive in vnfr.primitive:
                 if primitive.execution_status == "failure":
                     errs += '<error>'
-                    errs += primitive.execution_error_details
+                    if primitive.execution_error_details:
+                        errs += primitive.execution_error_details
+                    else:
+                        errs += '{}: Unknown error'.format(primitive.name)
                     errs += "</error>"
 
         return errs
@@ -516,13 +519,21 @@ class ConfigAgentJobMonitor(object):
         job_status = []
 
         for primitive in vnfr.primitive:
+            if primitive.execution_status != 'pending':
+                continue
+
             if primitive.execution_id == "":
-                # TODO: For some config data, the id will be empty, check if
-                # mapping is needed.
+                # Actions which failed to queue can have empty id
                 job_status.append(primitive.execution_status)
                 continue
 
-            task = self.loop.create_task(self.get_primitive_status(primitive))
+            elif primitive.execution_id == "config":
+                # Config job. Check if service is active
+                task = self.loop.create_task(self.get_service_status(vnfr.id, primitive))
+
+            else:
+                task = self.loop.create_task(self.get_primitive_status(primitive))
+
             tasks.append(task)
 
         if tasks:
@@ -541,6 +552,35 @@ class ConfigAgentJobMonitor(object):
             vnfr.vnf_job_status = "success"
             return "success"
 
+    @asyncio.coroutine
+    def get_service_status(self, vnfr_id, primitive):
+        try:
+            status = yield from self.loop.run_in_executor(
+                self.executor,
+                self.config_plugin.get_service_status,
+                vnfr_id
+            )
+
+            self.log.debug("Service status: {}".format(status))
+            if status in ['error', 'blocked']:
+                self.log.warning("Execution of config {} failed: {}".
+                                 format(primitive.execution_id, status))
+                primitive.execution_error_details = 'Config failed'
+                status = 'failure'
+            elif status in ['active']:
+                status = 'success'
+            elif status is None:
+                status = 'failure'
+            else:
+                status = 'pending'
+
+        except Exception as e:
+            self.log.exception(e)
+            status = "failed"
+
+        primitive.execution_status = status
+        return primitive.execution_status
+
     @asyncio.coroutine
     def get_primitive_status(self, primitive):
         """
@@ -706,6 +746,15 @@ class ConfigAgentJobManager(object):
         self.log.debug("Creating a job monitor for Job id: {}".format(
                 rpc_output.job_id))
 
+        # If the tasks are none, assume juju actions
+        # TBD: This logic need to be revisited
+        ca = self.nsm.config_agent_plugins[0]
+        if tasks is None:
+            for agent in self.nsm.config_agent_plugins:
+                if agent.agent_type == 'juju':
+                    ca = agent
+                    break
+
         # For every Job we will schedule a new monitoring process.
         job_monitor = ConfigAgentJobMonitor(
             self.dts,
@@ -713,7 +762,7 @@ class ConfigAgentJobManager(object):
             self.jobs[nsr_id],
             self.executor,
             self.loop,
-            self.nsm.config_agent_plugins[0]  # Hack
+            ca
             )
         task = self.loop.create_task(job_monitor.publish_action_status())
 
index 3d7b369..7ba5304 100644 (file)
@@ -693,9 +693,7 @@ class JujuApi(object):
                     except Exception as e:
                         msg = "{}: Resolve on unit {}: {}". \
                               format(self, unit, e)
-                        self.log.error(msg)
-                        self.log.exception(e)
-                        raise JujuResolveError(msg)
+                        self.log.warn(msg)
 
     @asyncio.coroutine
     def resolve_error(self, service=None, status=None, env=None):
index 03756d8..91bc1ab 100644 (file)
@@ -146,7 +146,7 @@ class RiftCMRPCHandler(object):
 
             for vnfr_id in agent_nsr.vnfr_ids:
                 vnfr = agent_vnfrs[vnfr_id]
-                self._log.debug("CA_RPC: VNFR metadata: {}".format(vnfr))
+                self._log.debug("CA-RPC: VNFR metadata: {}".format(vnfr))
 
                 # index->vnfr ref
                 vnfr_index_map[vnfr.member_vnf_index] = vnfr_id
@@ -189,8 +189,12 @@ class RiftCMRPCHandler(object):
                     for primitive in vnfr.vnf_configuration['initial_config_primitive']:
                         if 'parameter' in primitive:
                             for parameter in primitive['parameter']:
-                               value = xlate(parameter['value'], vnfr.tags)
-                               param_data[parameter.name] = value
+                                try:
+                                    value = xlate(parameter['value'], vnfr.tags)
+                                    param_data[parameter['name']] = value
+                                except KeyError as e:
+                                    self._log.warn("Unable to parse the parameter{}:  {}".
+                                                   format(parameter))
 
                 initial_params[vnfr_id] = param_data
 
@@ -207,7 +211,7 @@ class RiftCMRPCHandler(object):
                     return config_plugin.agent_data
             return ret
 
-        unit_names, init_data, vnfr_index_map, vnf_data_map = get_meta(agent_nsr, agent_vnfrs)
+        unit_names, init_data, vnfr_index_map, vnfr_data_map = get_meta(agent_nsr, agent_vnfrs)
 
         # The data consists of 4 sections
         # 1. Account data
@@ -227,7 +231,7 @@ class RiftCMRPCHandler(object):
             tmp_file.write(yaml.dump(data, default_flow_style=True)
                     .encode("UTF-8"))
 
-        self._log.debug("CA_RPC: Creating a temp file {} with input data: {}".
+        self._log.debug("CA-RPC: Creating a temp file {} with input data: {}".
                         format(tmp_file.name, data))
 
         # Get the full path to the script
@@ -238,12 +242,12 @@ class RiftCMRPCHandler(object):
         else:
             script = os.path.join(self._rift_artif_dir, 'launchpad/libs', agent_nsr.id, 'scripts',
                                   rpc_ip.user_defined_script)
-            self.log.debug("CA_RPC: Checking for script in %s", script)
+            self._log.debug("CA-RPC: Checking for script in %s", script)
             if not os.path.exists(script):
                 script = os.path.join(self._rift_install_dir, 'usr/bin', rpc_ip.user_defined_script)
 
         cmd = "{} {}".format(rpc_ip.user_defined_script, tmp_file.name)
-        self._log.debug("CA_RPC: Running the CMD: {}".format(cmd))
+        self._log.debug("CA-RPC: Running the CMD: {}".format(cmd))
 
         coro = asyncio.create_subprocess_shell(cmd, loop=self._loop,
                                                stderr=asyncio.subprocess.PIPE)
index 1f0ed8e..dce31c3 100644 (file)
 #
 
 import asyncio
+import os
 import re
 import tempfile
+import time
 import yaml
-import os
 
 import rift.mano.utils.juju_api as juju
 from . import riftcm_config_plugin
@@ -300,10 +301,6 @@ class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
     def vnf_config_primitive(self, nsr_id, vnfr_id, primitive, output):
         self._log.debug("jujuCA: VNF config primititve {} for nsr {}, vnfr_id {}".
                         format(primitive, nsr_id, vnfr_id))
-        output.execution_status = "failed"
-        output.execution_id = ''
-        output.execution_error_details = ''
-
         try:
             vnfr = self._juju_vnfs[vnfr_id].vnfr
         except KeyError:
@@ -311,6 +308,10 @@ class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
                             vnfr_id)
             return
 
+        output.execution_status = "failed"
+        output.execution_id = ''
+        output.execution_error_details = ''
+
         try:
             service = vnfr['vnf_juju_name']
             vnf_config = vnfr['config']
@@ -340,14 +341,16 @@ class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
                             params.update({parameter.name: val})
 
                     if config.name == 'config':
+                        output.execution_id = 'config'
                         if len(params):
                             self._log.debug("jujuCA: applying config with params {} for service {}".
                                             format(params, service))
 
-                            rc = yield from self.api.apply_config(params, service=service)
+                            rc = yield from self.api.apply_config(params, service=service, wait=False)
 
                             if rc:
-                                output.execution_status = "completed"
+                                # Mark as pending and check later for the status
+                                output.execution_status = "pending"
                                 self._log.debug("jujuCA: applied config {} on {}".
                                                 format(params, service))
                             else:
@@ -357,8 +360,9 @@ class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
                                 self._log.error("jujuCA: Error applying config {} on service {}".
                                                 format(params, service))
                         else:
-                            self._log.warn("jujuCA: Did not find valid paramaters for config : {}".
+                            self._log.warn("jujuCA: Did not find valid parameters for config : {}".
                                            format(primitive.parameter))
+                            output.execution_status = "completed"
                     else:
                         self._log.debug("jujuCA: Execute action {} on service {} with params {}".
                                         format(config.name, service, params))
@@ -550,8 +554,8 @@ class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
                     resp = yield from self.api.execute_action(action, params,
                                                               service=service)
                     if 'error' in resp:
-                        self._log.error("Applying initial config failed for {} with {}: {}".
-                                        format(action, params, resp))
+                        self._log.error("Applying initial config on {} failed for {} with {}: {}".
+                                        format(vnfr['vnf_juju_name'], action, params, resp))
                         return False
 
                     action_ids.append(resp['action']['tag'])
@@ -672,3 +676,18 @@ class JujuConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase):
                             execution_id)
             self._log.exception(e)
             raise e
+
+    def get_service_status(self, vnfr_id):
+        '''Get the service status, used by job status handle
+           Make sure this is NOT a coroutine
+        '''
+        service = self.get_service_name(vnfr_id)
+        if service is None:
+            self._log.error("jujuCA: VNFR {} not managed by this Juju agent".
+                            format(vnfr_id))
+            return None
+
+        # Delay for 3 seconds before checking as config apply takes a
+        # few seconds to transfer to the service
+        time.sleep(3)
+        return self.api._get_service_status(service=service)
index 4d0c700..f285afd 100644 (file)
@@ -271,6 +271,10 @@ class RiftCMConfigPluginBase(object):
         """ Add VNR to be managed by this config agent """
         pass
 
+    def get_service_status(self, vnfr_id):
+        """Get the status of the service"""
+        return None
+
     @asyncio.coroutine
     def invoke(self, method, *args):
         try: