from docker import DockerClient
from flask import Flask, request
import flask_restful as fr
+from gevent.pywsgi import WSGIServer
from subprocess import Popen
import ipaddress
import copy
if i.get("address"):
i["ip"] = i.get("address")
+ # get ports and port_bindings from the port and publish fields of CNFD
+ # see: https://github.com/containernet/containernet/wiki/Exposing-and-mapping-network-ports
+ ports = list() # Containernet naming
+ port_bindings = dict()
+ for i in intfs:
+ if i.get("port"):
+ if not isinstance(i.get("port"), int):
+ LOG.error("Field 'port' is no int CP: {}".format(i))
+ else:
+ ports.append(i.get("port"))
+ if i.get("publish"):
+ if not isinstance(i.get("publish"), dict):
+ LOG.error("Field 'publish' is no dict CP: {}".format(i))
+ else:
+ port_bindings.update(i.get("publish"))
+ if len(ports) > 0:
+ LOG.info("{} exposes ports: {}".format(vnf_container_name, ports))
+ if len(port_bindings) > 0:
+ LOG.info("{} publishes ports: {}".format(vnf_container_name, port_bindings))
+
# 5. collect additional information to start container
volumes = list()
cenv = dict()
mem_limit=mem_limit,
volumes=volumes,
properties=cenv, # environment
+ ports=ports,
+ port_bindings=port_bindings,
type=kwargs.get('type', 'docker'))
# add vnfd reference to vnfi
vnfi.vnfd = vnfd
def _get_vnf_instance(self, instance_uuid, vnf_id):
"""
- Returns VNFI object for a given "vnf_id" or "vnf_container_namse" taken from an NSD.
+ Returns VNFI object for a given "vnf_id" or "vnf_container_name" taken from an NSD.
:return: single object
"""
for vnfi in self.instances[instance_uuid]["vnf_instances"]:
"vnf_id" taken from an NSD.
:return: list
"""
+ if vnf_id is None:
+ return None
r = list()
for vnfi in self.instances[instance_uuid]["vnf_instances"]:
if vnf_id in vnfi.name:
env = config.get("Env", list())
for env_var in env:
var, cmd = map(str.strip, map(str, env_var.split('=', 1)))
- # LOG.debug("%r = %r" % (var, cmd))
if var == "SON_EMU_CMD" or var == "VIM_EMU_CMD":
LOG.info("Executing script in '{}': {}={}"
.format(vnfi.name, var, cmd))
cookie = 1
for link in eline_fwd_links:
LOG.info("Found E-Line: {}".format(link))
- # check if we need to deploy this link when its a management link:
- if USE_DOCKER_MGMT:
- if self.check_mgmt_interface(
- link["connection_points_reference"]):
- continue
-
src_id, src_if_name = parse_interface(
link["connection_points_reference"][0])
dst_id, dst_if_name = parse_interface(
link["connection_points_reference"][1])
- setChaining = False
- LOG.info("Creating E-Line: src={}, dst={}"
- .format(src_id, dst_id))
+ LOG.info("Searching C/VDU for E-Line: src={}, src_if={}, dst={}, dst_if={}"
+ .format(src_id, src_if_name, dst_id, dst_if_name))
+ # handle C/VDUs (ugly hack, only one V/CDU per VNF for now)
+ src_units = self._get_vnf_instance_units(instance_uuid, src_id)
+ dst_units = self._get_vnf_instance_units(instance_uuid, dst_id)
+ if src_units is None or dst_units is None:
+ LOG.info("No VNF-VNF link. Skipping: src={}, src_if={}, dst={}, dst_if={}"
+ .format(src_id, src_if_name, dst_id, dst_if_name))
+ return
+ # we only support VNFs with one V/CDU right now
+ if len(src_units) != 1 or len(dst_units) != 1:
+ raise BaseException("LLCM does not support E-LINES for multi V/CDU VNFs.")
+ # get the full name from that C/VDU and use it as src_id and dst_id
+ src_id = src_units[0].name
+ dst_id = dst_units[0].name
+ # from here we have all info we need
+ LOG.info("Creating E-Line for C/VDU: src={}, src_if={}, dst={}, dst_if={}"
+ .format(src_id, src_if_name, dst_id, dst_if_name))
# get involved vnfis
- src_vnfi = self._get_vnf_instance(instance_uuid, src_id)
- dst_vnfi = self._get_vnf_instance(instance_uuid, dst_id)
-
+ src_vnfi = src_units[0]
+ dst_vnfi = dst_units[0]
+ # proceed with chaining setup
+ setChaining = False
if src_vnfi is not None and dst_vnfi is not None:
setChaining = True
# re-configure the VNFs IP assignment and ensure that a new
eline_net.prefixlen)
ip2 = "{0}/{1}".format(str(eline_net[2]),
eline_net.prefixlen)
- # check if VNFs have fixed IPs (address field in VNFDs)
- if (self._get_vnfd_cp_from_vnfi(src_vnfi, src_if_name)
- .get("address") is None):
+ # check if VNFs have fixed IPs (ip/address field in VNFDs)
+ if (self._get_vnfd_cp_from_vnfi(
+ src_vnfi, src_if_name).get("ip") is None and
+ self._get_vnfd_cp_from_vnfi(
+ src_vnfi, src_if_name).get("address") is None):
self._vnf_reconfigure_network(src_vnfi, src_if_name, ip1)
- # check if VNFs have fixed IPs (address field in VNFDs)
- if (self._get_vnfd_cp_from_vnfi(dst_vnfi, dst_if_name)
- .get("address") is None):
+ # check if VNFs have fixed IPs (ip field in VNFDs)
+ if (self._get_vnfd_cp_from_vnfi(
+ dst_vnfi, dst_if_name).get("ip") is None and
+ self._get_vnfd_cp_from_vnfi(
+ dst_vnfi, dst_if_name).get("address") is None):
self._vnf_reconfigure_network(dst_vnfi, dst_if_name, ip2)
# set the chaining
if setChaining:
GK = None
initialize_GK()
# setup Flask
+http_server = None
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 512 * 1024 * 1024 # 512 MB max upload
api = fr.Api(app)
def start_rest_api(host, port, datacenters=dict()):
+ global http_server
GK.dcs = datacenters
GK.net = get_dc_network()
# start the Flask server (not the best performance but ok for our use case)
- app.run(host=host,
- port=port,
- debug=True,
- use_reloader=False # this is needed to run Flask in a non-main thread
- )
+ # app.run(host=host,
+ # port=port,
+ # debug=True,
+ # use_reloader=False # this is needed to run Flask in a non-main thread
+ # )
+ http_server = WSGIServer((host, port), app, log=open("/dev/null", "w"))
+ http_server.serve_forever()
+
+
+def stop_rest_api():
+ if http_server:
+ http_server.close()
def ensure_dir(name):