import zipfile
import yaml
import threading
-from docker import Client as DockerClient
+from docker import DockerClient, APIClient
from flask import Flask, request
import flask_restful as fr
from collections import defaultdict
import pkg_resources
+from subprocess import Popen
logging.basicConfig()
LOG = logging.getLogger("sonata-dummy-gatekeeper")
def __init__(self):
self.services = dict()
self.dcs = dict()
+ self.net = None
self.vnf_counter = 0 # used to generate short names for VNFs (Mininet limitation)
LOG.info("Create SONATA dummy gatekeeper.")
eline_fwd_links = [l for l in vlinks if (l["id"] in fwd_links) and (l["connectivity_type"] == "E-Line")]
elan_fwd_links = [l for l in vlinks if (l["id"] in fwd_links) and (l["connectivity_type"] == "E-LAN")]
+ GK.net.deployed_elines.extend(eline_fwd_links)
+ GK.net.deployed_elans.extend(elan_fwd_links)
+
# 4a. deploy E-Line links
# cookie is used as identifier for the flowrules installed by the dummygatekeeper
# eg. different services get a unique cookie for their flowrules
# 4b. deploy E-LAN links
base = 10
for link in elan_fwd_links:
+
+ elan_vnf_list=[]
+
# generate lan ip address
ip = 1
for intf in link["connection_points_reference"]:
if vnf_id in self.sap_identifiers:
src_docker_name = "{0}_{1}".format(vnf_id, intf_name)
vnf_id = src_docker_name
+ else:
+ src_docker_name = vnf_id
vnf_name = vnf_id2vnf_name[vnf_id]
LOG.debug(
"Setting up E-LAN link. %s(%s:%s) -> %s" % (
self._vnf_reconfigure_network(vnfi, intf_name, ip_address)
# increase for the next ip address on this E-LAN
ip += 1
+
+ # add this vnf and interface to the E-LAN for tagging
+ network = self.vnfds[vnf_name].get("dc").net # there should be a cleaner way to find the DCNetwork
+ elan_vnf_list.append({'name':src_docker_name,'interface':intf_name})
+
+
+ # install the VLAN tags for this E-LAN
+ network.setLAN(elan_vnf_list)
# increase the base ip address for the next E-LAN
base += 1
self.package_content_path,
make_relative_path(self.manifest.get("entry_service_template")))
self.nsd = load_yaml(nsd_path)
+ GK.net.deployed_nsds.append(self.nsd)
LOG.debug("Loaded NSD: %r" % self.nsd.get("name"))
def _load_vnfd(self):
dc = DockerClient()
for url in self.remote_docker_image_urls.itervalues():
if not FORCE_PULL: # only pull if not present (speedup for development)
- if len(dc.images(name=url)) > 0:
+ if len(dc.images.list(name=url)) > 0:
LOG.debug("Image %r present. Skipping pull." % url)
continue
LOG.info("Pulling image: %r" % url)
- dc.pull(url,
- insecure_registry=True)
+ # this seems to fail with latest docker api version 2.0.2
+ # dc.images.pull(url,
+ # insecure_registry=True)
+ #using docker cli instead
+ cmd = ["docker",
+ "pull",
+ url,
+ ]
+ Popen(cmd).wait()
+
+
+
def _check_docker_image_exists(self, image_name):
"""
:param image_name: name of the docker image
:return:
"""
- return len(DockerClient().images(image_name)) > 0
+ return len(DockerClient().images.list(name=image_name)) > 0
def _calculate_placement(self, algorithm):
"""
"""
try:
# get file contents
- print(request.files)
+ LOG.info("POST /packages called")
# lets search for the package in the request
+ is_file_object = False # make API more robust: file can be in data or in files field
if "package" in request.files:
son_file = request.files["package"]
- # elif "file" in request.files:
- # son_file = request.files["file"]
+ is_file_object = True
+ elif len(request.data) > 0:
+ son_file = request.data
else:
return {"service_uuid": None, "size": 0, "sha1": None, "error": "upload failed. file not found."}, 500
# generate a uuid to reference this package
ensure_dir(UPLOAD_FOLDER)
upload_path = os.path.join(UPLOAD_FOLDER, "%s.son" % service_uuid)
# store *.son file to disk
- son_file.save(upload_path)
+ if is_file_object:
+ son_file.save(upload_path)
+ else:
+ with open(upload_path, 'wb') as f:
+ f.write(son_file)
size = os.path.getsize(upload_path)
# create a service object and register it
s = Service(service_uuid, file_hash, upload_path)
Will return a new UUID to identify the running service instance.
:return: UUID
"""
+ LOG.info("POST /instantiations (or /reqeusts) called")
# try to extract the service uuid from the request
json_data = request.get_json(force=True)
service_uuid = json_data.get("service_uuid")
# lets be a bit fuzzy here to make testing easier
- if service_uuid is None and len(GK.services) > 0:
+ if (service_uuid is None or service_uuid=="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]
-
if service_uuid in GK.services:
# ok, we have a service uuid, lets start the service
service_instance_uuid = GK.services.get(service_uuid).start_service()
app.config['MAX_CONTENT_LENGTH'] = 512 * 1024 * 1024 # 512 MB max upload
api = fr.Api(app)
# define endpoints
-api.add_resource(Packages, '/packages')
-api.add_resource(Instantiations, '/instantiations')
+api.add_resource(Packages, '/packages', '/api/v2/packages')
+api.add_resource(Instantiations, '/instantiations', '/api/v2/instantiations', '/api/v2/requests')
api.add_resource(Exit, '/emulator/exit')
def start_rest_api(host, port, datacenters=dict()):
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,
r.append("%d.0.0.%d/%d" % (i, ip, subnet_size))
return r
+def get_dc_network():
+ """
+ retrieve the DCnetwork where this dummygatekeeper (GK) connects to.
+ Assume at least 1 datacenter is connected to this GK, and that all datacenters belong to the same DCNetwork
+ :return:
+ """
+ assert (len(GK.dcs) > 0)
+ return GK.dcs.values()[0].net
if __name__ == '__main__':
"""