Implemented the floating ip update API method

This commit is contained in:
Alan Quillin
2015-06-05 13:58:01 -05:00
parent ed60148090
commit 55d0f0685d
7 changed files with 387 additions and 65 deletions

View File

@@ -299,6 +299,12 @@ def ip_address_delete(context, addr):
context.session.delete(addr) context.session.delete(addr)
def ip_address_deallocate(context, address, **kwargs):
kwargs["_deallocated"] = 1
kwargs["deallocated_at"] = timeutils.utcnow()
return ip_address_update(context, address, **kwargs)
@scoped @scoped
def ip_address_find(context, lock_mode=False, **filters): def ip_address_find(context, lock_mode=False, **filters):
query = context.session.query(models.IPAddress) query = context.session.query(models.IPAddress)
@@ -898,12 +904,11 @@ def floating_ip_find(context, lock_mode=False, limit=None, sorts=None,
limit, sorts, marker) limit, sorts, marker)
def floating_ip_associate_fixed_ip(context, floating_ip, fixed_ip, def floating_ip_associate_fixed_ip(context, floating_ip, fixed_ip):
enable=True):
assoc = models.FloatingToFixedIPAssociation()
assoc.floating_ip_address_id = floating_ip.id
assoc.fixed_ip_address_id = fixed_ip.id
assoc.enabled = enable
context.session.add(assoc)
floating_ip.fixed_ip = fixed_ip floating_ip.fixed_ip = fixed_ip
return floating_ip return floating_ip
def floating_ip_disassociate_fixed_ip(context, floating_ip):
floating_ip.fixed_ip = None
return floating_ip

View File

