Finalizing Python3 migration
[osm/vim-emu.git] / src / emuvim / api / tango / llcm.py
index 75c71bf..6e570d0 100755 (executable)
@@ -357,6 +357,8 @@ class Service(object):
             # do some re-naming of fields to be compatible to containernet
             for i in intfs:
                 if i.get("address"):
+                    LOG.info("Found static address for {}: {}"
+                             .format(i.get("id"), i.get("address")))
                     i["ip"] = i.get("address")
 
             # get ports and port_bindings from the port and publish fields of CNFD
@@ -364,11 +366,30 @@ class Service(object):
             ports = list()  # Containernet naming
             port_bindings = dict()
             for i in intfs:
-                if i.get("port"):
+                if i.get("port"):  # field with a single port
                     if not isinstance(i.get("port"), int):
                         LOG.info("Field 'port' is no int CP: {}".format(i))
                     else:
-                        ports.append(i.get("port"))
+                        ports.append(i.get("port"))  # collect all ports
+                if i.get("ports"):  # list with multiple ports
+                    if not isinstance(i.get("ports"), list):
+                        LOG.info("Field 'port' is no list CP: {}".format(i))
+                    else:
+                        for p in i.get("ports"):
+                            if not isinstance(p, int):
+                                # do some parsing
+                                try:
+                                    if "/udp" in p:
+                                        p = tuple(p.split("/"))
+                                    else:
+                                        p = int(p)
+                                    ports.append(p)  # collect all ports
+                                except BaseException as ex:
+                                    LOG.error(
+                                        "Could not parse ports list: {}".format(p))
+                                    LOG.error(ex)
+                            else:
+                                ports.append(p)  # collect all ports
                 if i.get("publish"):
                     if not isinstance(i.get("publish"), dict):
                         LOG.info("Field 'publish' is no dict CP: {}".format(i))
@@ -400,6 +421,13 @@ class Service(object):
             conf_envs = self._load_instance_conf_envs(vnf_container_instance_name)
             cenv.update(conf_envs)
 
+            # 5.3 handle optional ipc_mode setting
+            ipc_mode = u.get("ipc_mode", None)
+            # 5.4 handle optional devices setting
+            devices = u.get("devices", [])
+            # 5.5 handle optional cap_add setting
+            cap_add = u.get("cap_add", [])
+
             # 6. Start the container
             LOG.info("Starting %r as %r in DC %r" %
                      (vnf_name, vnf_container_instance_name, target_dc))
@@ -419,6 +447,9 @@ class Service(object):
                 port_bindings=port_bindings,
                 # only publish if explicitly stated in descriptor
                 publish_all_ports=False,
+                ipc_mode=ipc_mode,
+                devices=devices,
+                cap_add=cap_add,
                 type=kwargs.get('type', 'docker'))
             # add vnfd reference to vnfi
             vnfi.vnfd = vnfd
@@ -716,8 +747,8 @@ class Service(object):
             lan_hosts = list(lan_net.hosts())
 
             # generate lan ip address for all interfaces (of all involved (V/CDUs))
-            for intf in link["connection_points_reference"]:
-                vnf_id, intf_name = parse_interface(intf)
+            for intf_ref in link["connection_points_reference"]:
+                vnf_id, intf_name = parse_interface(intf_ref)
                 if vnf_id is None:
                     continue  # skip references to NS connection points
                 units = self._get_vnf_instance_units(instance_uuid, vnf_id)
@@ -728,10 +759,20 @@ class Service(object):
                     # Attention: we apply a simplification for multi DU VNFs here:
                     # the connection points of all involved DUs have to have the same
                     # name as the connection points of the surrounding VNF to be mapped.
-                    # This is because we do not consider links specified in the VNFds
+                    # This is because we do not consider links specified in the VNFDs
                     container_name = uvnfi.name
