Merge pull request #368 from insequent/Replacing_post_update_logic
Removing POST update logic
This commit is contained in:
commit
f4ad7bca8a
@ -1,99 +0,0 @@
|
|||||||
# Copyright (c) 2013 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
from neutron.api import extensions
|
|
||||||
from neutron import manager
|
|
||||||
from neutron import wsgi
|
|
||||||
|
|
||||||
RESOURCE_NAME = "port"
|
|
||||||
RESOURCE_COLLECTION = RESOURCE_NAME + "s"
|
|
||||||
EXTENDED_ATTRIBUTES_2_0 = {
|
|
||||||
RESOURCE_COLLECTION: {
|
|
||||||
"network_id": {"allow_post": True, "default": '',
|
|
||||||
"is_visible": True},
|
|
||||||
"tenant_id": {"allow_post": True, "default": '',
|
|
||||||
"is_visible": True},
|
|
||||||
"segment_id": {"allow_post": True, "default": False},
|
|
||||||
"bridge": {'allow_post': False, 'allow_put': False,
|
|
||||||
'default': False, 'is_visible': True}}}
|
|
||||||
|
|
||||||
|
|
||||||
class QuarkPortsUpdateHandler(object):
|
|
||||||
def __init__(self, plugin):
|
|
||||||
self._plugin = plugin
|
|
||||||
|
|
||||||
def handle(self, request, response):
|
|
||||||
deserializer = wsgi.JSONDeserializer()
|
|
||||||
serializer = wsgi.JSONDictSerializer()
|
|
||||||
|
|
||||||
path = [part for part in request.path_url.split("/") if part]
|
|
||||||
id = path[-1].split('.')[0]
|
|
||||||
|
|
||||||
body = None
|
|
||||||
if request.body:
|
|
||||||
body = deserializer.deserialize(request.body)['body']
|
|
||||||
|
|
||||||
api_response = self._plugin.post_update_port(request.context,
|
|
||||||
id,
|
|
||||||
body)
|
|
||||||
return serializer.serialize({"port": api_response})
|
|
||||||
|
|
||||||
|
|
||||||
class Ports_quark(object):
|
|
||||||
"""Extends ports for quark API purposes.
|
|
||||||
|
|
||||||
* Allows for DELETE (disassociation of port) with IP address
|
|
||||||
* Allows for POST with fixed_ip in body to associate additional IPs
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_name(cls):
|
|
||||||
return "Quark Ports API Extension"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_alias(cls):
|
|
||||||
return "ports_quark"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_description(cls):
|
|
||||||
return "Quark Ports API Extension"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_namespace(cls):
|
|
||||||
return ("http://docs.openstack.org/network/ext/"
|
|
||||||
"port_disassociate/api/v2.0")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_updated(cls):
|
|
||||||
return "2013-03-25T19:00:00-00:00"
|
|
||||||
|
|
||||||
def get_extended_resources(self, version):
|
|
||||||
if version == "2.0":
|
|
||||||
return EXTENDED_ATTRIBUTES_2_0
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_request_extensions(cls):
|
|
||||||
exts = []
|
|
||||||
|
|
||||||
quark_ports_update_handler = QuarkPortsUpdateHandler(
|
|
||||||
manager.NeutronManager.get_plugin())
|
|
||||||
extension = extensions.RequestExtension(
|
|
||||||
"POST", "/ports/:(id)",
|
|
||||||
quark_ports_update_handler.handle)
|
|
||||||
exts.append(extension)
|
|
||||||
|
|
||||||
return exts
|
|
@ -119,10 +119,9 @@ def sessioned(func):
|
|||||||
class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
||||||
sg_ext.SecurityGroupPluginBase):
|
sg_ext.SecurityGroupPluginBase):
|
||||||
supported_extension_aliases = ["mac_address_ranges", "routes",
|
supported_extension_aliases = ["mac_address_ranges", "routes",
|
||||||
"ip_addresses", "ports_quark",
|
"ip_addresses", "security-group",
|
||||||
"security-group", "diagnostics",
|
"diagnostics", "subnets_quark",
|
||||||
"subnets_quark", "provider",
|
"provider", "ip_policies", "quotas",
|
||||||
"ip_policies", "quotas",
|
|
||||||
"networks_quark", "router",
|
"networks_quark", "router",
|
||||||
"ip_availabilities"]
|
"ip_availabilities"]
|
||||||
|
|
||||||
@ -133,7 +132,7 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
"""Will add the tenant_id to the context from body.
|
"""Will add the tenant_id to the context from body.
|
||||||
|
|
||||||
It is assumed that the body must have a tenant_id because neutron
|
It is assumed that the body must have a tenant_id because neutron
|
||||||
core would have never got here in such a situation.
|
core could never have gotten here otherwise.
|
||||||
"""
|
"""
|
||||||
if context.tenant_id is None:
|
if context.tenant_id is None:
|
||||||
context.tenant_id = resource["tenant_id"]
|
context.tenant_id = resource["tenant_id"]
|
||||||
@ -247,10 +246,6 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
|||||||
self._fix_missing_tenant_id(context, port["port"])
|
self._fix_missing_tenant_id(context, port["port"])
|
||||||
return ports.create_port(context, port)
|
return ports.create_port(context, port)
|
||||||
|
|
||||||
@sessioned
|
|
||||||
def post_update_port(self, context, id, port):
|
|
||||||
return ports.post_update_port(context, id, port)
|
|
||||||
|
|
||||||
@sessioned
|
@sessioned
|
||||||
def get_port(self, context, id, fields=None):
|
def get_port(self, context, id, fields=None):
|
||||||
return ports.get_port(context, id, fields)
|
return ports.get_port(context, id, fields)
|
||||||
|
@ -37,8 +37,8 @@ STRATEGY = network_strategy.STRATEGY
|
|||||||
# HACK(amir): RM9305: do not allow a tenant to associate a network to a port
|
# HACK(amir): RM9305: do not allow a tenant to associate a network to a port
|
||||||
# that does not belong to them unless it is publicnet or servicenet
|
# that does not belong to them unless it is publicnet or servicenet
|
||||||
def _raise_if_unauthorized(tenant_id, net):
|
def _raise_if_unauthorized(tenant_id, net):
|
||||||
if (not STRATEGY.is_parent_network(net["id"])
|
if (not STRATEGY.is_parent_network(net["id"]) and
|
||||||
and net["tenant_id"] != tenant_id):
|
net["tenant_id"] != tenant_id):
|
||||||
raise exceptions.NotAuthorized()
|
raise exceptions.NotAuthorized()
|
||||||
|
|
||||||
|
|
||||||
@ -403,58 +403,6 @@ def update_port(context, id, port):
|
|||||||
return v._make_port_dict(port_db)
|
return v._make_port_dict(port_db)
|
||||||
|
|
||||||
|
|
||||||
def post_update_port(context, id, port):
|
|
||||||
LOG.info("post_update_port %s for tenant %s" % (id, context.tenant_id))
|
|
||||||
if not port.get("port"):
|
|
||||||
raise exceptions.BadRequest(resource="ports",
|
|
||||||
msg="Port body required")
|
|
||||||
|
|
||||||
port_db = db_api.port_find(context, id=id, scope=db_api.ONE)
|
|
||||||
if not port_db:
|
|
||||||
raise exceptions.PortNotFound(port_id=id, net_id="")
|
|
||||||
|
|
||||||
port = port["port"]
|
|
||||||
if "fixed_ips" in port and port["fixed_ips"]:
|
|
||||||
for ip in port["fixed_ips"]:
|
|
||||||
address = None
|
|
||||||
ipam_driver = ipam.IPAM_REGISTRY.get_strategy(
|
|
||||||
port_db["network"]["ipam_strategy"])
|
|
||||||
if ip:
|
|
||||||
if "ip_id" in ip:
|
|
||||||
ip_id = ip["ip_id"]
|
|
||||||
address = db_api.ip_address_find(
|
|
||||||
context, id=ip_id, tenant_id=context.tenant_id,
|
|
||||||
scope=db_api.ONE)
|
|
||||||
elif "ip_address" in ip:
|
|
||||||
ip_address = ip["ip_address"]
|
|
||||||
net_address = netaddr.IPAddress(ip_address)
|
|
||||||
address = db_api.ip_address_find(
|
|
||||||
context, ip_address=net_address,
|
|
||||||
network_id=port_db["network_id"],
|
|
||||||
tenant_id=context.tenant_id, scope=db_api.ONE)
|
|
||||||
if not address:
|
|
||||||
address = ipam_driver.allocate_ip_address(
|
|
||||||
context, port_db["network_id"], id,
|
|
||||||
CONF.QUARK.ipam_reuse_after,
|
|
||||||
ip_addresses=[ip_address])
|
|
||||||
else:
|
|
||||||
address = ipam_driver.allocate_ip_address(
|
|
||||||
context, port_db["network_id"], id,
|
|
||||||
CONF.QUARK.ipam_reuse_after)
|
|
||||||
|
|
||||||
address["deallocated"] = 0
|
|
||||||
|
|
||||||
already_contained = False
|
|
||||||
for port_address in port_db["ip_addresses"]:
|
|
||||||
if address["id"] == port_address["id"]:
|
|
||||||
already_contained = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if not already_contained:
|
|
||||||
port_db["ip_addresses"].append(address)
|
|
||||||
return v._make_port_dict(port_db)
|
|
||||||
|
|
||||||
|
|
||||||
def get_port(context, id, fields=None):
|
def get_port(context, id, fields=None):
|
||||||
"""Retrieve a port.
|
"""Retrieve a port.
|
||||||
|
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
# Copyright 2015 Openstack Foundation
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
import json
|
|
||||||
import mock
|
|
||||||
from oslo_log import log as logging
|
|
||||||
|
|
||||||
from quark.api.extensions import ports_quark
|
|
||||||
from quark.tests.functional.base import BaseFunctionalTest
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class TestAPIExtensionPortsQuark(BaseFunctionalTest):
|
|
||||||
def test_QuarkPortsUpdateHandler(self):
|
|
||||||
mock_plugin = mock.MagicMock()
|
|
||||||
mock_request = mock.MagicMock()
|
|
||||||
mock_response = mock.MagicMock()
|
|
||||||
body = '"lots of stuff"'
|
|
||||||
port_id = "I_am_a_port"
|
|
||||||
|
|
||||||
handler = ports_quark.QuarkPortsUpdateHandler(mock_plugin)
|
|
||||||
self.assertEqual(handler._plugin, mock_plugin)
|
|
||||||
|
|
||||||
mock_plugin.post_update_port.return_value = {"id": port_id,
|
|
||||||
"body": body.strip('"')}
|
|
||||||
mock_request.body = body
|
|
||||||
mock_request.path_url = '/v2.0/ports/{}'.format(port_id)
|
|
||||||
expected = ('{{"port": {{"id": "{0}", "body": "{1}"}}}}'
|
|
||||||
''.format(port_id, body.strip('"')))
|
|
||||||
result = handler.handle(mock_request, mock_response)
|
|
||||||
self.assertEqual(json.loads(expected), json.loads(result))
|
|
@ -1136,143 +1136,6 @@ class TestQuarkUpdatePortSetsIps(test_quark_plugin.TestQuarkPlugin):
|
|||||||
self.assertTrue(self.called)
|
self.assertTrue(self.called)
|
||||||
|
|
||||||
|
|
||||||
class TestQuarkPostUpdatePort(test_quark_plugin.TestQuarkPlugin):
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def _stubs(self, port, addr, addr2=None, port_ips=None):
|
|
||||||
port_model = None
|
|
||||||
addr_model = None
|
|
||||||
addr_model2 = None
|
|
||||||
if port:
|
|
||||||
port_model = models.Port()
|
|
||||||
port_model.update(port)
|
|
||||||
if port_ips:
|
|
||||||
port_model["ip_addresses"] = []
|
|
||||||
for ip in port_ips:
|
|
||||||
ip_mod = models.IPAddress()
|
|
||||||
ip_mod.update(ip)
|
|
||||||
port_model["ip_addresses"].append(ip_mod)
|
|
||||||
net_model = models.Network()
|
|
||||||
net_model["ipam_strategy"] = "ANY"
|
|
||||||
port_model["network"] = net_model
|
|
||||||
|
|
||||||
if addr:
|
|
||||||
addr_model = models.IPAddress()
|
|
||||||
addr_model.update(addr)
|
|
||||||
if addr2:
|
|
||||||
addr_model2 = models.IPAddress()
|
|
||||||
addr_model2.update(addr2)
|
|
||||||
with contextlib.nested(
|
|
||||||
mock.patch("quark.db.api.port_find"),
|
|
||||||
mock.patch("quark.ipam.QuarkIpam.allocate_ip_address"),
|
|
||||||
mock.patch("quark.db.api.ip_address_find"),
|
|
||||||
) as (port_find, alloc_ip, ip_find):
|
|
||||||
port_find.return_value = port_model
|
|
||||||
alloc_ip.return_value = addr_model2 if addr_model2 else addr_model
|
|
||||||
ip_find.return_value = addr_model
|
|
||||||
yield port_find, alloc_ip, ip_find
|
|
||||||
|
|
||||||
def test_post_update_port_no_ports(self):
|
|
||||||
with self._stubs(port=None, addr=None):
|
|
||||||
with self.assertRaises(exceptions.PortNotFound):
|
|
||||||
self.plugin.post_update_port(self.context, 1,
|
|
||||||
{"port": {"network_id": 1}})
|
|
||||||
|
|
||||||
def test_post_update_port_fixed_ips_empty_body(self):
|
|
||||||
port = dict(port=dict(network_id=1, tenant_id=self.context.tenant_id,
|
|
||||||
device_id=2))
|
|
||||||
with self._stubs(port=port, addr=None):
|
|
||||||
with self.assertRaises(exceptions.BadRequest):
|
|
||||||
self.plugin.post_update_port(self.context, 1, {})
|
|
||||||
with self.assertRaises(exceptions.BadRequest):
|
|
||||||
self.plugin.post_update_port(self.context, 1, {"port": {}})
|
|
||||||
|
|
||||||
def test_post_update_port_fixed_ips_ip(self):
|
|
||||||
new_port_ip = dict(port=dict(fixed_ips=[dict()]))
|
|
||||||
port = dict(port=dict(network_id=1, tenant_id=self.context.tenant_id,
|
|
||||||
device_id=2))
|
|
||||||
ip = dict(id=1, address=netaddr.IPAddress('192.168.1.100'),
|
|
||||||
address_readable="192.168.1.100", subnet_id=1, network_id=2,
|
|
||||||
version=4, deallocated=True)
|
|
||||||
with self._stubs(port=port, addr=ip) as (port_find, alloc_ip, ip_find):
|
|
||||||
response = self.plugin.post_update_port(self.context, 1,
|
|
||||||
new_port_ip)
|
|
||||||
self.assertEqual(port_find.call_count, 1)
|
|
||||||
self.assertEqual(alloc_ip.call_count, 1)
|
|
||||||
self.assertEqual(ip_find.call_count, 0)
|
|
||||||
self.assertEqual(response["fixed_ips"][0]["ip_address"],
|
|
||||||
"192.168.1.100")
|
|
||||||
|
|
||||||
def test_post_update_port_fixed_ips_ip_id(self):
|
|
||||||
new_port_ip = dict(port=dict(fixed_ips=[dict(ip_id=1)]))
|
|
||||||
port = dict(port=dict(network_id=1, tenant_id=self.context.tenant_id,
|
|
||||||
device_id=2))
|
|
||||||
ip = dict(id=1, address=netaddr.IPAddress('192.168.1.100'),
|
|
||||||
address_readable="192.168.1.100", subnet_id=1, network_id=2,
|
|
||||||
version=4, deallocated=True)
|
|
||||||
with self._stubs(port=port, addr=ip) as (port_find, alloc_ip, ip_find):
|
|
||||||
response = self.plugin.post_update_port(self.context, 1,
|
|
||||||
new_port_ip)
|
|
||||||
self.assertEqual(port_find.call_count, 1)
|
|
||||||
self.assertEqual(alloc_ip.call_count, 0)
|
|
||||||
self.assertEqual(ip_find.call_count, 1)
|
|
||||||
self.assertEqual(response["fixed_ips"][0]["ip_address"],
|
|
||||||
"192.168.1.100")
|
|
||||||
|
|
||||||
def test_post_update_port_fixed_ips_ip_address_exists(self):
|
|
||||||
new_port_ip = dict(port=dict(fixed_ips=[dict(
|
|
||||||
ip_address="192.168.1.100")]))
|
|
||||||
port = dict(port=dict(network_id=1, tenant_id=self.context.tenant_id,
|
|
||||||
device_id=2))
|
|
||||||
ip = dict(id=1, address=netaddr.IPAddress('192.168.1.100'),
|
|
||||||
address_readable="192.168.1.100", subnet_id=1, network_id=2,
|
|
||||||
version=4, deallocated=True)
|
|
||||||
with self._stubs(port=port, addr=ip) as (port_find, alloc_ip, ip_find):
|
|
||||||
response = self.plugin.post_update_port(self.context, 1,
|
|
||||||
new_port_ip)
|
|
||||||
self.assertEqual(port_find.call_count, 1)
|
|
||||||
self.assertEqual(alloc_ip.call_count, 0)
|
|
||||||
self.assertEqual(ip_find.call_count, 1)
|
|
||||||
self.assertEqual(response["fixed_ips"][0]["ip_address"],
|
|
||||||
"192.168.1.100")
|
|
||||||
|
|
||||||
def test_post_update_port_fixed_ips_ip_address_doesnt_exist(self):
|
|
||||||
new_port_ip = dict(port=dict(fixed_ips=[dict(
|
|
||||||
ip_address="192.168.1.101")]))
|
|
||||||
port = dict(port=dict(network_id=1, tenant_id=self.context.tenant_id,
|
|
||||||
device_id=2))
|
|
||||||
ip = dict(id=1, address=3232235876, address_readable="192.168.1.101",
|
|
||||||
subnet_id=1, network_id=2, version=4, deallocated=True)
|
|
||||||
with self._stubs(port=port, addr=None, addr2=ip) as (port_find,
|
|
||||||
alloc_ip,
|
|
||||||
ip_find):
|
|
||||||
response = self.plugin.post_update_port(self.context, 1,
|
|
||||||
new_port_ip)
|
|
||||||
self.assertEqual(port_find.call_count, 1)
|
|
||||||
self.assertEqual(alloc_ip.call_count, 1)
|
|
||||||
self.assertEqual(ip_find.call_count, 1)
|
|
||||||
self.assertEqual(response["fixed_ips"][0]["ip_address"],
|
|
||||||
"192.168.1.101")
|
|
||||||
|
|
||||||
def test_post_update_port_already_has_ip(self):
|
|
||||||
new_port_ip = dict(port=dict(fixed_ips=[dict()]))
|
|
||||||
port = dict(port=dict(network_id=1, tenant_id=self.context.tenant_id,
|
|
||||||
device_id=2))
|
|
||||||
ip = dict(id=1, address=netaddr.IPAddress('192.168.1.100'),
|
|
||||||
address_readable="192.168.1.100", subnet_id=1, network_id=2,
|
|
||||||
version=4, deallocated=True)
|
|
||||||
port_ips = [ip]
|
|
||||||
with self._stubs(port=port, addr=ip, port_ips=port_ips) as (port_find,
|
|
||||||
alloc_ip,
|
|
||||||
ip_find):
|
|
||||||
response = self.plugin.post_update_port(self.context, 1,
|
|
||||||
new_port_ip)
|
|
||||||
self.assertEqual(port_find.call_count, 1)
|
|
||||||
self.assertEqual(alloc_ip.call_count, 1)
|
|
||||||
self.assertEqual(ip_find.call_count, 0)
|
|
||||||
self.assertEqual(response["fixed_ips"][0]["ip_address"],
|
|
||||||
"192.168.1.100")
|
|
||||||
|
|
||||||
|
|
||||||
class TestQuarkCreatePortOnSharedNetworks(test_quark_plugin.TestQuarkPlugin):
|
class TestQuarkCreatePortOnSharedNetworks(test_quark_plugin.TestQuarkPlugin):
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def _stubs(self, port=None, network=None, addr=None, mac=None):
|
def _stubs(self, port=None, network=None, addr=None, mac=None):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user