Shorten VDU names
[osm/SO.git] / rwlaunchpad / plugins / rwvnfm / rift / tasklets / rwvnfmtasklet / rwvnfmtasklet.py
index e0de7b0..2cbe240 100755 (executable)
@@ -51,6 +51,7 @@ import rift.package.store
 import rift.package.cloud_init
 import rift.package.script
 import rift.mano.dts as mano_dts
+import rift.mano.utils.short_name as mano_short_name
 
 
 class VMResourceError(Exception):
@@ -271,6 +272,7 @@ class VirtualDeploymentUnitRecord(object):
                  loop,
                  vdud,
                  vnfr,
+                 nsr_config,
                  mgmt_intf,
                  mgmt_network,
                  cloud_account_name,
@@ -282,6 +284,7 @@ class VirtualDeploymentUnitRecord(object):
         self._loop = loop
         self._vdud = vdud
         self._vnfr = vnfr
+        self._nsr_config = nsr_config
         self._mgmt_intf = mgmt_intf
         self._cloud_account_name = cloud_account_name
         self._vnfd_package_store = vnfd_package_store
@@ -341,6 +344,31 @@ class VirtualDeploymentUnitRecord(object):
         """ Return this VDUR's name """
         return self._name
 
+    # Truncated name confirming to RFC 1123
+    @property
+    def unique_short_name(self):
+        """ Return this VDUR's unique short name """
+        # Impose these restrictions on Unique name
+        #  Max 64
+        #    - Max 10 of NSR name (remove all specialcharacters, only numbers and alphabets)
+        #    - 6 chars of shortened name
+        #    - Max 10 of VDU name (remove all specialcharacters, only numbers and alphabets)
+        #
+        def _restrict_tag(input_str):
+           # Exclude all characters except a-zA-Z0-9
+           outstr = re.sub('[^a-zA-Z0-9]', '', input_str)
+           # Take max of 10 chars
+           return outstr[-10:]
+
+        # Use NSR name for part1
+        part1 = _restrict_tag(self._nsr_config.name)
+        # Get unique short string (6 chars)
+        part2 = mano_short_name.StringShortner(self._name)
+        # Use VDU ID for part3
+        part3 = _restrict_tag(self._vdud.id)
+        shortstr = part1 + "-" + part2.short_string + "-" + part3
+        return shortstr
+
     @property
     def cloud_account_name(self):
         """ Cloud account this VDU should be created in """
@@ -392,14 +420,17 @@ class VirtualDeploymentUnitRecord(object):
                       "hypervisor_epa",
                       "host_epa",
                       "volumes",
-                      "name"]
+                      ]
         vdu_copy_dict = {k: v for k, v in
                          self._vdud.as_dict().items() if k in vdu_fields}
         vdur_dict = {"id": self._vdur_id,
                      "vdu_id_ref": self._vdud.id,
                      "operational_status": self.operational_status,
                      "operational_status_details": self._state_failed_reason,
+                     "name": self.name,
+                     "unique_short_name": self.unique_short_name
                      }
+
         if self.vm_resp is not None:
             vdur_dict.update({"vim_id": self.vm_resp.vdu_id,
                               "flavor_id": self.vm_resp.flavor_id
@@ -521,6 +552,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")
@@ -609,7 +641,8 @@ class VirtualDeploymentUnitRecord(object):
         vdu_copy_dict = {k: v for k, v in self._vdud.as_dict().items() if k in vdu_fields}
 
         vm_create_msg_dict = {
-                "name": self.name,
+                "name": self.unique_short_name, # Truncated name confirming to RFC 1123
+                "node_id": self.name,           # Rift assigned Id
                 }
 
         if self.image_name is not None:
@@ -631,10 +664,12 @@ class VirtualDeploymentUnitRecord(object):
 
         cp_list = []
         for intf, cp, vlr in self._ext_intf:
-            cp_info = {"name": cp.name,
-                       "virtual_link_id": vlr.network_id,
-                       "type_yang": intf.virtual_interface.type_yang,
-                       "port_security_enabled": cp.port_security_enabled}
+            cp_info = { "name": cp.name,
+                        "virtual_link_id": vlr.network_id,
+                        "type_yang": intf.virtual_interface.type_yang }
+
+            if cp.has_field('port_security_enabled'):
+                cp_info["port_security_enabled"] = cp.port_security_enabled
 
             if (intf.virtual_interface.has_field('vpci') and
                     intf.virtual_interface.vpci is not None):
@@ -653,10 +688,16 @@ class VirtualDeploymentUnitRecord(object):
                                 "type_yang": intf.virtual_interface.type_yang,
                                 "vpci": intf.virtual_interface.vpci})
             else:
-                cp_list.append({"name": cp,
-                                "virtual_link_id": vlr.network_id,
-                                "type_yang": intf.virtual_interface.type_yang,
-                                "port_security_enabled": cp.port_security_enabled})
+                if cp.has_field('port_security_enabled'):
+                    cp_list.append({"name": cp,
+                                    "virtual_link_id": vlr.network_id,
+                                    "type_yang": intf.virtual_interface.type_yang,
+                                    "port_security_enabled": cp.port_security_enabled})
+                else:
+                    cp_list.append({"name": cp,
+                                    "virtual_link_id": vlr.network_id,
+                                    "type_yang": intf.virtual_interface.type_yang})
+
 
         vm_create_msg_dict["connection_points"] = cp_list
         vm_create_msg_dict.update(vdu_copy_dict)
