Include variables in cloud-init 77/7077/8
authorgcalvino <guillermo.calvinosanchez@altran.com>
Thu, 20 Dec 2018 08:33:12 +0000 (09:33 +0100)
committergcalvino <guillermo.calvinosanchez@altran.com>
Wed, 9 Jan 2019 07:48:34 +0000 (08:48 +0100)
Change-Id: Ic54f765cfde318dbf786e5285f900b119b50895f
Signed-off-by: gcalvino <guillermo.calvinosanchez@altran.com>
osm_lcm/ns.py
requirements.txt
setup.py
stdeb.cfg

index 1aaf2c5..20a4018 100644 (file)
@@ -22,6 +22,7 @@ import logging
 import logging.handlers
 import functools
 import traceback
+from jinja2 import Environment, Template, meta, TemplateError, TemplateNotFound, TemplateSyntaxError
 
 import ROclient
 from lcm_utils import LcmException, LcmExceptionNoMgmtIP, LcmBase
@@ -99,11 +100,13 @@ class NsLcm(LcmBase):
             artifacts=None,
         )
 
-    def vnfd2RO(self, vnfd, new_id=None):
+    def vnfd2RO(self, vnfd, new_id=None, additionalParams=None, nsrId=None):
         """
         Converts creates a new vnfd descriptor for RO base on input OSM IM vnfd
         :param vnfd: input vnfd
         :param new_id: overrides vnf id if provided
+        :param additionalParamsForVnf: Instantiation params for VNFs provided
+        :param nsrId: Id of the NSR
         :return: copy of vnfd
         """
         ci_file = None
@@ -116,19 +119,29 @@ class NsLcm(LcmBase):
             for vdu in vnfd_RO.get("vdu", ()):
                 if "cloud-init-file" in vdu:
                     base_folder = vnfd["_admin"]["storage"]
-                    clout_init_file = "{}/{}/cloud_init/{}".format(
-                        base_folder["folder"],
-                        base_folder["pkg-dir"],
-                        vdu["cloud-init-file"]
-                    )
-                    ci_file = self.fs.file_open(clout_init_file, "r")
-                    # TODO: detect if binary or text. Propose to read as binary and try to decode to utf8. If fails
-                    #  convert to base 64 or similar
-                    clout_init_content = ci_file.read()
-                    ci_file.close()
-                    ci_file = None
+                    cloud_init_file = "{}/{}/cloud_init/{}".format(base_folder["folder"], base_folder["pkg-dir"],
+                                                                   vdu["cloud-init-file"])
+                    with self.fs.file_open(cloud_init_file, "r") as ci_file:
+                        cloud_init_content = ci_file.read()
                     vdu.pop("cloud-init-file", None)
-                    vdu["cloud-init"] = clout_init_content
+                elif "cloud-init" in vdu:
+                    cloud_init_content = vdu["cloud-init"]
+                try:
+                    env = Environment()
+                    ast = env.parse(cloud_init_content)
+                    mandatory_vars = meta.find_undeclared_variables(ast)
+                    if mandatory_vars:
+                        for var in mandatory_vars:
+                            if not additionalParams or var not in additionalParams.keys():
+                                raise LcmException("Variable '{}' defined in vnfd[id={}] vdu[id={}] cloud-init or "
+                                                   "cloud-init-file, must be provided in the instantiation parameters "
+                                                   "inside the 'additionalParamsForVnf' block".format(var, vnfd["id"],
+                                                                                                      vdu["id"]))
+                        template = Template(cloud_init_content)
+                        cloud_init_content = template.render(additionalParams)
+                except (TemplateError, TemplateNotFound, TemplateSyntaxError) as e:
+                    raise LcmException("Error in jinja2 template: {}".format(e))
+                vdu["cloud-init"] = cloud_init_content
             # remnove unused by RO configuration, monitoring, scaling
             vnfd_RO.pop("vnf-configuration", None)
             vnfd_RO.pop("monitoring-param", None)
@@ -589,7 +602,7 @@ class NsLcm(LcmBase):
         nslcmop_operation_state = None
         db_vnfrs = {}
         RO_descriptor_number = 0   # number of descriptors created at RO
-        descriptor_id_2_RO = {}    # map between vnfd/nsd id to the id used at RO
+        vnf_index_2_RO_id = {}    # map between vnfd/nsd id to the id used at RO
         n2vc_info = {}
         exc = None
         try:
@@ -648,12 +661,13 @@ class NsLcm(LcmBase):
             self.update_db_2("nsrs", nsr_id, db_nsr_update)
 
             # get vnfds, instantiate at RO
