# Attention: This is not a configuration switch but a global variable! Don't change its default value.
DEPLOY_SAP = False
+# flag to indicate if we use bidirectional forwarding rules in the automatic chaining process
+BIDIRECTIONAL_CHAIN = False
+
class Gatekeeper(object):
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.")
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)
-
def onboard(self):
"""
Do all steps to prepare this service to be instantiated
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
ret = network.setChain(
src_docker_name, dst_docker_name,
vnf_src_interface=src_if_name, vnf_dst_interface=dst_if_name,
- bidirectional=True, cmd="add-flow", cookie=cookie, priority=10)
+ bidirectional=BIDIRECTIONAL_CHAIN, cmd="add-flow", cookie=cookie, priority=10)
# re-configure the VNFs IP assignment and ensure that a new subnet is used for each E-Link
src_vnfi = self._get_vnf_instance(instance_uuid, src_name)
# 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
LOG.info("Service started. Instance id: %r" % instance_uuid)
return instance_uuid
+ def stop_service(self, instance_uuid):
+ """
+ This method stops a running service instance.
+ It iterates over all VNF instances, stopping them each
+ and removing them from their data center.
+
+ :param instance_uuid: the uuid of the service instance to be stopped
+ """
+ LOG.info("Stopping service %r" % self.uuid)
+ # get relevant information
+ # instance_uuid = str(self.uuid.uuid4())
+ vnf_instances = self.instances[instance_uuid]["vnf_instances"]
+
+ for v in vnf_instances:
+ self._stop_vnfi(v)
+
+ if not GK_STANDALONE_MODE:
+ # remove placement?
+ # self._remove_placement(RoundRobinPlacement)
+ None
+
+ # last step: remove the instance from the list of all instances
+ del self.instances[instance_uuid]
+
def _start_vnfd(self, vnfd):
"""
Start a single VNFD of this service
vnfi = target_dc.startCompute(self.vnf_name2docker_name[vnf_name], network=intfs, image=docker_name, flavor_name="small")
return vnfi
+ def _stop_vnfi(self, vnfi):
+ """
+ Stop a VNF instance.
+
+ :param vnfi: vnf instance to be stopped
+ """
+ # Find the correct datacenter
+ status = vnfi.getStatus()
+ dc = vnfi.datacenter
+ # stop the vnfi
+ LOG.info("Stopping the vnf instance contained in %r in DC %r" % (status["name"], dc))
+ dc.stopCompute(status["name"])
+
def _get_vnf_instance(self, instance_uuid, name):
"""
Returns the Docker object for the given VNF name (or Docker name).
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):
# 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(':', '_')
+ sap_docker_name = "%s_%s" % (sap_vnf_id, sap_vnf_interface)
# add SAP to self.vnfds
sapfile = pkg_resources.resource_filename(__name__, "sap_vnfd.yml")
"""
Placement: Distribute VNFs across all available DCs in a round robin fashion.
"""
-
def place(self, nsd, vnfds, dcs):
c = 0
- dcs_list = list(dcs.itervalues())
+ dcs_list = list(dcs.itervalues())
for name, vnfd in vnfds.iteritems():
vnfd["dc"] = dcs_list[c % len(dcs_list)]
c += 1 # inc. c to use next DC
s = Service(service_uuid, file_hash, upload_path)
GK.register_service_package(service_uuid, s)
# generate the JSON result
- return {"service_uuid": service_uuid, "size": size, "sha1": file_hash, "error": None}
+ return {"service_uuid": service_uuid, "size": size, "sha1": file_hash, "error": None}, 201
except Exception as ex:
LOG.exception("Service package upload failed:")
return {"service_uuid": None, "size": 0, "sha1": None, "error": "upload failed"}, 500
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()
- return {"service_instance_uuid": service_instance_uuid}
+ return {"service_instance_uuid": service_instance_uuid}, 201
return "Service not found", 404
def get(self):
return {"service_instantiations_list": [
list(s.instances.iterkeys()) for s in GK.services.itervalues()]}
+ def delete(self):
+ """
+ Stops a running service specified by its service and instance UUID.
+ """
+ # try to extract the service and instance UUID from the request
+ json_data = request.get_json(force=True)
+ service_uuid = json_data.get("service_uuid")
+ instance_uuid = json_data.get("service_instance_uuid")
+
+ # try to be fuzzy
+ if service_uuid is None and len(GK.services) > 0:
+ #if we don't get a service uuid, we simply stop the last service in the list
+ service_uuid = list(GK.services.iterkeys())[0]
+ if instance_uuid is None and len(GK.services[service_uuid].instances) > 0:
+ instance_uuid = list(GK.services[service_uuid].instances.iterkeys())[0]
+
+ if service_uuid in GK.services and instance_uuid in GK.services[service_uuid].instances:
+ # valid service and instance UUID, stop service
+ GK.services.get(service_uuid).stop_service(instance_uuid)
+ del GK.services.get(service_uuid).instances[instance_uuid]
+ return
+ return "Service not found", 404
+
+class Exit(fr.Resource):
+
+ def put(self):
+ """
+ Stop the running Containernet instance regardless of data transmitted
+ """
+ GK.net.stop()
+
+
+def initialize_GK():
+ global GK
+ GK = Gatekeeper()
+
+
# create a single, global GK object
-GK = Gatekeeper()
+GK = None
+initialize_GK()
# setup Flask
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 512 * 1024 * 1024 # 512 MB max upload
# define endpoints
api.add_resource(Packages, '/packages')
api.add_resource(Instantiations, '/instantiations')
+api.add_resource(Exit, '/emulator/exit')
+
+
+#def initialize_GK():
+# global GK
+# GK = Gatekeeper()
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__':
"""