-                    ip_address = "{0}/{1}".format(str(lan_hosts.pop(0)),
-                                                  lan_net.prefixlen)
+
+                    ip_address = None
+                    # get the interface of the unit
+                    intf = self._get_vnfd_cp_from_vnfi(uvnfi, intf_name)
+                    # check if there is a manually assigned address
+                    if intf is not None:
+                        if intf.get("address"):
+                            ip_address = intf.get("address")
+                    if ip_address is None:
+                        # automatically asign an IP from our pool
+                        ip_address = "{0}/{1}".format(str(lan_hosts.pop(0)),
+                                                      lan_net.prefixlen)
                     LOG.debug(
                         "Setting up E-LAN/E-Tree interface. (%s:%s) -> %s" % (
                             container_name, intf_name, ip_address))
@@ -777,7 +818,7 @@ class Service(object):
         Get all URLs to pre-build docker images in some repo.
         :return:
         """
-        for vnf_id, v in self.vnfds.iteritems():
+        for vnf_id, v in list(self.vnfds.items()):
             for vu in v.get("virtual_deployment_units", []):
                 vnf_container_name = get_container_name(vnf_id, vu.get("id"))
                 if vu.get("vm_image_format") == "docker":
@@ -807,7 +848,7 @@ class Service(object):
         dc = DockerClient()
         LOG.info("Building %d Docker images (this may take several minutes) ..." % len(
             self.local_docker_files))
-        for k, v in self.local_docker_files.iteritems():
+        for k, v in list(self.local_docker_files.items()):
             for line in dc.build(path=v.replace(
                     "Dockerfile", ""), tag=k, rm=False, nocache=False):
                 LOG.debug("DOCKER BUILD: %s" % line)
@@ -818,7 +859,7 @@ class Service(object):
         If the package contains URLs to pre-build Docker images, we download them with this method.
         """
         dc = DockerClient()
-        for url in self.remote_docker_image_urls.itervalues():
+        for url in list(self.remote_docker_image_urls.values()):
             # only pull if not present (speedup for development)
             if not FORCE_PULL:
                 if len(dc.images.list(name=url)) > 0:
@@ -899,7 +940,7 @@ class FirstDcPlacement(object):
     """
 
     def place(self, dcs, vnfd, vnfid, vdu, ssiid, cname):
-        return list(dcs.itervalues())[0]
+        return list(dcs.values())[0]
 
 
 class RoundRobinDcPlacement(object):
@@ -911,7 +952,7 @@ class RoundRobinDcPlacement(object):
         self.count = 0
 
     def place(self, dcs, vnfd, vnfid, vdu, ssiid, cname):
-        dcs_list = list(dcs.itervalues())
+        dcs_list = list(dcs.values())
         rdc = dcs_list[self.count % len(dcs_list)]
         self.count += 1  # inc. count to use next DC
         return rdc
@@ -941,14 +982,14 @@ class StaticConfigPlacement(object):
         if cname not in self.static_placement:
             LOG.error("Coudn't find {} in placement".format(cname))
             LOG.error("Using first DC as fallback!")
-            return list(dcs.itervalues())[0]
+            return list(dcs.values())[0]
         # lookup
         candidate_dc = self.static_placement.get(cname)
         # check if DC exsits
         if candidate_dc not in dcs:
             LOG.error("Coudn't find DC {}".format(candidate_dc))
             LOG.error("Using first DC as fallback!")
-            return list(dcs.itervalues())[0]
+            return list(dcs.values())[0]
         # return correct DC
         return dcs.get(candidate_dc)
 
@@ -982,10 +1023,13 @@ class Packages(fr.Resource):
                         "error": "upload failed. file not found."}, 500
             # generate a uuid to reference this package
             service_uuid = str(uuid.uuid4())
-            file_hash = hashlib.sha1(str(son_file)).hexdigest()
+            file_hash = str(son_file)
+            file_hash = hashlib.sha1(file_hash.encode())
+            file_hash = file_hash.hexdigest()
             # ensure that upload folder exists
             ensure_dir(UPLOAD_FOLDER)
-            upload_path = os.path.join(UPLOAD_FOLDER, "%s.tgo" % service_uuid)
+            upload_path = os.path.\
+                join(UPLOAD_FOLDER, "%s.tgo" % service_uuid)
             # store *.son file to disk
             if is_file_object:
                 son_file.save(upload_path)
@@ -1034,7 +1078,7 @@ class Packages(fr.Resource):
         """
         LOG.info("GET /packages")
         result = list()