-            for vnfd_id, vnfd in db_vnfds.items():
+            for c_vnf in nsd.get("constituent-vnfd", ()):
+                member_vnf_index = c_vnf["member-vnf-index"]
                 vnfd_ref = vnfd["id"]
                 step = db_nsr_update["detailed-status"] = "Creating vnfd={} at RO".format(vnfd_ref)
                 # self.logger.debug(logging_text + step)
-                vnfd_id_RO = "{}.{}.{}".format(nsr_id, RO_descriptor_number, vnfd_ref[:23])
-                descriptor_id_2_RO[vnfd_ref] = vnfd_id_RO
+                vnfd_id_RO = "{}.{}.{}".format(nsr_id, RO_descriptor_number, member_vnf_index[:23])
+                vnf_index_2_RO_id[member_vnf_index] = vnfd_id_RO
                 RO_descriptor_number += 1
 
                 # look if present
@@ -663,7 +677,8 @@ class NsLcm(LcmBase):
                     self.logger.debug(logging_text + "vnfd={} exists at RO. Using RO_id={}".format(
                         vnfd_ref, vnfd_list[0]["uuid"]))
                 else:
-                    vnfd_RO = self.vnfd2RO(vnfd, vnfd_id_RO)
+                    vnfd_RO = self.vnfd2RO(vnfd, vnfd_id_RO, db_vnfrs[c_vnf["member-vnf-index"]].
+                                           get("additionalParamsForVnf"), nsr_id)
                     desc = await RO.create("vnfd", descriptor=vnfd_RO)
                     db_nsr_update["_admin.deployed.RO.vnfd_id.{}".format(vnfd_id)] = desc["uuid"]
                     self.logger.debug(logging_text + "vnfd={} created at RO. RO_id={}".format(
@@ -676,7 +691,6 @@ class NsLcm(LcmBase):
             # self.logger.debug(logging_text + step)
 
             RO_osm_nsd_id = "{}.{}.{}".format(nsr_id, RO_descriptor_number, nsd_ref[:23])
-            descriptor_id_2_RO[nsd_ref] = RO_osm_nsd_id
             RO_descriptor_number += 1
             nsd_list = await RO.get_list("nsd", filter_by={"osm_id": RO_osm_nsd_id})
             if nsd_list:
@@ -689,8 +703,13 @@ class NsLcm(LcmBase):
                 nsd_RO.pop("_id", None)
                 nsd_RO.pop("_admin", None)
                 for c_vnf in nsd_RO.get("constituent-vnfd", ()):
-                    vnfd_id = c_vnf["vnfd-id-ref"]
-                    c_vnf["vnfd-id-ref"] = descriptor_id_2_RO[vnfd_id]
+                    member_vnf_index = c_vnf["member-vnf-index"]
+                    c_vnf["vnfd-id-ref"] = vnf_index_2_RO_id[member_vnf_index]
+                for c_vld in nsd_RO.get("vld", ()):
+                    for cp in c_vld.get("vnfd-connection-point-ref", ()):
+                        member_vnf_index = cp["member-vnf-index-ref"]
+                        cp["vnfd-id-ref"] = vnf_index_2_RO_id[member_vnf_index]
+
                 desc = await RO.create("nsd", descriptor=nsd_RO)
                 db_nsr_update["_admin.nsState"] = "INSTANTIATED"
                 db_nsr_update["_admin.deployed.RO.nsd_id"] = RO_nsd_uuid = desc["uuid"]
index c1e758a..0ecc3eb 100644 (file)
@@ -14,5 +14,6 @@
 
 pyyaml==3.*
 aiohttp==0.20.2
+jinja2
 git+https://osm.etsi.org/gerrit/osm/common.git#egg=osm-common
 git+https://osm.etsi.org/gerrit/osm/N2VC.git#egg=n2vc
index 5d7a52c..17e6ab8 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -55,6 +55,7 @@ setup(
         'aiohttp==0.20.2',
         'osm-common',
         'n2vc',
+        'jinja2',
         # TODO this is version installed by 'apt python3-aiohttp' on Ubuntu Sserver 14.04
         # version installed by pip 3.3.2 is not compatible. Code should be migrated to this version and use pip3
     ],
index 8dd3fca..36d1fb0 100644 (file)
--- a/stdeb.cfg
+++ b/stdeb.cfg
@@ -1,3 +1,3 @@
 [DEFAULT]
 X-Python3-Version : >= 3.5
-Depends3: python3-osm-common, python3-n2vc, python3-yaml, python3-aiohttp
+Depends3: python3-osm-common, python3-n2vc, python3-yaml, python3-aiohttp, python3-jinja2