Merge pull request #368 from insequent/Replacing_post_update_logic

Removing POST update logic
This commit is contained in:
Amir Sadoughi 2015-03-31 11:17:37 -05:00
commit f4ad7bca8a
5 changed files with 6 additions and 343 deletions

View File

@ -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

View File

@ -119,10 +119,9 @@ def sessioned(func):
class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
sg_ext.SecurityGroupPluginBase):
supported_extension_aliases = ["mac_address_ranges", "routes",
"ip_addresses", "ports_quark",
"security-group", "diagnostics",
"subnets_quark", "provider",
"ip_policies", "quotas",
"ip_addresses", "security-group",
"diagnostics", "subnets_quark",
"provider", "ip_policies", "quotas",
"networks_quark", "router",
"ip_availabilities"]
@ -133,7 +132,7 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
"""Will add the tenant_id to the context from body.
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:
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"])
return ports.create_port(context, port)
@sessioned
def post_update_port(self, context, id, port):
return ports.post_update_port(context, id, port)
@sessioned
def get_port(self, context, id, fields=None):
return ports.get_port(context, id, fields)

View File

@ -37,8 +37,8 @@ STRATEGY = network_strategy.STRATEGY
# 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
def _raise_if_unauthorized(tenant_id, net):
if (not STRATEGY.is_parent_network(net["id"])
and net["tenant_id"] != tenant_id):
if (not STRATEGY.is_parent_network(net["id"]) and
net["tenant_id"] != tenant_id):
raise exceptions.NotAuthorized()
@ -403,58 +403,6 @@ def update_port(context, id, port):
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):
"""Retrieve a port.

View File

@ -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))

View File

@ -1136,143 +1136,6 @@ class TestQuarkUpdatePortSetsIps(test_quark_plugin.TestQuarkPlugin):
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):
@contextlib.contextmanager
def _stubs(self, port=None, network=None, addr=None, mac=None):