--- /dev/null
+#
+# 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 == '<rw_mgmt_ip>':
+ 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