@@ -59,8 +59,19 @@ class UnicornDriver(object):
LOG.error("register_floating_ip: %s" % msg) LOG.error("register_floating_ip: %s" % msg)
raise ex.RegisterFloatingIpFailure(id=floating_ip.id) raise ex.RegisterFloatingIpFailure(id=floating_ip.id)
def update_floating_ip(self, floating_ip): def update_floating_ip(self, floating_ip, port, fixed_ip):
pass url = "%s/%s" % (CONF.QUARK.floating_ip_base_url,
floating_ip["address_readable"])
req = self._build_request_body(floating_ip, port, fixed_ip)
LOG.info("Calling unicorn to register floating ip: %s %s" % (url, req))
r = requests.put(url, data=json.dumps(req))
if r.status_code != 200:
msg = "Unexpected status from unicorn API: Status Code %s, " \
"Message: %s" % (r.status_code, r.json())
LOG.error("register_floating_ip: %s" % msg)
raise ex.RegisterFloatingIpFailure(id=floating_ip.id)
def remove_floating_ip(self, floating_ip): def remove_floating_ip(self, floating_ip):
url = "%s/%s" % (CONF.QUARK.floating_ip_base_url, url = "%s/%s" % (CONF.QUARK.floating_ip_base_url,
@@ -69,7 +80,10 @@ class UnicornDriver(object):
LOG.info("Calling unicorn to remove floating ip: %s" % url) LOG.info("Calling unicorn to remove floating ip: %s" % url)
r = requests.delete(url) r = requests.delete(url)
if r.status_code != 204: if r.status_code == 404:
LOG.warn("The floating IP %s does not exist in the unicorn system."
% floating_ip.address_readable)
elif r.status_code != 204:
msg = "Unexpected status from unicorn API: Status Code %s, " \ msg = "Unexpected status from unicorn API: Status Code %s, " \
"Message: %s" % (r.status_code, r.json()) "Message: %s" % (r.status_code, r.json())
LOG.error("remove_floating_ip: %s" % msg) LOG.error("remove_floating_ip: %s" % msg)

View File

@@ -167,3 +167,13 @@ class NoAvailableFixedIPsForPort(exceptions.Conflict):
class PortDoesNotHaveAGateway(exceptions.Conflict): class PortDoesNotHaveAGateway(exceptions.Conflict):
message = _("Port %(port_id) does not have a gateway") message = _("Port %(port_id) does not have a gateway")
class PortAlreadyAssociatedToFloatingIP(exceptions.BadRequest):
message = _("Port %(port_id) is already associated with "
"floating IP %(flip_id)")
class FloatingIPUpdateNoPortIdSupplied(exceptions.BadRequest):
message = _("When no port is currently associated to the floating if, "
"port_id is required but was not supplied")

View File

@@ -413,7 +413,8 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
@sessioned @sessioned
def update_floatingip(self, context, id, floatingip): def update_floatingip(self, context, id, floatingip):
return floating_ips.update_floatingip(context, id, floatingip) return floating_ips.update_floatingip(context, id,
floatingip["floatingip"])
@sessioned @sessioned
def get_floatingip(self, context, id, fields=None): def get_floatingip(self, context, id, fields=None):

View File

@@ -20,7 +20,7 @@ from oslo_log import log as logging
from quark.db import api as db_api from quark.db import api as db_api
from quark.db import ip_types from quark.db import ip_types
from quark.drivers import floating_ip_registry as registry from quark.drivers import floating_ip_registry as registry
from quark import exceptions as quark_exceptions from quark import exceptions as qex
from quark import ipam from quark import ipam
from quark import plugin_views as v from quark import plugin_views as v
@@ -40,6 +40,17 @@ CONF.register_opts(quark_router_opts, "QUARK")
def create_floatingip(context, content): def create_floatingip(context, content):
"""Allocate or reallocate a floating IP.
:param context: neutron api request context.
:param content: dictionary describing the floating ip, with keys
as listed in the RESOURCE_ATTRIBUTE_MAP object in
neutron/api/v2/attributes.py. All keys will be populated.
:returns: Dictionary containing details for the new floating IP. If values
are declared in the fields parameter, then only those keys will be
present.
"""
LOG.info("create_floatingip %s for tenant %s and body %s" % LOG.info("create_floatingip %s for tenant %s and body %s" %
(id, context.tenant_id, content)) (id, context.tenant_id, content))
tenant_id = content.get("tenant_id") tenant_id = content.get("tenant_id")
@@ -69,12 +80,12 @@ def create_floatingip(context, content):
raise exceptions.PortNotFound(port_id=port_id) raise exceptions.PortNotFound(port_id=port_id)
if not port.ip_addresses or len(port.ip_addresses) == 0: if not port.ip_addresses or len(port.ip_addresses) == 0:
raise quark_exceptions.NoAvailableFixedIPsForPort(port_id=port_id) raise qex.NoAvailableFixedIPsForPort(port_id=port_id)
if not fixed_ip_address: if not fixed_ip_address:
fixed_ip = _get_next_available_fixed_ip(port) fixed_ip = _get_next_available_fixed_ip(port)
if not fixed_ip: if not fixed_ip:
raise quark_exceptions.NoAvailableFixedIPsForPort( raise qex.NoAvailableFixedIPsForPort(
port_id=port_id) port_id=port_id)
else: else:
fixed_ip = next((ip for ip in port.ip_addresses fixed_ip = next((ip for ip in port.ip_addresses
@@ -83,13 +94,13 @@ def create_floatingip(context, content):
None) None)
if not fixed_ip: if not fixed_ip:
raise quark_exceptions.FixedIpDoesNotExistsForPort( raise qex.FixedIpDoesNotExistsForPort(
fixed_ip=fixed_ip_address, port_id=port_id) fixed_ip=fixed_ip_address, port_id=port_id)
if any(ip for ip in port.ip_addresses if any(ip for ip in port.ip_addresses
if (ip.get("address_type") == ip_types.FLOATING and if (ip.get("address_type") == ip_types.FLOATING and
ip.fixed_ip["address_readable"] == fixed_ip_address)): ip.fixed_ip["address_readable"] == fixed_ip_address)):
raise quark_exceptions.PortAlreadyContainsFloatingIp( raise qex.PortAlreadyContainsFloatingIp(
port_id=port_id) port_id=port_id)
new_addresses = [] new_addresses = []
@@ -106,55 +117,145 @@ def create_floatingip(context, content):
ip_addresses=ip_addresses, ip_addresses=ip_addresses,
address_type=ip_types.FLOATING) address_type=ip_types.FLOATING)
floating_ip = new_addresses[0] flip = new_addresses[0]
if fixed_ip and port: if fixed_ip and port:
with context.session.begin(): with context.session.begin():
floating_ip = db_api.floating_ip_associate_fixed_ip(context, flip = db_api.port_associate_ip(context, [port], flip, [port_id])
floating_ip, flip = db_api.floating_ip_associate_fixed_ip(context, flip,
fixed_ip) fixed_ip)
flip_driver_type = CONF.QUARK.default_floating_ip_driver
flip_driver = registry.DRIVER_REGISTRY.get_driver(flip_driver_type)
flip_driver.register_floating_ip(flip, port, fixed_ip)
return v._make_floating_ip_dict(flip, port_id)
def update_floatingip(context, id, content):
"""Update an existing floating IP.
:param context: neutron api request context.
:param id: id of the floating ip
:param content: dictionary with keys indicating fields to update.
valid keys are those that have a value of True for 'allow_put'
as listed in the RESOURCE_ATTRIBUTE_MAP object in
neutron/api/v2/attributes.py.
:returns: Dictionary containing details for the new floating IP. If values
are declared in the fields parameter, then only those keys will be
present.
"""
LOG.info("update_floatingip %s for tenant %s and body %s" %
(id, context.tenant_id, content))
if "port_id" not in content:
raise exceptions.BadRequest(resource="floating_ip",
msg="port_id is required.")
port_id = content.get("port_id")
port = None
fixed_ip = None
current_port = None
flip = None
with context.session.begin():
flip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE)
current_ports = flip.ports
if current_ports and len(current_ports) > 0:
current_port = current_ports[0]
if not port_id and not current_port:
raise qex.FloatingIPUpdateNoPortIdSupplied()
if port_id:
port = db_api.port_find(context, id=port_id, scope=db_api.ONE)
if not port:
raise exceptions.PortNotFound(port_id=port_id)
if current_port and current_port.id == port_id:
d = dict(flip_id=id, port_id=port_id)
raise qex.PortAlreadyAssociatedToFloatingIP(**d)
fixed_ip = _get_next_available_fixed_ip(port)
LOG.info("new fixed ip: %s" % fixed_ip)
if not fixed_ip:
raise qex.NoAvailableFixedIPsForPort(port_id=port_id)
LOG.info("current ports: %s" % current_ports)
if current_port:
flip = db_api.port_disassociate_ip(context, [current_port], flip)
if flip.fixed_ip:
flip = db_api.floating_ip_disassociate_fixed_ip(context, flip)
if port:
flip = db_api.port_associate_ip(context, [port], flip, [port_id])
flip = db_api.floating_ip_associate_fixed_ip(context, flip,
fixed_ip)
flip_driver_type = CONF.QUARK.default_floating_ip_driver flip_driver_type = CONF.QUARK.default_floating_ip_driver
flip_driver = registry.DRIVER_REGISTRY.get_driver(flip_driver_type) flip_driver = registry.DRIVER_REGISTRY.get_driver(flip_driver_type)
flip_driver.register_floating_ip(floating_ip, port, fixed_ip) if port:
if current_port:
flip_driver.update_floating_ip(flip, port, fixed_ip)
else:
flip_driver.register_floating_ip(flip, port, fixed_ip)
else:
flip_driver.remove_floating_ip(flip)
return v._make_floating_ip_dict(floating_ip) # Note(alanquillin) The ports parameters on the model is not
# properly getting cleaned up when removed. Manually cleaning them up.
# Need to fix the db api to correctly update the model.
if not port:
flip.ports = []
return v._make_floating_ip_dict(flip)
def update_floatingip(context, id, body):
LOG.info("update_floatingip %s for tenant %s and body %s" %
(id, context.tenant_id, body))
# floating_ip_dict = body.get("ip_address")
#
# if "port_id" not in floating_ip_dict:
# raise exceptions.BadRequest(resource="floating_ip",
# msg="port_id is required.")
# port_id = floating_ip_dict.get("port_id")
raise NotImplementedError()
def delete_floatingip(context, id): def delete_floatingip(context, id):
"""deallocate a floating IP.
:param context: neutron api request context.
:param id: id of the floating ip
"""
LOG.info("delete_floatingip %s for tenant %s" % (id, context.tenant_id)) LOG.info("delete_floatingip %s for tenant %s" % (id, context.tenant_id))
filters = {"address_type": ip_types.FLOATING, "_deallocated": False} filters = {"address_type": ip_types.FLOATING, "_deallocated": False}
floating_ip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, flip = db_api.floating_ip_find(context, id=id, scope=db_api.ONE, **filters)
**filters) if not flip:
if not floating_ip: raise qex.FloatingIpNotFound(id=id)
raise quark_exceptions.FloatingIpNotFound(id=id)
driver_type = CONF.QUARK.default_floating_ip_driver current_ports = flip.ports
driver = registry.DRIVER_REGISTRY.get_driver(driver_type) current_port = None
driver.remove_floating_ip(floating_ip) if current_ports and len(current_ports) > 0:
current_port = current_ports[0]
strategy_name = floating_ip.network.get("ipam_strategy") with context.session.begin():
ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name) strategy_name = flip.network.get("ipam_strategy")
ipam_driver.deallocate_ip_address(context, floating_ip) ipam_driver = ipam.IPAM_REGISTRY.get_strategy(strategy_name)
ipam_driver.deallocate_ip_address(context, flip)
if current_port:
flip = db_api.port_disassociate_ip(context, [current_port],
flip)
if flip.fixed_ip:
flip = db_api.floating_ip_disassociate_fixed_ip(context, flip)
db_api.ip_address_deallocate(context, flip)
if flip.fixed_ip:
driver_type = CONF.QUARK.default_floating_ip_driver
driver = registry.DRIVER_REGISTRY.get_driver(driver_type)
driver.remove_floating_ip(flip)
def get_floatingip(context, id, fields=None): def get_floatingip(context, id, fields=None):
@@ -179,7 +280,7 @@ def get_floatingip(context, id, fields=None):
**filters) **filters)
if not floating_ip: if not floating_ip:
raise quark_exceptions.FloatingIpNotFound(id=id) raise qex.FloatingIpNotFound(id=id)
return v._make_floating_ip_dict(floating_ip) return v._make_floating_ip_dict(floating_ip)

