X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=src%2Femuvim%2Fapi%2Fopenstack%2Fopenstack_dummies%2Fneutron_dummy_api.py;h=6f6d3dc958d901b71d1942a6d8ff8cd2522606f6;hb=refs%2Fchanges%2F26%2F6026%2F1;hp=38a5ad4d419d53deb0ad8d40643c129b9a1e332a;hpb=ae58801332baaa66ea71c9e233e23f0f68a0afe2;p=osm%2Fvim-emu.git diff --git a/src/emuvim/api/openstack/openstack_dummies/neutron_dummy_api.py b/src/emuvim/api/openstack/openstack_dummies/neutron_dummy_api.py index 38a5ad4..6f6d3dc 100755 --- a/src/emuvim/api/openstack/openstack_dummies/neutron_dummy_api.py +++ b/src/emuvim/api/openstack/openstack_dummies/neutron_dummy_api.py @@ -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/.json", + "/v2.0/sfc/port_pairs/", + resource_class_kwargs={'api': self}) + self.api.add_resource(SFC.PortPairsDelete, "/v2.0/sfc/port_pairs/.json", + "/v2.0/sfc/port_pairs/", + 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/.json", + "/v2.0/sfc/port_pairs/", + 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/.json", + "/v2.0/sfc/port_pair_groups/", + resource_class_kwargs={'api': self}) + self.api.add_resource(SFC.PortPairGroupDelete, "/v2.0/sfc/port_pair_groups/.json", + "/v2.0/sfc/port_pair_groups/", + 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/.json", + "/v2.0/sfc/port_pair_groups/", + 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/.json", + "/v2.0/sfc/flow_classifiers/", + resource_class_kwargs={'api': self}) + self.api.add_resource(SFC.FlowClassifierDelete, "/v2.0/sfc/flow_classifiers/.json", + "/v2.0/sfc/flow_classifiers/", + 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/.json", + "/v2.0/sfc/flow_classifiers/", + 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/.json", + "/v2.0/sfc/port_chains/", + resource_class_kwargs={'api': self}) + self.api.add_resource(SFC.PortChainDelete, "/v2.0/sfc/port_chains/.json", + "/v2.0/sfc/port_chains/", + 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/.json", + "/v2.0/sfc/port_chains/", + 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')