From 9e86badd6a6b11888cd247d8f5ccf1d428682ea9 Mon Sep 17 00:00:00 2001 From: Philip Joseph Date: Mon, 26 Sep 2016 07:04:58 -0400 Subject: [PATCH] Fix for service primitive execution and status Signed-off-by: Philip Joseph --- .../python/rift/mano/config_agent/operdata.py | 59 +++++++++++++++++-- common/python/rift/mano/utils/juju_api.py | 4 +- .../tasklets/rwconmantasklet/RiftCM_rpc.py | 18 +++--- .../rift/tasklets/rwconmantasklet/jujuconf.py | 39 ++++++++---- .../rwconmantasklet/riftcm_config_plugin.py | 4 ++ 5 files changed, 99 insertions(+), 25 deletions(-) diff --git a/common/python/rift/mano/config_agent/operdata.py b/common/python/rift/mano/config_agent/operdata.py index 6bbf7f25..551aea2d 100644 --- a/common/python/rift/mano/config_agent/operdata.py +++ b/common/python/rift/mano/config_agent/operdata.py @@ -428,7 +428,10 @@ class ConfigAgentJobMonitor(object): for primitive in vnfr.primitive: if primitive.execution_status == "failure": errs += '' - errs += primitive.execution_error_details + if primitive.execution_error_details: + errs += primitive.execution_error_details + else: + errs += '{}: Unknown error'.format(primitive.name) errs += "" 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()) diff --git a/common/python/rift/mano/utils/juju_api.py b/common/python/rift/mano/utils/juju_api.py index 3d7b369f..7ba53047 100644 --- a/common/python/rift/mano/utils/juju_api.py +++ b/common/python/rift/mano/utils/juju_api.py @@ -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): diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCM_rpc.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCM_rpc.py index 03756d87..91bc1ab5 100644 --- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCM_rpc.py +++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCM_rpc.py @@ -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) diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py index 1f0ed8ef..dce31c3e 100644 --- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py +++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/jujuconf.py @@ -15,10 +15,11 @@ # 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) diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py index 4d0c700e..f285afd7 100644 --- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py +++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/riftcm_config_plugin.py @@ -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: -- 2.25.1