View File

@@ -276,13 +276,15 @@ def _make_ip_policy_dict(ipp):
"exclude": [ippc["cidr"] for ippc in ipp["exclude"]]} "exclude": [ippc["cidr"] for ippc in ipp["exclude"]]}
def _make_floating_ip_dict(flip): def _make_floating_ip_dict(flip, port_id=None):
ports = flip.ports if not port_id:
port_id = None ports = flip.ports
if ports and len(ports) > 0: port_id = None
port_id = None if not ports[0] else ports[0].id if ports and len(ports) > 0:
port_id = None if not ports[0] else ports[0].id
fixed_ip = flip.fixed_ip fixed_ip = flip.fixed_ip
return {"id": flip.get("id"), return {"id": flip.get("id"),
"floating_network_id": flip.get("network_id"), "floating_network_id": flip.get("network_id"),
"router_id": CONF.QUARK.floating_ip_router_id, "router_id": CONF.QUARK.floating_ip_router_id,

View File

@@ -18,10 +18,10 @@ import contextlib
import datetime import datetime
import mock import mock
import netaddr import netaddr
from neutron.common import exceptions from neutron.common import exceptions as ex
from quark.db import models from quark.db import models
from quark import exceptions as quark_exceptions from quark import exceptions as q_ex
from quark.plugin_modules import floating_ips from quark.plugin_modules import floating_ips
from quark.tests import test_quark_plugin from quark.tests import test_quark_plugin
@@ -36,10 +36,14 @@ class TestRemoveFloatingIPs(test_quark_plugin.TestQuarkPlugin):
with contextlib.nested( with contextlib.nested(
mock.patch("quark.db.api.floating_ip_find"), mock.patch("quark.db.api.floating_ip_find"),
mock.patch("quark.db.api.floating_ip_disassociate_fixed_ip"),
mock.patch("quark.db.api.port_disassociate_ip"),
mock.patch("quark.db.api.ip_address_deallocate"),
mock.patch("quark.ipam.QuarkIpam.deallocate_ip_address"), mock.patch("quark.ipam.QuarkIpam.deallocate_ip_address"),
mock.patch("quark.drivers.unicorn_driver.UnicornDriver" mock.patch("quark.drivers.unicorn_driver.UnicornDriver"
".remove_floating_ip") ".remove_floating_ip")
) as (flip_find, mock_dealloc, mock_remove_flip): ) as (flip_find, db_fixed_ip_disassoc, db_port_disassoc, db_dealloc,
mock_dealloc, mock_remove_flip):
flip_find.return_value = flip_model flip_find.return_value = flip_model
yield yield
@@ -52,7 +56,7 @@ class TestRemoveFloatingIPs(test_quark_plugin.TestQuarkPlugin):
def test_delete_floating_by_when_ip_address_does_not_exists_fails(self): def test_delete_floating_by_when_ip_address_does_not_exists_fails(self):
with self._stubs(): with self._stubs():
with self.assertRaises(quark_exceptions.FloatingIpNotFound): with self.assertRaises(q_ex.FloatingIpNotFound):
self.plugin.delete_floatingip(self.context, 1) self.plugin.delete_floatingip(self.context, 1)
@@ -213,6 +217,10 @@ class TestCreateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
def _alloc_ip(context, new_addr, net_id, port_m, *args, **kwargs): def _alloc_ip(context, new_addr, net_id, port_m, *args, **kwargs):
new_addr.append(flip_model) new_addr.append(flip_model)
def _port_assoc(context, ports, addr, enable_port=None):
addr.ports = ports
return addr
def _flip_fixed_ip_assoc(context, addr, fixed_ip): def _flip_fixed_ip_assoc(context, addr, fixed_ip):
addr.fixed_ip = fixed_ip addr.fixed_ip = fixed_ip
return addr return addr
@@ -224,13 +232,16 @@ class TestCreateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
mock.patch("quark.ipam.QuarkIpam.allocate_ip_address"), mock.patch("quark.ipam.QuarkIpam.allocate_ip_address"),
mock.patch("quark.drivers.unicorn_driver.UnicornDriver" mock.patch("quark.drivers.unicorn_driver.UnicornDriver"
".register_floating_ip"), ".register_floating_ip"),
mock.patch("quark.db.api.port_associate_ip"),
mock.patch("quark.db.api.floating_ip_associate_fixed_ip") mock.patch("quark.db.api.floating_ip_associate_fixed_ip")
) as (flip_find, net_find, port_find, alloc_ip, mock_reg_flip, assoc): ) as (flip_find, net_find, port_find, alloc_ip, mock_reg_flip,
port_assoc, fixed_ip_assoc):
flip_find.return_value = flip_model flip_find.return_value = flip_model
net_find.return_value = net_model net_find.return_value = net_model
port_find.return_value = port_model port_find.return_value = port_model
alloc_ip.side_effect = _alloc_ip alloc_ip.side_effect = _alloc_ip
assoc.side_effect = _flip_fixed_ip_assoc port_assoc.side_effect = _port_assoc
fixed_ip_assoc.side_effect = _flip_fixed_ip_assoc
yield yield
def test_create_with_a_port(self): def test_create_with_a_port(self):
@@ -329,14 +340,14 @@ class TestCreateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
def test_create_without_network_id_fails(self): def test_create_without_network_id_fails(self):
with self._stubs(): with self._stubs():
with self.assertRaises(exceptions.BadRequest): with self.assertRaises(ex.BadRequest):
request = dict(port_id=2, floating_ip_address="10.0.0.1") request = dict(port_id=2, floating_ip_address="10.0.0.1")
self.plugin.create_floatingip(self.context, self.plugin.create_floatingip(self.context,
dict(floatingip=request)) dict(floatingip=request))
def test_create_with_invalid_network_fails(self): def test_create_with_invalid_network_fails(self):
with self._stubs(): with self._stubs():
with self.assertRaises(exceptions.NetworkNotFound): with self.assertRaises(ex.NetworkNotFound):
request = dict(floating_network_id=123, request = dict(floating_network_id=123,
port_id=2, floating_ip_address="10.0.0.1") port_id=2, floating_ip_address="10.0.0.1")
self.plugin.create_floatingip(self.context, self.plugin.create_floatingip(self.context,
@@ -347,7 +358,7 @@ class TestCreateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
ipam_strategy="ANY") ipam_strategy="ANY")
with self._stubs(network=network): with self._stubs(network=network):
with self.assertRaises(exceptions.PortNotFound): with self.assertRaises(ex.PortNotFound):
request = dict(floating_network_id=network["id"], request = dict(floating_network_id=network["id"],
port_id=2, floating_ip_address="10.0.0.1") port_id=2, floating_ip_address="10.0.0.1")
self.plugin.create_floatingip(self.context, self.plugin.create_floatingip(self.context,
@@ -367,7 +378,7 @@ class TestCreateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
with self._stubs(port=port, ips=fixed_ips, network=network): with self._stubs(port=port, ips=fixed_ips, network=network):
with self.assertRaises( with self.assertRaises(
quark_exceptions.FixedIpDoesNotExistsForPort): q_ex.FixedIpDoesNotExistsForPort):
request = dict(floating_network_id=network["id"], request = dict(floating_network_id=network["id"],
port_id=port["id"], port_id=port["id"],
fixed_ip_address="192.168.0.2") fixed_ip_address="192.168.0.2")
@@ -400,7 +411,7 @@ class TestCreateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
with self._stubs(port=port, ips=ips, network=network): with self._stubs(port=port, ips=ips, network=network):
with self.assertRaises( with self.assertRaises(
quark_exceptions.PortAlreadyContainsFloatingIp): q_ex.PortAlreadyContainsFloatingIp):
request = dict(floating_network_id=network["id"], request = dict(floating_network_id=network["id"],
port_id=port["id"], port_id=port["id"],
fixed_ip_address="192.168.0.1") fixed_ip_address="192.168.0.1")
@@ -415,7 +426,7 @@ class TestCreateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
with self._stubs(port=port, network=network): with self._stubs(port=port, network=network):
with self.assertRaises( with self.assertRaises(
quark_exceptions.NoAvailableFixedIPsForPort): q_ex.NoAvailableFixedIPsForPort):
request = dict(floating_network_id=network["id"], request = dict(floating_network_id=network["id"],
port_id=port["id"]) port_id=port["id"])
self.plugin.create_floatingip(self.context, self.plugin.create_floatingip(self.context,
@@ -444,8 +455,186 @@ class TestCreateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
with self._stubs(port=port, ips=ips, network=network): with self._stubs(port=port, ips=ips, network=network):
with self.assertRaises( with self.assertRaises(
quark_exceptions.NoAvailableFixedIPsForPort): q_ex.NoAvailableFixedIPsForPort):
request = dict(floating_network_id=network["id"], request = dict(floating_network_id=network["id"],
port_id=port["id"]) port_id=port["id"])
self.plugin.create_floatingip(self.context, self.plugin.create_floatingip(self.context,
dict(floatingip=request)) dict(floatingip=request))
class TestUpdateFloatingIPs(test_quark_plugin.TestQuarkPlugin):
@contextlib.contextmanager
def _stubs(self, flip=None, curr_port=None, new_port=None):
curr_port_model = None
if curr_port:
curr_port_model = models.Port()
curr_port_model.update(curr_port)
new_port_model = None
if new_port:
new_port_model = models.Port()
new_port_model.update(new_port)
fixed_ips = new_port.get("fixed_ips")
if fixed_ips:
new_port_model.ip_addresses = []
for ip in fixed_ips:
addr = netaddr.IPAddress(ip)
fixed_ip_model = models.IPAddress()
fixed_ip_model.update(dict(address_readable=ip,
address=int(addr), version=4,
address_type="fixed"))
new_port_model.ip_addresses.append(fixed_ip_model)
flip_model = None
if flip:
flip_model = models.IPAddress()
flip_model.update(flip)
if curr_port_model:
flip_model.ports = [curr_port_model]
fixed_ip = flip.get("fixed_ip_address")
if fixed_ip:
addr = netaddr.IPAddress(fixed_ip)
fixed_ip_model = models.IPAddress()
fixed_ip_model.update(dict(address_readable=fixed_ip,
address=int(addr), version=4,
address_type="fixed"))
flip_model.fixed_ip = fixed_ip_model
def _find_port(context, id, **kwargs):
return (curr_port_model if (curr_port_model and
id == curr_port_model.id)
else new_port_model)
def _flip_assoc(context, addr, fixed_ip):
addr.fixed_ip = fixed_ip
return addr
def _flip_disassoc(context, addr):
addr.fixed_ip = None
return addr
def _port_assoc(context, ports, addr, enable_ports=None):
addr.ports = ports
return addr
def _port_dessoc(context, ports, addr):
addr.associations = []
addr.ports = []
return addr
with contextlib.nested(
mock.patch("quark.db.api.floating_ip_find"),
mock.patch("quark.db.api.port_find"),
mock.patch("quark.drivers.unicorn_driver.UnicornDriver"
".register_floating_ip"),
mock.patch("quark.drivers.unicorn_driver.UnicornDriver"
".update_floating_ip"),
mock.patch("quark.drivers.unicorn_driver.UnicornDriver"
".remove_floating_ip"),
mock.patch("quark.db.api.port_associate_ip"),
mock.patch("quark.db.api.port_disassociate_ip"),
mock.patch("quark.db.api.floating_ip_associate_fixed_ip"),
mock.patch("quark.db.api.floating_ip_disassociate_fixed_ip")
) as (flip_find, port_find, reg_flip, update_flip, rem_flip,
port_assoc, port_dessoc, flip_assoc, flip_dessoc):
flip_find.return_value = flip_model
port_find.side_effect = _find_port
port_assoc.side_effect = _port_assoc
port_dessoc.side_effect = _port_dessoc
flip_assoc.side_effect = _flip_assoc
flip_dessoc.side_effect = _flip_disassoc
yield
def test_update_with_new_port_and_no_previous_port(self):
new_port = dict(id="2", fixed_ips=["192.168.0.1"])
addr = netaddr.IPAddress("10.0.0.1")
flip = dict(id="3", fixed_ip_address="172.16.1.1", address=int(addr),
address_readable=str(addr))
with self._stubs(flip=flip, new_port=new_port):
content = dict(port_id=new_port["id"])
ret = self.plugin.update_floatingip(self.context, flip["id"],
dict(floatingip=content))
self.assertEqual(ret["fixed_ip_address"], "192.168.0.1")
self.assertEqual(ret["port_id"], new_port["id"])
def test_update_with_new_port(self):
curr_port = dict(id="1")
new_port = dict(id="2", fixed_ips=["192.168.0.1"])
addr = netaddr.IPAddress("10.0.0.1")
flip = dict(id="3", fixed_ip_address="172.16.1.1", address=int(addr),
address_readable=str(addr))
with self._stubs(flip=flip, curr_port=curr_port, new_port=new_port):
content = dict(port_id=new_port["id"])
ret = self.plugin.update_floatingip(self.context, flip["id"],
dict(floatingip=content))
self.assertEqual(ret["fixed_ip_address"], "192.168.0.1")
self.assertEqual(ret["port_id"], new_port["id"])
def test_update_with_no_port(self):
curr_port = dict(id="1")
addr = netaddr.IPAddress("10.0.0.1")
flip = dict(id="3", fixed_ip_address="172.16.1.1", address=int(addr),
address_readable=str(addr))
with self._stubs(flip=flip, curr_port=curr_port):
content = dict(port_id=None)
ret = self.plugin.update_floatingip(self.context, flip["id"],
dict(floatingip=content))
self.assertEqual(ret.get("fixed_ip_address"), None)
self.assertEqual(ret.get("port_id"), None)
def test_update_with_non_existent_port_should_fail(self):
addr = netaddr.IPAddress("10.0.0.1")
flip = dict(id="3", fixed_ip_address="172.16.1.1", address=int(addr),
address_readable=str(addr))
with self._stubs(flip=flip):
with self.assertRaises(ex.PortNotFound):
content = dict(port_id="123")
self.plugin.update_floatingip(self.context, flip["id"],
dict(floatingip=content))
def test_update_with_port_with_no_fixed_ip_avail_should_fail(self):
new_port = dict(id="123")
addr = netaddr.IPAddress("10.0.0.1")
flip = dict(id="3", fixed_ip_address="172.16.1.1", address=int(addr),
address_readable=str(addr))
with self._stubs(flip=flip, new_port=new_port):
with self.assertRaises(q_ex.NoAvailableFixedIPsForPort):
content = dict(port_id="123")
self.plugin.update_floatingip(self.context, flip["id"],
dict(floatingip=content))
def test_update_with_same_port_should_fail(self):
new_port = dict(id="123")
curr_port = dict(id="123")
addr = netaddr.IPAddress("10.0.0.1")
flip = dict(id="3", fixed_ip_address="172.16.1.1", address=int(addr),
address_readable=str(addr))
with self._stubs(flip=flip, new_port=new_port, curr_port=curr_port):
with self.assertRaises(q_ex.PortAlreadyAssociatedToFloatingIP):
content = dict(port_id="123")
self.plugin.update_floatingip(self.context, flip["id"],
dict(floatingip=content))
def test_update_with_no_port_and_no_previous_port_should_fail(self):
addr = netaddr.IPAddress("10.0.0.1")
flip = dict(id="3", fixed_ip_address="172.16.1.1", address=int(addr),
address_readable=str(addr))
with self._stubs(flip=flip):
with self.assertRaises(q_ex.FloatingIPUpdateNoPortIdSupplied):
content = dict(port_id=None)
self.plugin.update_floatingip(self.context, flip["id"],
dict(floatingip=content))
def test_update_with_missing_port_id_param_should_fail(self):
with self._stubs():
with self.assertRaises(ex.BadRequest):
content = {}
self.plugin.update_floatingip(self.context, "123",
dict(floatingip=content))