Bug 149
[osm/SO.git] / rwlaunchpad / plugins / rwvnfm / rift / tasklets / rwvnfmtasklet / rwvnfmtasklet.py
index 8a4474e..2bcbecc 100755 (executable)
@@ -49,6 +49,7 @@ from gi.repository import (
 import rift.tasklets
 import rift.package.store
 import rift.package.cloud_init
+import rift.package.script
 import rift.mano.dts as mano_dts
 
 
@@ -311,6 +312,14 @@ class VirtualDeploymentUnitRecord(object):
                     return conn_point.ip_address
         return "0.0.0.0"
 
+    def cp_mac_addr(self, cp_name):
+        """ Find mac address by connection point name """
+        if self._vm_resp is not None:
+            for conn_point in self._vm_resp.connection_points:
+                if conn_point.name == cp_name:
+                    return conn_point.mac_addr
+        return "00:00:00:00:00:00"
+
     def cp_id(self, cp_name):
         """ Find connection point id  by connection point name """
         if self._vm_resp is not None:
@@ -376,7 +385,7 @@ class VirtualDeploymentUnitRecord(object):
 
     @property
     def msg(self):
-        """ VDU message """
+        """ Process VDU message from resmgr"""
         vdu_fields = ["vm_flavor",
                       "guest_epa",
                       "vswitch_epa",
@@ -412,6 +421,26 @@ class VirtualDeploymentUnitRecord(object):
                     vdurvol_data = [vduvol for vduvol in vdur_dict['volumes'] if vduvol['name'] == opvolume.name]
                     if len(vdurvol_data) == 1:
                        vdurvol_data[0]["volume_id"] = opvolume.volume_id
+                       if opvolume.has_field('custom_meta_data'):
+                           metadata_list = list()
+                           for metadata_item in opvolume.custom_meta_data:
+                               metadata_list.append(metadata_item.as_dict())
+                           vdurvol_data[0]['custom_meta_data'] = metadata_list
+
+            if self._vm_resp.has_field('supplemental_boot_data'):
+                vdur_dict['supplemental_boot_data'] = dict()
+                if self._vm_resp.supplemental_boot_data.has_field('boot_data_drive'):
+                    vdur_dict['supplemental_boot_data']['boot_data_drive'] = self._vm_resp.supplemental_boot_data.boot_data_drive
+                if self._vm_resp.supplemental_boot_data.has_field('custom_meta_data'):
+                    metadata_list = list()
+                    for metadata_item in self._vm_resp.supplemental_boot_data.custom_meta_data:
+                       metadata_list.append(metadata_item.as_dict())
+                    vdur_dict['supplemental_boot_data']['custom_meta_data'] = metadata_list
+                if self._vm_resp.supplemental_boot_data.has_field('config_file'):
+                    file_list = list()
+                    for file_item in self._vm_resp.supplemental_boot_data.config_file:
+                       file_list.append(file_item.as_dict())
+                    vdur_dict['supplemental_boot_data']['config_file'] = file_list
 
         icp_list = []
         ii_list = []
@@ -422,7 +451,8 @@ class VirtualDeploymentUnitRecord(object):
             icp_list.append({"name": cp.name,
                              "id": cp.id,
                              "type_yang": "VPORT",
-                             "ip_address": self.cp_ip_addr(cp.id)})
+                             "ip_address": self.cp_ip_addr(cp.id),
+                             "mac_address": self.cp_mac_addr(cp.id)})
 
             ii_list.append({"name": intf.name,
                             "vdur_internal_connection_point_ref": cp.id,
@@ -434,10 +464,13 @@ class VirtualDeploymentUnitRecord(object):
 
         ei_list = []
         for intf, cp, vlr in self._ext_intf:
-            ei_list.append({"name": cp,
-                            "vnfd_connection_point_ref": cp,
+            ei_list.append({"name": cp.name,
+                            "vnfd_connection_point_ref": cp.name,
                             "virtual_interface": {}})
-            self._vnfr.update_cp(cp, self.cp_ip_addr(cp), self.cp_id(cp))
+            self._vnfr.update_cp(cp.name,
+                                 self.cp_ip_addr(cp.name),
+                                 self.cp_mac_addr(cp.name),
+                                 self.cp_id(cp.name))
 
         vdur_dict["external_interface"] = ei_list
 
@@ -488,6 +521,7 @@ class VirtualDeploymentUnitRecord(object):
             try:
                 return cloud_init_extractor.read_script(stored_package, filename)
             except rift.package.cloud_init.CloudInitExtractionError as e:
+                self.instantiation_failed(str(e))
                 raise VirtualDeploymentUnitRecordError(e)
         else:
             self._log.debug("VDU Instantiation: cloud-init script not provided")
@@ -540,12 +574,37 @@ class VirtualDeploymentUnitRecord(object):
             self._log.info("Ignoring placement group with cloud construct for cloud-type: %s", cloud_type)
         return
 
+    def process_custom_bootdata(self, vm_create_msg_dict):
+        """Process the custom boot data"""
+        if 'config_file' not in vm_create_msg_dict['supplemental_boot_data']:
+            return
+
+        self._vnfd_package_store.refresh()
+        stored_package = self._vnfd_package_store.get_package(self._vnfr.vnfd_id)
+        cloud_init_extractor = rift.package.cloud_init.PackageCloudInitExtractor(self._log)
+        for file_item in vm_create_msg_dict['supplemental_boot_data']['config_file']:
+            if 'source' not in file_item or 'dest' not in file_item:
+                continue
+            source = file_item['source']
+            # Find source file in scripts dir of VNFD
+            self._log.debug("Checking for source config file at %s", source)
+            try:
+               source_file_str = cloud_init_extractor.read_script(stored_package, source)
+            except rift.package.cloud_init.CloudInitExtractionError as e:
+               raise  VirtualDeploymentUnitRecordError(e)
+            # Update source file location with file contents
+            file_item['source'] = source_file_str
+
+        return
+
     def resmgr_msg(self, config=None):
         vdu_fields = ["vm_flavor",
                       "guest_epa",
                       "vswitch_epa",
                       "hypervisor_epa",
-                      "host_epa"]
+                      "host_epa",
+                      "volumes",
+                      "supplemental_boot_data"]
 
         self._log.debug("Creating params based on VDUD: %s", self._vdud)
         vdu_copy_dict = {k: v for k, v in self._vdud.as_dict().items() if k in vdu_fields}
@@ -573,9 +632,10 @@ class VirtualDeploymentUnitRecord(object):
 
         cp_list = []
         for intf, cp, vlr in self._ext_intf:
-            cp_info = {"name": cp,
+            cp_info = {"name": cp.name,
                        "virtual_link_id": vlr.network_id,
-                       "type_yang": intf.virtual_interface.type_yang}
+                       "type_yang": intf.virtual_interface.type_yang,
+                       "port_security_enabled": cp.port_security_enabled}
 
             if (intf.virtual_interface.has_field('vpci') and
                     intf.virtual_interface.vpci is not None):
@@ -596,21 +656,21 @@ class VirtualDeploymentUnitRecord(object):
             else:
                 cp_list.append({"name": cp,
                                 "virtual_link_id": vlr.network_id,
-                                "type_yang": intf.virtual_interface.type_yang})
+                                "type_yang": intf.virtual_interface.type_yang,
+                                "port_security_enabled": cp.port_security_enabled})
 
         vm_create_msg_dict["connection_points"] = cp_list
         vm_create_msg_dict.update(vdu_copy_dict)
 
         self.process_placement_groups(vm_create_msg_dict)
+        if 'supplemental_boot_data' in vm_create_msg_dict:
+             self.process_custom_bootdata(vm_create_msg_dict) 
 
         msg = RwResourceMgrYang.VDUEventData()
         msg.event_id = self._request_id
         msg.cloud_account = self.cloud_account_name
         msg.request_info.from_dict(vm_create_msg_dict)
 
-        for volume in self._vdud.volumes:
-            v = msg.request_info.volumes.add()
-            v.from_dict(volume.as_dict())
         return msg
 
     @asyncio.coroutine
@@ -722,7 +782,7 @@ class VirtualDeploymentUnitRecord(object):
 
             vlr = vnfr.ext_vlr_by_id(cp.vlr_ref)
 
-            etuple = (ext_intf, cp.name, vlr)
+            etuple = (ext_intf, cp, vlr)
             self._ext_intf.append(etuple)
 
             self._log.debug("Created external interface tuple  : %s", etuple)
@@ -883,8 +943,8 @@ class VirtualDeploymentUnitRecord(object):
 
             vm_resp = yield from self.create_resource(xact, vnfr, config)
             self._vm_resp = vm_resp
-
             self._state = VDURecordState.RESOURCE_ALLOC_PENDING
+
             self._log.debug("Requested VM from resource manager response %s",
                             vm_resp)
             if vm_resp.resource_state == "active":
@@ -927,13 +987,14 @@ class VlRecordState(enum.Enum):
 
 class InternalVirtualLinkRecord(object):
     """ Internal Virtual Link record """
-    def __init__(self, dts, log, loop, ivld_msg, vnfr_name, cloud_account_name):
+    def __init__(self, dts, log, loop, ivld_msg, vnfr_name, cloud_account_name, ip_profile=None):
         self._dts = dts
         self._log = log
         self._loop = loop
         self._ivld_msg = ivld_msg
         self._vnfr_name = vnfr_name
         self._cloud_account_name = cloud_account_name
+        self._ip_profile = ip_profile
 
         self._vlr_req = self.create_vlr()
         self._vlr = None
@@ -947,7 +1008,10 @@ class InternalVirtualLinkRecord(object):
     @property
     def name(self):
         """ Name of this VL """
-        return self._vnfr_name + "." + self._ivld_msg.name
+        if self._ivld_msg.vim_network_name:
+            return self._ivld_msg.vim_network_name
+        else:
+            return self._vnfr_name + "." + self._ivld_msg.name
 
     @property
     def network_id(self):
@@ -966,6 +1030,7 @@ class InternalVirtualLinkRecord(object):
                       "description",
                       "version",
                       "type_yang",
+                      "vim_network_name",
                       "provider_network"]
 
         vld_copy_dict = {k: v for k, v in self._ivld_msg.as_dict().items() if k in vld_fields}
