X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=rwcm%2Fplugins%2Frwconman%2Frift%2Ftasklets%2Frwconmantasklet%2FRiftCA.py;h=5d29c31e7b9679444a567fe05447c6bfe6f3805d;hb=f314b4af9744068a7ed7a6a6314220c3aa857523;hp=267d6df4d838076b4981420c145e4be86b5446f7;hpb=6f1a3fe149e4a6b9803382cb299c902f4cf58ec9;p=osm%2FSO.git diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py index 267d6df4..5d29c31e 100644 --- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py +++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py @@ -1,4 +1,4 @@ -# +# # Copyright 2016 RIFT.IO Inc # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,34 +16,32 @@ import asyncio import concurrent.futures +import os import re +import shlex import tempfile import yaml -import os from gi.repository import ( RwDts as rwdts, ) from . import riftcm_config_plugin -from . import rwconman_events as Events class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): """ Implementation of the riftcm_config_plugin.RiftCMConfigPluginBase """ - def __init__(self, dts, log, loop, account): - riftcm_config_plugin.RiftCMConfigPluginBase.__init__(self, dts, log, loop, account) + def __init__(self, dts, log, loop, project, account): + riftcm_config_plugin.RiftCMConfigPluginBase.__init__(self, dts, log, + loop, project, account) self._name = account.name self._type = riftcm_config_plugin.DEFAULT_CAP_TYPE self._rift_install_dir = os.environ['RIFT_INSTALL'] - self._rift_artif_dir = os.environ['RIFT_ARTIFACTS'] + self._rift_var_root_dir = os.environ['RIFT_VAR_ROOT'] self._rift_vnfs = {} self._tasks = {} - # Instantiate events that will handle RiftCA configuration requests - self._events = Events.ConfigManagerEvents(dts, log, loop, self) - @property def name(self): return self._name @@ -94,7 +92,7 @@ class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): def riftca_log(self, name, level, log_str, *args): getattr(self._log, level)('RiftCA:({}) {}'.format(name, log_str), *args) - + @asyncio.coroutine def notify_create_vnfr(self, agent_nsr, agent_vnfr): """ @@ -140,12 +138,131 @@ class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): pass @asyncio.coroutine - def vnf_config_primitive(self, agent_nsr, agent_vnfr, primitive, output): + def _vnf_config_primitive(self, nsr_id, vnfr_id, primitive, + vnf_config=None, vnfd_descriptor=None): + ''' + Pass vnf_config to avoid querying DTS each time + ''' + self._log.debug("VNF config primitive {} for nsr {}, vnfr {}". + format(primitive.name, nsr_id, vnfr_id)) + + if vnf_config is None or vnfd_descriptor is None: + vnfr_msg = yield from self.get_vnfr(vnfr_id) + if vnfr_msg is None: + msg = "Unable to get VNFR {} through DTS".format(vnfr_id) + self._log.error(msg) + return 3, msg + + vnf_config = vnfr_msg.vnf_configuration + vnfd_descriptor = vnfr_msg.vnfd + self._log.debug("VNF config= %s", vnf_config.as_dict()) + self._log.debug("VNFD descriptor= %s", vnfd_descriptor.as_dict()) + + data = {} + script = None + found = False + + configs = vnf_config.config_primitive + for config in configs: + if config.name == primitive.name: + found = True + self._log.debug("RiftCA: Found the config primitive %s", + config.name) + + spt = config.user_defined_script + if spt is None: + self._log.error("RiftCA: VNFR {}, Did not find " + "script defined in config {}". + format(vnfr['name'], config.as_dict())) + return 1, "Did not find user defined script for " \ + "config primitive {}".format(primitive.name) + + spt = shlex.quote(spt.strip()) + if spt[0] == '/': + script = spt + else: + script = os.path.join(self._rift_var_root_dir, + 'launchpad/packages/vnfd', + self._project.name, + vnfd_descriptor.id, + 'scripts', + spt) + self._log.debug("Rift config agent: Checking for script " + "in %s", script) + if not os.path.exists(script): + self._log.debug("Rift config agent: Did not find " + "script %s", script) + return 1, "Did not find user defined " \ + "script {}".format(spt) + + params = {} + for param in config.parameter: + val = None + for p in primitive.parameter: + if p.name == param.name: + val = p.value + break + + if val is None: + val = param.default_value + + if val is None: + # Check if mandatory parameter + if param.mandatory: + msg = "VNFR {}: Primitive {} called " \ + "without mandatory parameter {}". \ + format(vnfr.name, config.name, + param.name) + self._log.error(msg) + return 1, msg + + if val: + val = self.convert_value(val, param.data_type) + params.update({param.name: val}) + + data['parameters'] = params + break + + if not found: + msg = "Did not find the primitive {} in VNFR {}". \ + format(primitive.name, vnfr.name) + self._log.error(msg) + return 1, msg + + rc, script_err = yield from self.exec_script(script, data) + return rc, script_err + + @asyncio.coroutine + def vnf_config_primitive(self, nsr_id, vnfr_id, primitive, output): ''' primitives support by RiftCA + + Pass vnf_config to avoid querying DTS each time ''' - pass - + try: + vnfr = self._rift_vnfs[vnfr_id].vnfr + except KeyError: + msg = "Did not find VNFR {} in Rift plugin".format(vnfr_id) + self._log.debug(msg) + return + + output.execution_status = "failed" + output.execution_id = '' + output.execution_error_details = '' + + rc, err = yield from self._vnf_config_primitive(nsr_id, + vnfr_id, + primitive) + self._log.debug("VNFR {} primitive {} exec status: {}". + format(vnfr_id, primitive.name, rc)) + + if rc == 0: + output.execution_status = "completed" + else: + self._rift_vnfs[vnfr_id].error = True + + output.execution_error_details = '{}'.format(err) + @asyncio.coroutine def apply_config(self, config, nsr, vnfr, rpc_ip): """ Notification on configuration of an NSR """ @@ -189,11 +306,18 @@ class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): vnfr_data_dict['mgmt_interface'] = vnfr.vnfr['mgmt_interface'] vnfr_data_dict['connection_point'] = [] + vnfr_data_dict['name'] = vnfr.vnfr['name'] + vnfr_data_dict['datacenter'] = vnfr.vnfr['datacenter'] if 'connection_point' in vnfr.vnfr: for cp in vnfr.vnfr['connection_point']: cp_dict = dict() cp_dict['name'] = cp['name'] cp_dict['ip_address'] = cp['ip_address'] + cp_dict['connection_point_id'] = cp['connection_point_id'] + if 'virtual_cps' in cp: + cp_dict['virtual_cps'] = [ {k:v for k,v in vcp.items() + if k in ['ip_address', 'mac_address']} + for vcp in cp['virtual_cps'] ] vnfr_data_dict['connection_point'].append(cp_dict) vnfr_data_dict['vdur'] = [] @@ -235,7 +359,7 @@ class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): data["init_config"] = init_data data["vnfr_index_map"] = vnfr_index_map data["vnfr_data_map"] = vnfr_data_map - + tmp_file = None with tempfile.NamedTemporaryFile(delete=False) as tmp_file: tmp_file.write(yaml.dump(data, default_flow_style=True) @@ -247,12 +371,14 @@ class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): # The script has full path, use as is script = rpc_ip.user_defined_script else: - script = os.path.join(self._rift_artif_dir, 'launchpad/libs', agent_nsr.nsd_id, 'scripts', + script = os.path.join(self._rift_var_root_dir, + 'launchpad/packages/nsd', + self._project.name, + agent_nsr.nsd_id, 'scripts', rpc_ip.user_defined_script) self._log.debug("Rift config agent: Checking for script in %s", script) if not os.path.exists(script): - self._log.debug("Rift config agent: Did not find scipt %s", script) - script = os.path.join(self._rift_install_dir, 'usr/bin', rpc_ip.user_defined_script) + self._log.error("Rift config agent: Did not find script %s", script) cmd = "{} {}".format(script, tmp_file.name) self._log.debug("Rift config agent: Running the CMD: {}".format(cmd)) @@ -265,31 +391,97 @@ class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): return task, err + @asyncio.coroutine + def apply_initial_config_new(self, agent_nsr, agent_vnfr): + self._log.debug("RiftCA: VNF initial config primitive for nsr {}, vnfr {}". + format(agent_nsr.name, agent_vnfr.name)) + + try: + vnfr = self._rift_vnfs[agent_vnfr.id].vnfr + except KeyError: + self._log.error("RiftCA: Did not find VNFR %s in RiftCA plugin", + agent_vnfr.name) + return False + + class Primitive: + def __init__(self, name): + self.name = name + self.value = None + self.parameter = [] + + vnfr = yield from self.get_vnfr(agent_vnfr.id) + if vnfr is None: + msg = "Unable to get VNFR {} ({}) through DTS". \ + format(agent_vnfr.id, agent_vnfr.name) + self._log.error(msg) + raise RuntimeError(msg) + + vnf_config = vnfr.vnf_configuration + self._log.debug("VNFR %s config: %s", vnfr.name, + vnf_config.as_dict()) + + vnfd_descriptor = vnfr.vnfd + self._log.debug("VNFR %s vnfd descriptor: %s", vnfr.name, + vnfd_descriptor.as_dict()) + + + # Sort the primitive based on the sequence number + primitives = sorted(vnf_config.initial_config_primitive, + key=lambda k: k.seq) + if not primitives: + self._log.debug("VNFR {}: No initial-config-primitive specified". + format(vnfr.name)) + return True + + for primitive in primitives: + if primitive.config_primitive_ref: + # Reference to a primitive in config primitive + prim = Primitive(primitive.config_primitive_ref) + rc, err = yield from self._vnf_config_primitive(agent_nsr.id, + agent_vnfr.id, + prim, + vnf_config, vnfd_descriptor) + if rc != 0: + msg = "Error executing initial config primitive" \ + " {} in VNFR {}: rc={}, stderr={}". \ + format(prim.name, vnfr.name, rc, err) + self._log.error(msg) + return False + + elif primitive.name: + if not primitive.user_defined_script: + msg = "Primitive {} definition in initial config " \ + "primitive for VNFR {} not supported yet". \ + format(primitive.name, vnfr.name) + self._log.error(msg) + raise NotImplementedError(msg) + + return True + @asyncio.coroutine def apply_initial_config(self, agent_nsr, agent_vnfr): """ Apply the initial configuration """ - rc = False self._log.debug("Rift config agent: Apply initial config to VNF:%s/%s", agent_nsr.name, agent_vnfr.name) + rc = False + try: if agent_vnfr.id in self._rift_vnfs.keys(): - # Check if VNF instance is configurable (TBD - future) - ### Remove this once is_vnf_configurable() is implemented - agent_vnfr.set_to_configurable() - if agent_vnfr.is_configurable: - # apply initial config for the vnfr - rc = yield from self._events.apply_vnf_config(agent_vnfr.vnf_cfg) - else: - self._log.info("Rift config agent: VNF:%s/%s is not configurable yet!", - agent_nsr.name, agent_vnfr.name) + rc = yield from self.apply_initial_config_new(agent_nsr, agent_vnfr) + if not rc: + agent_vnfr._error = True + + else: + rc = True except Exception as e: self._log.error("Rift config agent: Error on initial configuration to VNF:{}/{}, e {}" .format(agent_nsr.name, agent_vnfr.name, str(e))) - + self._log.exception(e) - return rc + agent_vnfr.error = True + return False return rc @@ -310,6 +502,8 @@ class RiftCAConfigPlugin(riftcm_config_plugin.RiftCMConfigPluginBase): @asyncio.coroutine def get_config_status(self, agent_nsr, agent_vnfr): if agent_vnfr.id in self._rift_vnfs.keys(): + if agent_vnfr.error: + return 'error' return 'configured' return 'unknown'