update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / rwcm / plugins / rwconman / rift / tasklets / rwconmantasklet / RiftCA.py
index 267d6df..5d29c31 100644 (file)
@@ -1,4 +1,4 @@
-# 
+#
 #   Copyright 2016 RIFT.IO Inc
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 
 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'