From db2f94382278b94fe9f8bbfaeb505b8657f8f387 Mon Sep 17 00:00:00 2001 From: stevenvanrossem Date: Sat, 20 Aug 2016 00:01:11 +0200 Subject: [PATCH] deploy SAP endpoints via flag for dummygatekeeper --- setup.py | 4 ++ src/emuvim/api/sonata/__init__.py | 3 +- src/emuvim/api/sonata/dummygatekeeper.py | 70 ++++++++++++++++---- src/emuvim/api/sonata/sap_vnfd.yml | 50 ++++++++++++++ src/emuvim/examples/son-monitor_test_topo.py | 2 +- 5 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 src/emuvim/api/sonata/sap_vnfd.yml diff --git a/setup.py b/setup.py index 8770532..0baad49 100755 --- a/setup.py +++ b/setup.py @@ -36,6 +36,10 @@ setup(name='emuvim', package_dir={'': 'src'}, # packages=find_packages('emuvim', exclude=['*.test', '*.test.*', 'test.*', 'test']), packages=find_packages('src'), + include_package_data=True, + package_data= { + 'emuvim.api.sonata': ['*.yml'] + }, install_requires=[ 'pyaml', 'zerorpc', diff --git a/src/emuvim/api/sonata/__init__.py b/src/emuvim/api/sonata/__init__.py index 4c93fc4..434ec1c 100755 --- a/src/emuvim/api/sonata/__init__.py +++ b/src/emuvim/api/sonata/__init__.py @@ -46,10 +46,11 @@ class SonataDummyGatekeeperEndpoint(object): topology. """ - def __init__(self, listenip, port): + def __init__(self, listenip, port, deploy_sap=False): self.dcs = {} self.ip = listenip self.port = port + dgk.DEPLOY_SAP = deploy_sap logging.debug("Created API endpoint %s" % self) def __repr__(self): diff --git a/src/emuvim/api/sonata/dummygatekeeper.py b/src/emuvim/api/sonata/dummygatekeeper.py index 2aa712e..55191b2 100755 --- a/src/emuvim/api/sonata/dummygatekeeper.py +++ b/src/emuvim/api/sonata/dummygatekeeper.py @@ -42,6 +42,7 @@ from docker import Client as DockerClient from flask import Flask, request import flask_restful as fr from collections import defaultdict +import pkg_resources logging.basicConfig() LOG = logging.getLogger("sonata-dummy-gatekeeper") @@ -61,6 +62,9 @@ GK_STANDALONE_MODE = False # should a new version of an image be pulled even if its available FORCE_PULL = False +# Automatically deploy SAPs (endpoints) of the service as new containers +DEPLOY_SAP = False + class Gatekeeper(object): def __init__(self): @@ -106,6 +110,7 @@ class Service(object): self.remote_docker_image_urls = dict() self.instances = dict() self.vnf_name2docker_name = dict() + self.sap_identifiers = set() # lets generate a set of subnet configurations used for e-line chaining setup self.eline_subnets_src = generate_subnet_strings(50, start=200, subnet_size=24, ip=1) self.eline_subnets_dst = generate_subnet_strings(50, start=200, subnet_size=24, ip=2) @@ -122,6 +127,8 @@ class Service(object): self._load_package_descriptor() self._load_nsd() self._load_vnfd() + if DEPLOY_SAP: + self._load_saps() # 3. prepare container images (e.g. download or build Dockerfile) if BUILD_DOCKERFILE: self._load_docker_files() @@ -147,7 +154,13 @@ class Service(object): self.instances[instance_uuid] = dict() self.instances[instance_uuid]["vnf_instances"] = list() - # 2. compute placement of this service instance (adds DC names to VNFDs) + # 2. Configure the chaining of the network functions (currently only E-Line and E-LAN links supported) + vnf_id2vnf_name = defaultdict(lambda: "NotExistingNode", + reduce(lambda x, y: dict(x, **y), + map(lambda d: {d["vnf_id"]: d["vnf_name"]}, + self.nsd["network_functions"]))) + + # 3. compute placement of this service instance (adds DC names to VNFDs) if not GK_STANDALONE_MODE: self._calculate_placement(FirstDcPlacement) # iterate over all vnfds that we have to start @@ -157,18 +170,12 @@ class Service(object): vnfi = self._start_vnfd(vnfd) self.instances[instance_uuid]["vnf_instances"].append(vnfi) - # 3. Configure the chaining of the network functions (currently only E-Line and E-LAN links supported) - vnf_id2vnf_name = defaultdict(lambda: "NotExistingNode", - reduce(lambda x, y: dict(x, **y), - map(lambda d: {d["vnf_id"]: d["vnf_name"]}, - self.nsd["network_functions"]))) - vlinks = self.nsd["virtual_links"] fwd_links = self.nsd["forwarding_graphs"][0]["constituent_virtual_links"] 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")] - # 3a. deploy E-Line 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 cookie = 1 @@ -176,6 +183,19 @@ class Service(object): src_id, src_if_name = link["connection_points_reference"][0].split(":") dst_id, dst_if_name = link["connection_points_reference"][1].split(":") + # check if there is a SAP in the link + if src_id in self.sap_identifiers: + src_docker_name = "{0}_{1}".format(src_id, src_if_name) + src_id = src_docker_name + else: + src_docker_name = src_id + + if dst_id in self.sap_identifiers: + dst_docker_name = "{0}_{1}".format(dst_id, dst_if_name) + dst_id = dst_docker_name + else: + dst_docker_name = dst_id + src_name = vnf_id2vnf_name[src_id] dst_name = vnf_id2vnf_name[dst_id] @@ -185,8 +205,6 @@ class Service(object): if (src_name in self.vnfds) and (dst_name in self.vnfds): network = self.vnfds[src_name].get("dc").net # there should be a cleaner way to find the DCNetwork - src_docker_name = self.vnf_name2docker_name[src_name] - dst_docker_name = self.vnf_name2docker_name[dst_name] LOG.debug(src_docker_name) ret = network.setChain( src_docker_name, dst_docker_name, @@ -201,7 +219,7 @@ class Service(object): if dst_vnfi is not None: self._vnf_reconfigure_network(dst_vnfi, dst_if_name, self.eline_subnets_dst.pop(0)) - # 3b. deploy E-LAN links + # 4b. deploy E-LAN links base = 10 for link in elan_fwd_links: # generate lan ip address @@ -209,6 +227,9 @@ class Service(object): for intf in link["connection_points_reference"]: ip_address = generate_lan_string("10.0", base, subnet_size=24, ip=ip) vnf_id, intf_name = intf.split(":") + if vnf_id in self.sap_identifiers: + src_docker_name = "{0}_{1}".format(vnf_id, intf_name) + vnf_id = src_docker_name vnf_name = vnf_id2vnf_name[vnf_id] LOG.debug( "Setting up E-LAN link. %s(%s:%s) -> %s" % ( @@ -226,9 +247,7 @@ class Service(object): # increase the base ip address for the next E-LAN base += 1 - - - # 4. run the emulator specific entrypoint scripts in the VNFIs of this service instance + # 5. run the emulator specific entrypoint scripts in the VNFIs of this service instance self._trigger_emulator_start_scripts_in_vnfis(self.instances[instance_uuid]["vnf_instances"]) LOG.info("Service started. Instance id: %r" % instance_uuid) @@ -257,6 +276,7 @@ class Service(object): # TODO consider flavors, and other annotations intfs = vnfd.get("connection_points") + # TODO: get all vnf id's from the nsd for this vnfd and use those as dockername # use the vnf_id in the nsd as docker name # so deployed containers can be easily mapped back to the nsd vnf_name2id = defaultdict(lambda: "NotExistingNode", @@ -360,6 +380,28 @@ class Service(object): self.vnfds[vnfd.get("name")] = vnfd LOG.debug("Loaded VNFD: %r" % vnfd.get("name")) + def _load_saps(self): + # Each Service Access Point (connection_point) in the nsd is getting its own container + SAPs = [p["id"] for p in self.nsd["connection_points"] if p["type"] == "interface"] + for sap in SAPs: + # endpoints needed in this service + sap_vnf_id, sap_vnf_interface = sap.split(':') + # set of the connection_point ids found in the nsd (in the examples this is 'ns') + self.sap_identifiers.add(sap_vnf_id) + + sap_docker_name = sap.replace(':', '_') + + # add SAP to self.vnfds + sapfile = pkg_resources.resource_filename(__name__, "sap_vnfd.yml") + sap_vnfd = load_yaml(sapfile) + sap_vnfd["connection_points"][0]["id"] = sap_vnf_interface + sap_vnfd["name"] = sap_docker_name + self.vnfds[sap_docker_name] = sap_vnfd + # add SAP vnf to list in the NSD so it is deployed later on + # each SAP get a unique VNFD and vnf_id in the NSD + self.nsd["network_functions"].append({"vnf_id": sap_docker_name, "vnf_name": sap_docker_name}) + LOG.debug("Loaded SAP: %r" % sap_vnfd.get("name")) + def _load_docker_files(self): """ Get all paths to Dockerfiles from VNFDs and store them in dict. diff --git a/src/emuvim/api/sonata/sap_vnfd.yml b/src/emuvim/api/sonata/sap_vnfd.yml new file mode 100644 index 0000000..38fa700 --- /dev/null +++ b/src/emuvim/api/sonata/sap_vnfd.yml @@ -0,0 +1,50 @@ + +--- +## +## Some general information regarding this +## VNF descriptor. +## +descriptor_version: "vnfd-schema-01" +vendor: "eu.sonata-nfv" +name: "sap_vnf" +version: "0.1" +author: "Steven Van Rossem, Ghent University, steven.vanrossem@intec.ugent.be" +description: "An empty ubuntu VNF; used as SAP" +## +## The virtual deployment unit. +## +virtual_deployment_units: + - id: "1" + vm_image: "registry.sonata-nfv.eu:5000/son-emu-sap" + vm_image_format: "docker" + resource_requirements: + cpu: + vcpus: 1 + memory: + size: 1 + size_unit: "GB" + storage: + size: 1 + size_unit: "GB" + connection_points: + - id: "vdu01:cp01" + type: "interface" + +## +## The virtual links that interconnect +## the different connections points. +## +virtual_links: + - id: "port" + connectivity_type: "E-Line" + connection_points_reference: + - "vdu01:cp02" + - "port" + +## +## The VNF connection points to the +## outside world. +## +connection_points: + - id: "port" + type: "interface" diff --git a/src/emuvim/examples/son-monitor_test_topo.py b/src/emuvim/examples/son-monitor_test_topo.py index b79f7c7..9438460 100755 --- a/src/emuvim/examples/son-monitor_test_topo.py +++ b/src/emuvim/examples/son-monitor_test_topo.py @@ -67,7 +67,7 @@ def create_topology1(): rapi1.start() # add the SONATA dummy gatekeeper to each DC - sdkg1 = SonataDummyGatekeeperEndpoint("0.0.0.0", 5000) + sdkg1 = SonataDummyGatekeeperEndpoint("0.0.0.0", 5000, deploy_sap=True) sdkg1.connectDatacenter(dc1) sdkg1.connectDatacenter(dc2) # run the dummy gatekeeper (in another thread, don't block) -- 2.17.1