added stubs for stopping a running service and implemented removing a vnfd
[osm/vim-emu.git] / src / emuvim / api / sonata / dummygatekeeper.py
index 7ae3522..2a994bd 100755 (executable)
@@ -64,8 +64,12 @@ GK_STANDALONE_MODE = False
 FORCE_PULL = False
 
 # Automatically deploy SAPs (endpoints) of the service as new containers
+# 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):
@@ -116,7 +120,6 @@ class Service(object):
         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
@@ -163,7 +166,8 @@ class Service(object):
 
         # 3. compute placement of this service instance (adds DC names to VNFDs)
         if not GK_STANDALONE_MODE:
-            self._calculate_placement(FirstDcPlacement)
+            #self._calculate_placement(FirstDcPlacement)
+            self._calculate_placement(RoundRobinDcPlacement)
         # iterate over all vnfds that we have to start
         for vnfd in self.vnfds.itervalues():
             vnfi = None
@@ -210,7 +214,7 @@ class Service(object):
                 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)
@@ -238,8 +242,8 @@ class Service(object):
 
                 if vnf_name in self.vnfds:
                     # re-configure the VNFs IP assignment and ensure that a new subnet is used for each E-LAN
-                    # E-LAN relies on the learning switch capability of the infrastructure switch in dockernet,
-                    # so no explicit chaining is necessary
+                    # E-LAN relies on the learning switch capability of Ryu which has to be turned on in the topology
+                    # (DCNetwork(controller=RemoteController, enable_learning=True)), so no explicit chaining is necessary.
                     vnfi = self._get_vnf_instance(instance_uuid, vnf_name)
                     if vnfi is not None:
                         self._vnf_reconfigure_network(vnfi, intf_name, ip_address)
@@ -254,6 +258,18 @@ class Service(object):
         LOG.info("Service started. Instance id: %r" % instance_uuid)
         return instance_uuid
 
+    def stop_service(self):
+        """
+        This method stops a running service instance.
+        It iterates over all VNFDs, stopping them each
+        and removing them from their data center.
+
+        :return:
+        """
+
+
+
+
     def _start_vnfd(self, vnfd):
         """
         Start a single VNFD of this service
@@ -292,6 +308,20 @@ class Service(object):
             vnfi = target_dc.startCompute(self.vnf_name2docker_name[vnf_name], network=intfs, image=docker_name, flavor_name="small")
             return vnfi
 
+    def _stop_vnfd(self, vnf_name):
+        """
+        Stop a VNFD specified by its name.
+
+        :param vnf_name: Name of the vnf to be stopped
+        :return:
+        """
+        if vnf_name not in self.vnfds:
+            raise Exception("VNFD with name %s not found." % vnf_name)
+        vnfd = self.vnfds[vnf_name]
+        dc = vnfd.get("dc")
+        LOG.info("Stopping %r contained in %r in DC %r" % (vnf_name, self.vnf_name2docker_name[vnf_name], dc)
+        dc.stopCompute(self.vnf_name2docker_name[vnf_name])
+
     def _get_vnf_instance(self, instance_uuid, name):
         """
         Returns the Docker object for the given VNF name (or Docker name).
@@ -393,7 +423,7 @@ class Service(object):
             # 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")
@@ -501,6 +531,20 @@ class FirstDcPlacement(object):
             vnfd["dc"] = list(dcs.itervalues())[0]
 
 
+class RoundRobinDcPlacement(object):
+    """
+    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())
+        for name, vnfd in vnfds.iteritems():
+            vnfd["dc"] = dcs_list[c % len(dcs_list)]
+            c += 1  # inc. c to use next DC
+
+
+
+
 """
 Resource definitions and API endpoints
 """
@@ -538,7 +582,7 @@ class Packages(fr.Resource):
             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
@@ -584,6 +628,22 @@ class Instantiations(fr.Resource):
         return {"service_instantiations_list": [
             list(s.instances.iterkeys()) for s in GK.services.itervalues()]}
 
+    def delete(self):
+        """
+        Stops a running service specified by its UUID.
+
+        :return:
+        """
+        # try to extract the service UUID from the request
+        json_data = request.get_json(force=True)
+        service_uuid = json_data.get("service_uuid")
+
+        if service_uuid in GK.services:
+            # valid service UUID, stop service
+            GK.services.get(service_uuid).stop_service()
+            return "", 0
+        return "Service not found", 404
+
 
 # create a single, global GK object
 GK = Gatekeeper()