summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Young <sleepsonthefloor@gmail.com>2011-08-30 00:03:39 -0700
committerAnthony Young <sleepsonthefloor@gmail.com>2011-08-30 00:03:39 -0700
commita635027ddbeb73dfad8bbf2890f67cb1ed7511bf (patch)
tree4f980a3fb07103885a14a5df5ba9fd22e26693df
parent2a2aa10316abe9135541198bddd4c189976eb2fd (diff)
downloadnova-a635027ddbeb73dfad8bbf2890f67cb1ed7511bf.tar.gz
nova-a635027ddbeb73dfad8bbf2890f67cb1ed7511bf.tar.xz
nova-a635027ddbeb73dfad8bbf2890f67cb1ed7511bf.zip
disassociate floating ips before re-associating, and prevent re-association of already associated floating ips in manager
-rw-r--r--nova/exception.py4
-rw-r--r--nova/network/api.py6
-rw-r--r--nova/network/manager.py7
-rw-r--r--nova/tests/api/openstack/contrib/test_floating_ips.py68
-rw-r--r--nova/tests/test_network.py16
5 files changed, 96 insertions, 5 deletions
diff --git a/nova/exception.py b/nova/exception.py
index 32981f4d5..b54981963 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -533,6 +533,10 @@ class NoMoreFloatingIps(FloatingIpNotFound):
message = _("Zero floating ips available.")
+class FloatingIpAlreadyInUse(NovaException):
+ message = _("Floating ip %(address) already in use by %(fixed_ip).")
+
+
class NoFloatingIpsDefined(NotFound):
message = _("Zero floating ips exist.")
diff --git a/nova/network/api.py b/nova/network/api.py
index d04474df3..78580d360 100644
--- a/nova/network/api.py
+++ b/nova/network/api.py
@@ -111,6 +111,12 @@ class API(base.Base):
'(%(project)s)') %
{'address': floating_ip['address'],
'project': context.project_id})
+
+ # If this address has been previously associated to a
+ # different instance, disassociate the floating_ip
+ if floating_ip['fixed_ip'] and floating_ip['fixed_ip'] is not fixed_ip:
+ self.disassociate_floating_ip(context, floating_ip['address'])
+
# NOTE(vish): if we are multi_host, send to the instances host
if fixed_ip['network']['multi_host']:
host = fixed_ip['instance']['host']
diff --git a/nova/network/manager.py b/nova/network/manager.py
index b4605eea5..e6b30d1a0 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -280,6 +280,13 @@ class FloatingIP(object):
def associate_floating_ip(self, context, floating_address, fixed_address):
"""Associates an floating ip to a fixed ip."""
+ floating_ip = self.db.floating_ip_get_by_address(context,
+ floating_address)
+ if floating_ip['fixed_ip']:
+ raise exception.FloatingIpAlreadyInUse(
+ address=floating_ip['address'],
+ fixed_ip=floating_ip['fixed_ip']['address'])
+
self.db.floating_ip_fixed_ip_associate(context,
floating_address,
fixed_address)
diff --git a/nova/tests/api/openstack/contrib/test_floating_ips.py b/nova/tests/api/openstack/contrib/test_floating_ips.py
index 568faf867..c14c29bf3 100644
--- a/nova/tests/api/openstack/contrib/test_floating_ips.py
+++ b/nova/tests/api/openstack/contrib/test_floating_ips.py
@@ -23,6 +23,7 @@ from nova import db
from nova import test
from nova import network
from nova.tests.api.openstack import fakes
+from nova.tests.api.openstack import test_servers
from nova.api.openstack.contrib.floating_ips import FloatingIPController
@@ -60,10 +61,38 @@ def compute_api_associate(self, context, instance_id, floating_ip):
pass
+def network_api_associate(self, context, floating_ip, fixed_ip):
+ pass
+
+
def network_api_disassociate(self, context, floating_address):
pass
+def network_get_instance_nw_info(self, context, instance):
+ info = {
+ 'label': 'fake',
+ 'gateway': 'fake',
+ 'dhcp_server': 'fake',
+ 'broadcast': 'fake',
+ 'mac': 'fake',
+ 'vif_uuid': 'fake',
+ 'rxtx_cap': 'fake',
+ 'dns': [],
+ 'ips': [{'ip': '10.0.0.1'}],
+ 'should_create_bridge': False,
+ 'should_create_vlan': False}
+
+ return [['ignore', info]]
+
+
+def fake_instance_get(context, instance_id):
+ return {
+ "id": 1,
+ "user_id": 'fakeuser',
+ "project_id": '123'}
+
+
class FloatingIpTest(test.TestCase):
address = "10.10.10.10"
@@ -79,9 +108,6 @@ class FloatingIpTest(test.TestCase):
def setUp(self):
super(FloatingIpTest, self).setUp()
- self.controller = FloatingIPController()
- fakes.stub_out_networking(self.stubs)
- fakes.stub_out_rate_limiting(self.stubs)
self.stubs.Set(network.api.API, "get_floating_ip",
network_api_get_floating_ip)
self.stubs.Set(network.api.API, "get_floating_ip_by_ip",
@@ -92,10 +118,13 @@ class FloatingIpTest(test.TestCase):
network_api_allocate)
self.stubs.Set(network.api.API, "release_floating_ip",
network_api_release)
- self.stubs.Set(compute.api.API, "associate_floating_ip",
- compute_api_associate)
self.stubs.Set(network.api.API, "disassociate_floating_ip",
network_api_disassociate)
+ self.stubs.Set(network.api.API, "get_instance_nw_info",
+ network_get_instance_nw_info)
+ self.stubs.Set(db.api, 'instance_get',
+ fake_instance_get)
+
self.context = context.get_admin_context()
self._create_floating_ip()
@@ -165,6 +194,8 @@ class FloatingIpTest(test.TestCase):
self.assertEqual(res.status_int, 202)
def test_add_floating_ip_to_instance(self):
+ self.stubs.Set(network.api.API, "associate_floating_ip",
+ network_api_associate)
body = dict(addFloatingIp=dict(address='11.0.0.1'))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
req.method = "POST"
@@ -174,6 +205,33 @@ class FloatingIpTest(test.TestCase):
resp = req.get_response(fakes.wsgi_app())
self.assertEqual(resp.status_int, 202)
+ def test_add_associated_floating_ip_to_instance(self):
+ def fake_fixed_ip_get_by_address(ctx, address, session=None):
+ return {'address': address, 'network': {'multi_host': None,
+ 'host': 'fake'}}
+
+ self.disassociated = False
+
+ def fake_network_api_disassociate(local_self, ctx, floating_address):
+ self.disassociated = True
+
+ db.floating_ip_update(self.context, self.address, {'project_id': '123',
+ 'fixed_ip_id': 1})
+ self.stubs.Set(network.api.API, "disassociate_floating_ip",
+ fake_network_api_disassociate)
+ self.stubs.Set(db.api, "fixed_ip_get_by_address",
+ fake_fixed_ip_get_by_address)
+
+ body = dict(addFloatingIp=dict(address=self.address))
+ req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
+ req.method = "POST"
+ req.body = json.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ resp = req.get_response(fakes.wsgi_app())
+ self.assertEqual(resp.status_int, 202)
+ self.assertTrue(self.disassociated)
+
def test_remove_floating_ip_from_instance(self):
body = dict(removeFloatingIp=dict(address='11.0.0.1'))
req = webob.Request.blank('/v1.1/123/servers/test_inst/action')
diff --git a/nova/tests/test_network.py b/nova/tests/test_network.py
index 0b8539442..25ff940f0 100644
--- a/nova/tests/test_network.py
+++ b/nova/tests/test_network.py
@@ -371,6 +371,22 @@ class VlanNetworkTestCase(test.TestCase):
self.mox.ReplayAll()
self.network.validate_networks(self.context, requested_networks)
+ def test_cant_associate_associated_floating_ip(self):
+ ctxt = context.RequestContext('testuser', 'testproject',
+ is_admin=False)
+
+ def fake_floating_ip_get_by_address(context, address):
+ return {'address': '10.10.10.10',
+ 'fixed_ip': {'address': '10.0.0.1'}}
+ self.stubs.Set(self.network.db, 'floating_ip_get_by_address',
+ fake_floating_ip_get_by_address)
+
+ self.assertRaises(exception.FloatingIpAlreadyInUse,
+ self.network.associate_floating_ip,
+ ctxt,
+ mox.IgnoreArg(),
+ mox.IgnoreArg())
+
class CommonNetworkTestCase(test.TestCase):