X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=rwcm%2Fplugins%2Frwconman%2Frift%2Ftasklets%2Frwconmantasklet%2FRiftCA.py;fp=rwcm%2Fplugins%2Frwconman%2Frift%2Ftasklets%2Frwconmantasklet%2FRiftCA.py;h=4a95a7da12788f84bba3824162afdad135f83c6d;hb=6f07e6f33f751ab4ffe624f6037f887b243bece2;hp=0000000000000000000000000000000000000000;hpb=72a563886272088feb7cb52e4aafbe6d2c580ff9;p=osm%2FSO.git diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py new file mode 100644 index 00000000..4a95a7da --- /dev/null +++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/RiftCA.py @@ -0,0 +1,299 @@ +# +# Copyright 2016 RIFT.IO Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import asyncio +import concurrent.futures +import re +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) + 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_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 + + @property + def agent_type(self): + return self._type + + @asyncio.coroutine + def notify_create_vlr(self, agent_nsr, agent_vnfr, vld, vlr): + """ + Notification of create VL record + """ + pass + + @asyncio.coroutine + def is_vnf_configurable(self, agent_vnfr): + ''' + This needs to be part of abstract class + ''' + loop_count = 10 + while loop_count: + loop_count -= 1 + # Set this VNF's configurability status (need method to check) + yield from asyncio.sleep(2, loop=self._loop) + + 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): + """ + Notification of create Network VNF record + """ + # Deploy the charm if specified for the vnf + self._log.debug("Rift config agent: create vnfr nsr={} vnfr={}" + .format(agent_nsr.name, agent_vnfr.name)) + try: + self._loop.create_task(self.is_vnf_configurable(agent_vnfr)) + except Exception as e: + self._log.debug("Rift config agent: vnf_configuration error for VNF:%s/%s: %s", + agent_nsr.name, agent_vnfr.name, str(e)) + return False + + return True + + @asyncio.coroutine + def notify_instantiate_vnfr(self, agent_nsr, agent_vnfr): + """ + Notification of Instantiate NSR with the passed nsr id + """ + pass + + @asyncio.coroutine + def notify_instantiate_vlr(self, agent_nsr, agent_vnfr, vlr): + """ + Notification of Instantiate NSR with the passed nsr id + """ + pass + + @asyncio.coroutine + def notify_terminate_vnfr(self, agent_nsr, agent_vnfr): + """ + Notification of Terminate the network service + """ + + @asyncio.coroutine + def notify_terminate_vlr(self, agent_nsr, agent_vnfr, vlr): + """ + Notification of Terminate the virtual link + """ + pass + + @asyncio.coroutine + def vnf_config_primitive(self, agent_nsr, agent_vnfr, primitive, output): + ''' + primitives support by RiftCA + ''' + pass + + @asyncio.coroutine + def apply_config(self, config, nsr, vnfr, rpc_ip): + """ Notification on configuration of an NSR """ + pass + + @asyncio.coroutine + def apply_ns_config(self, agent_nsr, agent_vnfrs, rpc_ip): + """Hook: Runs the user defined script. Feeds all the necessary data + for the script thro' yaml file. + + Args: + rpc_ip (YangInput_Nsr_ExecNsConfigPrimitive): The input data. + nsr (NetworkServiceRecord): Description + vnfrs (dict): VNFR ID => VirtualNetworkFunctionRecord + """ + + def xlate(tag, tags): + # TBD + if tag is None or tags is None: + return tag + val = tag + if re.search('<.*>', tag): + try: + if tag == '': + val = tags['rw_mgmt_ip'] + except KeyError as e: + self._log.info("RiftCA: Did not get a value for tag %s, e=%s", + tag, e) + return val + + def get_meta(agent_nsr, agent_vnfrs): + unit_names, initial_params, vnfr_index_map, vnfr_data_map = {}, {}, {}, {} + + for vnfr_id in agent_nsr.vnfr_ids: + vnfr = agent_vnfrs[vnfr_id] + + # index->vnfr ref + vnfr_index_map[vnfr.member_vnf_index] = vnfr_id + vnfr_data_dict = dict() + if 'mgmt_interface' in vnfr.vnfr: + vnfr_data_dict['mgmt_interface'] = vnfr.vnfr['mgmt_interface'] + + vnfr_data_dict['connection_point'] = [] + 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'] + vnfr_data_dict['connection_point'].append(cp_dict) + + vnfr_data_dict['vdur'] = [] + vdu_data = [(vdu['name'], vdu['management_ip'], vdu['vm_management_ip'], vdu['id']) + for vdu in vnfr.vnfr['vdur']] + + for data in vdu_data: + data = dict(zip(['name', 'management_ip', 'vm_management_ip', 'id'] , data)) + vnfr_data_dict['vdur'].append(data) + + vnfr_data_map[vnfr.member_vnf_index] = vnfr_data_dict + # Unit name + unit_names[vnfr_id] = vnfr.name + # Flatten the data for simplicity + param_data = {} + if 'initial_config_primitive' in vnfr.vnf_configuration: + for primitive in vnfr.vnf_configuration['initial_config_primitive']: + for parameter in primitive.parameter: + value = xlate(parameter.value, vnfr.tags) + param_data[parameter.name] = value + + initial_params[vnfr_id] = param_data + + + return unit_names, initial_params, vnfr_index_map, vnfr_data_map + + 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 + # 2. The input passed. + # 3. Unit names (keyed by vnfr ID). + # 4. Initial config data (keyed by vnfr ID). + data = dict() + data['config_agent'] = dict( + name=self._name, + ) + data["rpc_ip"] = rpc_ip.as_dict() + data["unit_names"] = unit_names + 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) + .encode("UTF-8")) + + # Get the full path to the script + script = '' + if rpc_ip.user_defined_script[0] == '/': + # 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', + 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) + + cmd = "{} {}".format(script, tmp_file.name) + self._log.debug("Rift config agent: Running the CMD: {}".format(cmd)) + + coro = asyncio.create_subprocess_shell(cmd, loop=self._loop, + stderr=asyncio.subprocess.PIPE) + process = yield from coro + err = yield from process.stderr.read() + task = self._loop.create_task(process.wait()) + + return task, err + + @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) + 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) + 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 + + return rc + + def is_vnfr_managed(self, vnfr_id): + try: + if vnfr_id in self._rift_vnfs: + return True + except Exception as e: + self._log.debug("Rift config agent: Is VNFR {} managed: {}". + format(vnfr_id, e)) + return False + + def add_vnfr_managed(self, agent_vnfr): + if agent_vnfr.id not in self._rift_vnfs.keys(): + self._log.info("Rift config agent: add vnfr={}/{}".format(agent_vnfr.name, agent_vnfr.id)) + self._rift_vnfs[agent_vnfr.id] = agent_vnfr + + @asyncio.coroutine + def get_config_status(self, agent_nsr, agent_vnfr): + if agent_vnfr.id in self._rift_vnfs.keys(): + return 'configured' + return 'unknown' + + + def get_action_status(self, execution_id): + ''' Get the action status for an execution ID + *** Make sure this is NOT a asyncio coroutine function *** + ''' + return None