@@ -974,6 +1039,10 @@ class InternalVirtualLinkRecord(object):
                     "name": self.name,
                     "cloud_account": self._cloud_account_name,
                     }
+
+        if self._ip_profile and self._ip_profile.has_field('ip_profile_params'):
+            vlr_dict['ip_profile_params' ] = self._ip_profile.ip_profile_params.as_dict()
+
         vlr_dict.update(vld_copy_dict)
 
         vlr = RwVlrYang.YangData_Vlr_VlrCatalog_Vlr.from_dict(vlr_dict)
@@ -1357,6 +1426,13 @@ class VirtualNetworkFunctionRecord(object):
         self._log.debug("Published VNFR path = [%s], record = [%s]",
                         self.xpath, self.msg)
 
+    def resolve_vld_ip_profile(self, vnfd_msg, vld):
+        self._log.debug("Receieved ip profile ref is %s",vld.ip_profile_ref)
+        if not vld.has_field('ip_profile_ref'):
+            return None
+        profile = [profile for profile in vnfd_msg.ip_profiles if profile.name == vld.ip_profile_ref]
+        return profile[0] if profile else None
+
     @asyncio.coroutine
     def create_vls(self):
         """ Publish The VLs associated with this VNF """
@@ -1372,7 +1448,8 @@ class VirtualNetworkFunctionRecord(object):
                                             loop=self._loop,
                                             ivld_msg=ivld_msg,
                                             vnfr_name=self.name,