@@ -942,8 +983,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":
@@ -986,13 +1027,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
@@ -1006,7 +1048,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):
@@ -1025,6 +1070,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}
@@ -1033,6 +1079,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)
@@ -1416,6 +1466,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 """
@@ -1431,7 +1488,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)
 
@@ -1480,7 +1538,7 @@ class VirtualNetworkFunctionRecord(object):
         return None
 
     @asyncio.coroutine
-    def get_vdu_placement_groups(self, vdu):
+    def get_vdu_placement_groups(self, vdu, nsr_config):
         placement_groups = []
         ### Step-1: Get VNF level placement groups
         for group in self._vnfr_msg.placement_groups_info:
@@ -1488,10 +1546,7 @@ class VirtualNetworkFunctionRecord(object):
             #group_info.from_dict(group.as_dict())
             placement_groups.append(group)
 
-        ### Step-2: Get NSR config. This is required for resolving placement_groups cloud constructs
-        nsr_config = yield from self.get_nsr_config()
-
-        ### Step-3: Get VDU level placement groups
+        ### Step-2: Get VDU level placement groups
         for group in self.vnfd.placement_groups:
             for member_vdu in group.member_vdus:
                 if member_vdu.member_vdu_ref == vdu.id:
@@ -1510,6 +1565,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 """
@@ -1534,16 +1593,22 @@ class VirtualNetworkFunctionRecord(object):
 
 
         self._log.info("Creating VDU's for vnfd id: %s", self.vnfd_id)
+
+        # Get NSR config - Needed for placement groups and to derive VDU short-name
+        nsr_config = yield from self.get_nsr_config()
+
         for vdu in self._rw_vnfd.vdu:
             self._log.debug("Creating vdu: %s", vdu)
             vdur_id = get_vdur_id(vdu)
 
-            placement_groups = yield from self.get_vdu_placement_groups(vdu)
-            self._log.info("Launching VDU: %s from VNFD :%s (Member Index: %s) with Placement Groups: %s",
+
+            placement_groups = yield from self.get_vdu_placement_groups(vdu, nsr_config)
+            self._log.info("Launching VDU: %s from VNFD :%s (Member Index: %s) with Placement Groups: %s, Existing vdur_id %s",
                            vdu.name,
                            self.vnf_name,
                            self.member_vnf_index,
-                           [ group.name for group in placement_groups])
+                           [ group.name for group in placement_groups],
+                           vdur_id)
 
             vdur = VirtualDeploymentUnitRecord(
                 dts=self._dts,
@@ -1551,6 +1616,7 @@ class VirtualNetworkFunctionRecord(object):
                 loop=self._loop,
                 vdud=vdu,
                 vnfr=vnfr,
+                nsr_config=nsr_config,
                 mgmt_intf=self.has_mgmt_interface(vdu),
                 mgmt_network=self._mgmt_network,
                 cloud_account_name=self.cloud_account_name,
@@ -1574,8 +1640,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
@@ -1603,7 +1669,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)
 
@@ -1844,8 +1909,9 @@ 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)
+        self._log.debug("VNFR-ID %s: Instantiate VLs, restart mode %s", self._vnfr_id, restart_mode)
         try:
             yield from self.instantiate_vls(xact, restart_mode)
         except Exception as e:
@@ -1856,9 +1922,16 @@ class VirtualNetworkFunctionRecord(object):
         self.set_state(VirtualNetworkFunctionRecordState.VM_INIT_PHASE)
 
         # instantiate VDUs
-        self._log.debug("VNFR-ID %s: Create VDUs", self._vnfr_id)
+        self._log.debug("VNFR-ID %s: Create VDUs, restart mode %s", self._vnfr_id, restart_mode)
         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)
@@ -2065,7 +2138,7 @@ class VnfrConsoleOperdataDtsHandler(object):
             if action == rwdts.QueryAction.READ:
                 schema = RwVnfrYang.YangData_RwVnfr_VnfrConsole_Vnfr_Vdur.schema()
                 path_entry = schema.keyspec_to_entry(ks_path)
-                self._log.debug("VDU Opdata path is {}".format(path_entry))
+                self._log.debug("VDU Opdata path is {}".format(path_entry.key00.id))
                 try:
                     vnfr = self._vnfm.get_vnfr(self._vnfr_id)
                 except VnfRecordError as e:
@@ -2388,6 +2461,8 @@ class VdurDatastore(object):
 
         set_if_not_none('name', vdur._vdud.name)
         set_if_not_none('mgmt.ip', vdur.vm_management_ip)
+        # The below can be used for hostname
+        set_if_not_none('vdur_name', vdur.unique_short_name)
 
     def update(self, vdur):
         """Update the VDUR information in the datastore
@@ -2416,6 +2491,8 @@ class VdurDatastore(object):
 
         set_or_delete('name', vdur._vdud.name)
         set_or_delete('mgmt.ip', vdur.vm_management_ip)
+        # The below can be used for hostname
+        set_or_delete('vdur_name', vdur.unique_short_name)
 
     def remove(self, vdur_id):
         """Remove all of the data associated with specified VDUR