Fix: hackfest_1 deployment using OSM LB returned
[osm/vim-emu.git] / src / emuvim / api / openstack / openstack_dummies / neutron_dummy_api.py
index 38a5ad4..6f6d3dc 100755 (executable)
@@ -1,20 +1,54 @@
+"""
+Copyright (c) 2017 SONATA-NFV and Paderborn University
+ALL RIGHTS RESERVED.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Neither the name of the SONATA-NFV, Paderborn University
+nor the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+This work has been performed in the framework of the SONATA project,
+funded by the European Commission under Grant number 671517 through
+the Horizon 2020 and 5G-PPP programmes. The authors would like to
+acknowledge the contributions of their colleagues of the SONATA
+partner consortium (www.sonata-nfv.eu).
+"""
 from flask_restful import Resource
 from flask import request, Response
 from emuvim.api.openstack.openstack_dummies.base_openstack_dummy import BaseOpenstackDummy
+from emuvim.api.openstack.helper import get_host
 from datetime import datetime
+import neutron_sfc_dummy_api as SFC
 import logging
 import json
 import uuid
 import copy
 
+LOG = logging.getLogger("api.openstack.neutron")
+
 
 class NeutronDummyApi(BaseOpenstackDummy):
     def __init__(self, ip, port, compute):
         super(NeutronDummyApi, self).__init__(ip, port)
         self.compute = compute
 
+        # create default networks (OSM usually assumes to have these pre-configured)
+        self.compute.create_network("mgmt")
+        self.compute.create_network("mgmtnet")
+
         self.api.add_resource(NeutronListAPIVersions, "/")
-        self.api.add_resource(Shutdown, "/shutdown")
         self.api.add_resource(NeutronShowAPIv2Details, "/v2.0")
         self.api.add_resource(NeutronListNetworks, "/v2.0/networks.json", "/v2.0/networks",
                               resource_class_kwargs={'api': self})
@@ -49,20 +83,62 @@ class NeutronDummyApi(BaseOpenstackDummy):
         self.api.add_resource(NeutronAddFloatingIp, "/v2.0/floatingips.json", "/v2.0/floatingips",
                               resource_class_kwargs={'api': self})
 
-    def _start_flask(self):
-        logging.info("Starting %s endpoint @ http://%s:%d" % (__name__, self.ip, self.port))
-        if self.app is not None:
-            self.app.before_request(self.dump_playbook)
-            self.app.run(self.ip, self.port, debug=True, use_reloader=False)
+        # Service Function Chaining (SFC) API
+        self.api.add_resource(SFC.PortPairsCreate, "/v2.0/sfc/port_pairs.json", "/v2.0/sfc/port_pairs",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortPairsUpdate, "/v2.0/sfc/port_pairs/<pair_id>.json",
+                              "/v2.0/sfc/port_pairs/<pair_id>",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortPairsDelete, "/v2.0/sfc/port_pairs/<pair_id>.json",
+                              "/v2.0/sfc/port_pairs/<pair_id>",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortPairsList, "/v2.0/sfc/port_pairs.json", "/v2.0/sfc/port_pairs",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortPairsShow, "/v2.0/sfc/port_pairs/<pair_id>.json",
+                              "/v2.0/sfc/port_pairs/<pair_id>",
+                              resource_class_kwargs={'api': self})
 
+        self.api.add_resource(SFC.PortPairGroupCreate, "/v2.0/sfc/port_pair_groups.json", "/v2.0/sfc/port_pair_groups",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortPairGroupUpdate, "/v2.0/sfc/port_pair_groups/<group_id>.json",
+                              "/v2.0/sfc/port_pair_groups/<group_id>",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortPairGroupDelete, "/v2.0/sfc/port_pair_groups/<group_id>.json",
+                              "/v2.0/sfc/port_pair_groups/<group_id>",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortPairGroupList, "/v2.0/sfc/port_pair_groups.json", "/v2.0/sfc/port_pair_groups",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortPairGroupShow, "/v2.0/sfc/port_pair_groups/<group_id>.json",
+                              "/v2.0/sfc/port_pair_groups/<group_id>",
+                              resource_class_kwargs={'api': self})
 