-        for suuid, sobj in GK.services.iteritems():
+        for suuid, sobj in GK.services.items():
             pkg = dict()
             pkg["pd"] = dict()
             pkg["uuid"] = suuid
@@ -1056,7 +1100,7 @@ class Services(fr.Resource):
         """
         LOG.info("GET /services")
         result = list()
-        for suuid, sobj in GK.services.iteritems():
+        for suuid, sobj in GK.services.items():
             service = dict()
             service["nsd"] = dict()
             service["uuid"] = suuid
@@ -1085,7 +1129,7 @@ class Instantiations(fr.Resource):
             service_name = service_uuid
         # first try to find by service_name
         if service_name is not None:
-            for s_uuid, s in GK.services.iteritems():
+            for s_uuid, s in GK.services.items():
                 if s.manifest.get("name") == service_name:
                     LOG.info("Searched for: {}. Found service w. UUID: {}"
                              .format(service_name, s_uuid))
@@ -1095,7 +1139,7 @@ class Instantiations(fr.Resource):
                 "latest") and len(GK.services) > 0:
             # if we don't get a service uuid, we simple start the first service
             # in the list
-            service_uuid = list(GK.services.iterkeys())[0]
+            service_uuid = list(GK.services.keys())[0]
         if service_uuid in GK.services:
             # ok, we have a service uuid, lets start the service
             service_instance_uuid = GK.services.get(
@@ -1113,10 +1157,10 @@ class Instantiations(fr.Resource):
         """
         LOG.debug("GET /instantiations or /api/v3/records/services")
         # return {"service_instantiations_list": [
-        #    list(s.instances.iterkeys()) for s in GK.services.itervalues()]}
+        #    list(s.instances.keys()) for s in GK.services.values()]}
         result = list()
-        for suuid, sobj in GK.services.iteritems():
-            for iuuid, iobj in sobj.instances.iteritems():
+        for suuid, sobj in GK.services.items():
+            for iuuid, iobj in sobj.instances.items():
                 inst = dict()
                 inst["uuid"] = iobj.get("uuid")
                 inst["instance_name"] = "{}-inst.{}".format(
@@ -1139,7 +1183,7 @@ class Instantiations(fr.Resource):
         # try to be fuzzy
         if service_uuid_input is None:
             # if we don't get a service uuid we stop all services
-            service_uuid_list = list(GK.services.iterkeys())
+            service_uuid_list = list(GK.services.keys())
             LOG.info("No service_uuid given, stopping all.")
         else:
             service_uuid_list = [service_uuid_input]
@@ -1147,7 +1191,7 @@ class Instantiations(fr.Resource):
         for service_uuid in service_uuid_list:
             if instance_uuid_input is None:
                 instance_uuid_list = list(
-                    GK.services[service_uuid].instances.iterkeys())
+                    GK.services[service_uuid].instances.keys())
             else:
                 instance_uuid_list = [instance_uuid_input]
             # for all service instances
@@ -1174,7 +1218,7 @@ def generate_subnets(prefix, base, subnet_size=50, mask=24):
     r = list()
     for net in range(base, base + subnet_size):
         subnet = "{0}.{1}.0/{2}".format(prefix, net, mask)
-        r.append(ipaddress.ip_network(unicode(subnet)))
+        r.append(ipaddress.ip_network(subnet))
     return r
 
 
@@ -1259,7 +1303,7 @@ def get_dc_network():
     :return:
     """
     assert (len(GK.dcs) > 0)
-    return GK.dcs.values()[0].net
+    return list(GK.dcs.values())[0].net
 
 
 def parse_interface(interface_name):
@@ -1298,7 +1342,7 @@ def update_port_mapping_multi_instance(ssiid, port_bindings):
     def _offset(p):
         return p + MULTI_INSTANCE_PORT_OFFSET * ssiid
 
-    port_bindings = {k: _offset(v) for k, v in port_bindings.iteritems()}
+    port_bindings = {k: _offset(v) for k, v in port_bindings.items()}
     return port_bindings