-                                            cloud_account_name=self.cloud_account_name
+                                            cloud_account_name=self.cloud_account_name,
+                                            ip_profile=self.resolve_vld_ip_profile(self.vnfd, ivld_msg)
                                             )
             self._vlrs.append(vlr)
 
@@ -1451,6 +1528,10 @@ class VirtualNetworkFunctionRecord(object):
 
         return placement_groups
 
+    @asyncio.coroutine
+    def vdu_cloud_init_instantiation(self):
+        [vdu.vdud_cloud_init for vdu in self._vdus]
+
     @asyncio.coroutine
     def create_vdus(self, vnfr, restart_mode=False):
         """ Create the VDUs associated with this VNF """
@@ -1515,8 +1596,8 @@ class VirtualNetworkFunctionRecord(object):
         vdu_id_pattern = re.compile(r"\{\{ vdu\[([^]]+)\]\S* \}\}")
 
         for vdu in self._vdus:
-            if vdu.vdud_cloud_init is not None:
-                for vdu_id in vdu_id_pattern.findall(vdu.vdud_cloud_init):
+            if vdu._vdud_cloud_init is not None:
+                for vdu_id in vdu_id_pattern.findall(vdu._vdud_cloud_init):
                     if vdu_id != vdu.vdu_id:
                         # This means that vdu.vdu_id depends upon vdu_id,
                         # i.e. vdu_id must be instantiated before