-class Shutdown(Resource):
-    def get(self):
-        logging.debug(("%s is beeing shut down") % (__name__))
-        func = request.environ.get('werkzeug.server.shutdown')
-        if func is None:
-            raise RuntimeError('Not running with the Werkzeug Server')
-        func()
+        self.api.add_resource(SFC.FlowClassifierCreate, "/v2.0/sfc/flow_classifiers.json", "/v2.0/sfc/flow_classifiers",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.FlowClassifierUpdate, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
+                              "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.FlowClassifierDelete, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
+                              "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.FlowClassifierList, "/v2.0/sfc/flow_classifiers.json", "/v2.0/sfc/flow_classifiers",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.FlowClassifierShow, "/v2.0/sfc/flow_classifiers/<flow_classifier_id>.json",
+                              "/v2.0/sfc/flow_classifiers/<flow_classifier_id>",
+                              resource_class_kwargs={'api': self})
+
+        self.api.add_resource(SFC.PortChainCreate, "/v2.0/sfc/port_chains.json", "/v2.0/sfc/port_chains",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortChainUpdate, "/v2.0/sfc/port_chains/<chain_id>.json",
+                              "/v2.0/sfc/port_chains/<chain_id>",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortChainDelete, "/v2.0/sfc/port_chains/<chain_id>.json",
+                              "/v2.0/sfc/port_chains/<chain_id>",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortChainList, "/v2.0/sfc/port_chains.json", "/v2.0/sfc/port_chains",
+                              resource_class_kwargs={'api': self})
+        self.api.add_resource(SFC.PortChainShow, "/v2.0/sfc/port_chains/<chain_id>.json",
+                              "/v2.0/sfc/port_chains/<chain_id>",
+                              resource_class_kwargs={'api': self})
 
 
 class NeutronListAPIVersions(Resource):
@@ -73,7 +149,7 @@ class NeutronListAPIVersions(Resource):
         :return: Returns a json with API versions.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: Neutron - List API Versions")
+        LOG.debug("API CALL: Neutron - List API Versions")
         resp = dict()
         resp['versions'] = dict()
 
@@ -100,7 +176,7 @@ class NeutronShowAPIv2Details(Resource):
         :return: Returns a json with API details.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
         resp = dict()
 
         resp['resources'] = dict()
@@ -151,15 +227,20 @@ class NeutronListNetworks(Resource):
         :return: Returns a json response, starting with 'networks' as root node.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
+        # LOG.debug("ARGS: {}".format(request.args))
         try:
             if request.args.get('name'):
                 tmp_network = NeutronShowNetwork(self.api)
-                return tmp_network.get_network(request.args.get('name'), True)
+                response = tmp_network.get_network(request.args.get('name'), True)
+                LOG.debug("{} RESPONSE (1): {}".format(self.__class__.__name__, response))
+                return response
             id_list = request.args.getlist('id')
             if len(id_list) == 1:
                 tmp_network = NeutronShowNetwork(self.api)
-                return tmp_network.get_network(request.args.get('id'), True)
+                response = tmp_network.get_network(request.args.get('id'), True)
+                LOG.debug("{} RESPONSE (2): {}".format(self.__class__.__name__, response))
+                return response
 
             network_list = list()
             network_dict = dict()
@@ -177,11 +258,11 @@ class NeutronListNetworks(Resource):
                             network_list.append(tmp_network_dict)
 
             network_dict["networks"] = network_list
-
+            LOG.debug("{} RESPONSE (3): {}".format(self.__class__.__name__, network_dict))
             return Response(json.dumps(network_dict), status=200, mimetype='application/json')
 
         except Exception as ex:
-            logging.exception("Neutron: List networks exception.")
+            LOG.exception("Neutron: List networks exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -198,7 +279,7 @@ class NeutronShowNetwork(Resource):
         :return: Returns a json response, starting with 'network' as root node and one network description.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
         return self.get_network(network_id, False)
 
     def get_network(self, network_name_or_id, as_list):
@@ -245,7 +326,7 @@ class NeutronCreateNetwork(Resource):
             * 201, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s POST" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
         try:
             network_dict = json.loads(request.data)
             name = network_dict['network']['name']
@@ -256,7 +337,7 @@ class NeutronCreateNetwork(Resource):
             net = self.api.compute.create_network(name)
             return Response(json.dumps({"network": net.create_network_dict()}), status=201, mimetype='application/json')
         except Exception as ex:
-            logging.exception("Neutron: Create network excepiton.")
+            LOG.exception("Neutron: Create network excepiton.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -275,7 +356,7 @@ class NeutronUpdateNetwork(Resource):
             * 200, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s PUT" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s PUT" % str(self.__class__.__name__))
         try:
             if network_id in self.api.compute.nets:
                 net = self.api.compute.nets[network_id]
@@ -300,7 +381,7 @@ class NeutronUpdateNetwork(Resource):
             return Response('Network not found.\n', status=404, mimetype='application/json')
 
         except Exception as ex:
-            logging.exception("Neutron: Show networks exception.")
+            LOG.exception("Neutron: Show networks exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -319,7 +400,7 @@ class NeutronDeleteNetwork(Resource):
             * 204, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
         try:
             if network_id not in self.api.compute.nets:
                 return Response('Could not find network. (' + network_id + ')\n',
@@ -334,9 +415,9 @@ class NeutronDeleteNetwork(Resource):
 
             self.api.compute.delete_network(network_id)
 
-            return Response('Network ' + str(network_id) + ' deleted.\n', status=204, mimetype='application/json')
+            return Response('', status=204, mimetype='application/json')
         except Exception as ex:
-            logging.exception("Neutron: Delete network exception.")
+            LOG.exception("Neutron: Delete network exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -352,7 +433,7 @@ class NeutronListSubnets(Resource):
         :return: Returns a json response, starting with 'subnets' as root node.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
         try:
             if request.args.get('name'):
                 show_subnet = NeutronShowSubnet(self.api)
@@ -381,7 +462,7 @@ class NeutronListSubnets(Resource):
             return Response(json.dumps(subnet_dict), status=200, mimetype='application/json')
 
         except Exception as ex:
-            logging.exception("Neutron: List subnets exception.")
+            LOG.exception("Neutron: List subnets exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -398,7 +479,7 @@ class NeutronShowSubnet(Resource):
         :return: Returns a json response, starting with 'subnet' as root node and one subnet description.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
         return self.get_subnet(subnet_id, False)
 
     def get_subnet(self, subnet_name_or_id, as_list):
@@ -426,7 +507,7 @@ class NeutronShowSubnet(Resource):
             return Response('Subnet not found. (' + subnet_name_or_id + ')\n', status=404, mimetype='application/json')
 
         except Exception as ex:
-            logging.exception("Neutron: Show subnet exception.")
+            LOG.exception("Neutron: Show subnet exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -445,7 +526,7 @@ class NeutronCreateSubnet(Resource):
             * 201, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s POST" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
         try:
             subnet_dict = json.loads(request.data)
             net = self.api.compute.find_network_by_name_or_id(subnet_dict['subnet']['network_id'])
@@ -455,6 +536,7 @@ class NeutronCreateSubnet(Resource):
 
             net.subnet_name = subnet_dict["subnet"].get('name', str(net.name) + '-sub')
             if net.subnet_id is not None:
+                LOG.error("Only one subnet per network is supported: {}".format(net.subnet_id))
                 return Response('Only one subnet per network is supported\n', status=409, mimetype='application/json')
 
             if "id" in subnet_dict["subnet"]:
@@ -478,7 +560,7 @@ class NeutronCreateSubnet(Resource):
             return Response(json.dumps({'subnet': net.create_subnet_dict()}), status=201, mimetype='application/json')
 
         except Exception as ex:
-            logging.exception("Neutron: Create network excepiton.")
+            LOG.exception("Neutron: Create network excepiton.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -497,7 +579,7 @@ class NeutronUpdateSubnet(Resource):
             * 200, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s PUT" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s PUT" % str(self.__class__.__name__))
         try:
             for net in self.api.compute.nets.values():
                 if net.subnet_id == subnet_id:
@@ -529,7 +611,7 @@ class NeutronUpdateSubnet(Resource):
             return Response('Network not found.\n', status=404, mimetype='application/json')
 
         except Exception as ex:
-            logging.exception("Neutron: Show networks exception.")
+            LOG.exception("Neutron: Show networks exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -548,13 +630,16 @@ class NeutronDeleteSubnet(Resource):
             * 204, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
         try:
             for net in self.api.compute.nets.values():
                 if net.subnet_id == subnet_id:
                     for server in self.api.compute.computeUnits.values():
                         for port_name in server.port_names:
                             port = self.api.compute.find_port_by_name_or_id(port_name)
+                            if port is None:
+                                LOG.warning("Port search for {} returned None.".format(port_name))
+                                continue
                             if port.net_name == net.name:
                                 port.ip_address = None
                                 self.api.compute.dc.net.removeLink(
@@ -565,12 +650,11 @@ class NeutronDeleteSubnet(Resource):
 
                     net.delete_subnet()
 
-                    return Response('Subnet ' + str(subnet_id) + ' deleted.\n',
-                                    status=204, mimetype='application/json')
+                    return Response('', status=204, mimetype='application/json')
 
             return Response('Could not find subnet.', status=404, mimetype='application/json')
         except Exception as ex:
-            logging.exception("Neutron: Delete subnet exception.")
+            LOG.exception("Neutron: Delete subnet exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -586,7 +670,7 @@ class NeutronListPorts(Resource):
         :return: Returns a json response, starting with 'ports' as root node.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
         try:
             if request.args.get('name'):
                 show_port = NeutronShowPort(self.api)
@@ -614,7 +698,7 @@ class NeutronListPorts(Resource):
             return Response(json.dumps(port_dict), status=200, mimetype='application/json')
 
         except Exception as ex:
-            logging.exception("Neutron: List ports exception.")
+            LOG.exception("Neutron: List ports exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -631,7 +715,7 @@ class NeutronShowPort(Resource):
         :return: Returns a json response, starting with 'port' as root node and one network description.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s GET" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s GET" % str(self.__class__.__name__))
         return self.get_port(port_id, False)
 
     def get_port(self, port_name_or_id, as_list):
@@ -657,7 +741,7 @@ class NeutronShowPort(Resource):
                 tmp_dict["port"] = tmp_port_dict
             return Response(json.dumps(tmp_dict), status=200, mimetype='application/json')
         except Exception as ex:
-            logging.exception("Neutron: Show port exception.")
+            LOG.exception("Neutron: Show port exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -674,7 +758,7 @@ class NeutronCreatePort(Resource):
             * 201, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s POST" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
         try:
             port_dict = json.loads(request.data)
             net_id = port_dict['port']['network_id']
@@ -721,7 +805,7 @@ class NeutronCreatePort(Resource):
             return Response(json.dumps({'port': port.create_port_dict(self.api.compute)}), status=201,
                             mimetype='application/json')
         except Exception as ex:
-            logging.exception("Neutron: Show port exception.")
+            LOG.exception("Neutron: Show port exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -740,7 +824,7 @@ class NeutronUpdatePort(Resource):
             * 200, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s PUT" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s PUT" % str(self.__class__.__name__))
         try:
             port_dict = json.loads(request.data)
             port = self.api.compute.find_port_by_name_or_id(port_id)
@@ -782,7 +866,7 @@ class NeutronUpdatePort(Resource):
             return Response(json.dumps({'port': port.create_port_dict(self.api.compute)}), status=200,
                             mimetype='application/json')
         except Exception as ex:
-            logging.exception("Neutron: Update port exception.")
+            LOG.exception("Neutron: Update port exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -801,7 +885,7 @@ class NeutronDeletePort(Resource):
             * 204, if everything worked out.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s DELETE" % str(self.__class__.__name__))
         try:
             port = self.api.compute.find_port_by_name_or_id(port_id)
             if port is None:
@@ -823,10 +907,10 @@ class NeutronDeletePort(Resource):
             # delete the port
             self.api.compute.delete_port(port.id)
 
-            return Response('Port ' + port_id + ' deleted.\n', status=204, mimetype='application/json')
+            return Response('', status=204, mimetype='application/json')
 
         except Exception as ex:
-            logging.exception("Neutron: Delete port exception.")
+            LOG.exception("Neutron: Delete port exception.")
             return Response(ex.message, status=500, mimetype='application/json')
 
 
@@ -845,7 +929,7 @@ class NeutronAddFloatingIp(Resource):
         resp["floatingips"] = list()
         # create a list of floting IP definitions and return it
         for i in range(100, 110):
-            ip=dict()
+            ip = dict()
             ip["router_id"] = "router_id"
             ip["description"] = "hardcoded in api"
             ip["created_at"] = "router_id"
@@ -862,7 +946,6 @@ class NeutronAddFloatingIp(Resource):
             resp["floatingips"].append(ip)
         return Response(json.dumps(resp), status=200, mimetype='application/json')
 
-
     def post(self):
         """
         Adds a floating IP to neutron.
@@ -870,7 +953,7 @@ class NeutronAddFloatingIp(Resource):
         :return: Returns a floating network description.
         :rtype: :class:`flask.response`
         """
-        logging.debug("API CALL: %s POST" % str(self.__class__.__name__))
+        LOG.debug("API CALL: %s POST" % str(self.__class__.__name__))
         try:
             # Fiddle with floating_network !
             req = json.loads(request.data)
@@ -911,5 +994,5 @@ class NeutronAddFloatingIp(Resource):
 
             return Response(json.dumps(response), status=200, mimetype='application/json')
         except Exception as ex:
-            logging.exception("Neutron: Create FloatingIP exception %s.", ex)
+            LOG.exception("Neutron: Create FloatingIP exception %s.", ex)
             return Response(ex.message, status=500, mimetype='application/json')