@@ -1544,7 +1625,6 @@ class VirtualNetworkFunctionRecord(object):
             # wait for the VDUR to enter a terminal state
             while vdu._state not in terminal:
                 yield from asyncio.sleep(1, loop=self._loop)
-
             # update the datastore
             datastore.update(vdu)
 
@@ -1706,13 +1786,14 @@ class VirtualNetworkFunctionRecord(object):
         # Update the VNFR with the changed status
         yield from self.publish(None)
 
-    def update_cp(self, cp_name, ip_address, cp_id):
+    def update_cp(self, cp_name, ip_address, mac_addr, cp_id):
         """Updated the connection point with ip address"""
         for cp in self._cprs:
             if cp.name == cp_name:
                 self._log.debug("Setting ip address and id for cp %s, cpr %s with ip %s id %s",
                                 cp_name, cp, ip_address, cp_id)
                 cp.ip_address = ip_address
+                cp.mac_address = mac_addr
                 cp.connection_point_id = cp_id
                 return
 
@@ -1738,7 +1819,7 @@ class VirtualNetworkFunctionRecord(object):
 
             def cpr_from_cp(cp):
                 """ Creates a record level connection point from the desciptor cp"""
-                cp_fields = ["name", "image", "vm-flavor"]
+                cp_fields = ["name", "image", "vm-flavor", "port_security_enabled"]
                 cp_copy_dict = {k: v for k, v in cp.as_dict().items() if k in cp_fields}
                 cpr_dict = {}
                 cpr_dict.update(cp_copy_dict)
@@ -1784,6 +1865,7 @@ class VirtualNetworkFunctionRecord(object):
         self._log.debug("VNFR-ID %s: Publish VNFR", self._vnfr_id)
         yield from self.publish(xact)
 
+
         # instantiate VLs
         self._log.debug("VNFR-ID %s: Instantiate VLs", self._vnfr_id)
         try:
@@ -1799,6 +1881,13 @@ class VirtualNetworkFunctionRecord(object):
         self._log.debug("VNFR-ID %s: Create VDUs", self._vnfr_id)
         yield from self.create_vdus(self, restart_mode)
 
+        try:
+            yield from self.vdu_cloud_init_instantiation()
+        except Exception as e:
+            self.set_state(VirtualNetworkFunctionRecordState.FAILED)
+            self._state_failed_reason = str(e)
+            yield from self.publish(xact)
+
         # publish the VNFR
         self._log.debug("VNFR-ID %s: Publish VNFR", self._vnfr_id)
         yield from self.publish(xact)
@@ -2505,7 +2594,13 @@ class VnfManager(object):
             self._dts, self._log, self._loop, self._cluster_name, self, self.vcs_handler, vnfr,
             mgmt_network=mgmt_network
             )
-        self._vnfds_to_vnfr[vnfr.vnfd.id] = self._vnfrs[vnfr.id]
+
+        #Update ref count
+        if vnfr.vnfd.id in self._vnfds_to_vnfr:
+            self._vnfds_to_vnfr[vnfr.vnfd.id] += 1
+        else:
+            self._vnfds_to_vnfr[vnfr.vnfd.id] = 1
+
         return self._vnfrs[vnfr.id]
 
     @asyncio.coroutine
@@ -2514,6 +2609,11 @@ class VnfManager(object):
         if vnfr.vnfr_id in self._vnfrs:
             self._log.debug("Deleting VNFR id %s", vnfr.vnfr_id)
             yield from self._vnfr_handler.delete(xact, vnfr.xpath)
+
+            if vnfr.vnfd.id in self._vnfds_to_vnfr:
+                if self._vnfds_to_vnfr[vnfr.vnfd.id]:
+                    self._vnfds_to_vnfr[vnfr.vnfd.id] -= 1
+
             del self._vnfrs[vnfr.vnfr_id]
 
     @asyncio.coroutine
@@ -2542,7 +2642,7 @@ class VnfManager(object):
         """ Is this VNFD in use """
         self._log.debug("Is this VNFD in use - msg:%s", vnfd_id)
         if vnfd_id in self._vnfds_to_vnfr:
-            return self._vnfds_to_vnfr[vnfd_id].in_use()
+            return (self._vnfds_to_vnfr[vnfd_id] > 0)
         return False
 
     @asyncio.coroutine
@@ -2556,18 +2656,17 @@ class VnfManager(object):
     def delete_vnfd(self, vnfd_id):
         """ Delete the Virtual Network Function descriptor with the passed id """
         self._log.debug("Deleting the virtual network function descriptor - %s", vnfd_id)
-        if vnfd_id not in self._vnfds_to_vnfr:
-            self._log.debug("Delete VNFD failed - cannot find vnfd-id %s", vnfd_id)
-            raise VirtualNetworkFunctionDescriptorNotFound("Cannot find %s", vnfd_id)
-
-        if self._vnfds_to_vnfr[vnfd_id].in_use():
-            self._log.debug("Cannot delete VNFD id %s reference exists %s",
-                            vnfd_id,
-                            self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count)
-            raise VirtualNetworkFunctionDescriptorRefCountExists(
-                "Cannot delete :%s, ref_count:%s",
-                vnfd_id,
-                self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count)
+        if vnfd_id in self._vnfds_to_vnfr:
+            if self._vnfds_to_vnfr[vnfd_id]:
+                self._log.debug("Cannot delete VNFD id %s reference exists %s",
+                                vnfd_id,
+                                self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count)
+                raise VirtualNetworkFunctionDescriptorRefCountExists(
+                    "Cannot delete :%s, ref_count:%s",
+                    vnfd_id,
+                    self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count)
+
+            del self._vnfds_to_vnfr[vnfd_id]
 
         # Remove any files uploaded with VNFD and stored under $RIFT_ARTIFACTS/libs/<id>
         try:
@@ -2580,7 +2679,6 @@ class VnfManager(object):
                             format(self._vnfds_to_vnfr[vnfd_id].vnfd.name, e))
             self._log.exception(e)
 
-        del self._vnfds_to_vnfr[vnfd_id]
 
     def vnfd_refcount_xpath(self, vnfd_id):
         """ xpath for ref count entry """
@@ -2592,15 +2690,15 @@ class VnfManager(object):
         """ Get the vnfd_list from this VNFM"""
         vnfd_list = []
         if vnfd_id is None or vnfd_id == "":
-            for vnfr in self._vnfds_to_vnfr.values():
+            for vnfd in self._vnfds_to_vnfr.keys():
                 vnfd_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_VnfdRefCount()
-                vnfd_msg.vnfd_id_ref = vnfr.vnfd.id
-                vnfd_msg.instance_ref_count = vnfr.vnfd_ref_count
-                vnfd_list.append((self.vnfd_refcount_xpath(vnfr.vnfd.id), vnfd_msg))
+                vnfd_msg.vnfd_id_ref = vnfd
+                vnfd_msg.instance_ref_count = self._vnfds_to_vnfr[vnfd]
+                vnfd_list.append((self.vnfd_refcount_xpath(vnfd), vnfd_msg))
         elif vnfd_id in self._vnfds_to_vnfr:
                 vnfd_msg = RwVnfrYang.YangData_Vnfr_VnfrCatalog_VnfdRefCount()
-                vnfd_msg.vnfd_id_ref = self._vnfds_to_vnfr[vnfd_id].vnfd.id
-                vnfd_msg.instance_ref_count = self._vnfds_to_vnfr[vnfd_id].vnfd_ref_count
+                vnfd_msg.vnfd_id_ref = vnfd_id
+                vnfd_msg.instance_ref_count = self._vnfds_to_vnfr[vnfd_id]
                 vnfd_list.append((self.vnfd_refcount_xpath(vnfd_id), vnfd_msg))
 
         return vnfd_list