summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorMaru Newby <mnewby@internap.com>2012-09-18 18:27:26 +0000
committerMaru Newby <mnewby@internap.com>2012-09-18 19:40:04 +0000
commitef222bfe6f50d5203f83fa9d2e9071969f814c29 (patch)
treee114636aa8f23ff57a4cdfc1c8e065016e9b25c2 /nova
parent1db2f54e0bc2d9ac3b8140ff71b6f87e1f92a1cd (diff)
Add lookup by ip via Quantum for metadata service.
* The Nova network API's get_fixed_ip_by_address() is used by the metadata service in determining which instance to return metadata for. * This change implements support for the function in the Quantum v2 implementation of the network API to ensure that the metadata service can return results when Nova is configured to use Quantum. * Overlapping network spaces are not supported at this time. * Addresses bug 1052196 Change-Id: Iaa5d78c4de92313e93ee9008a2c26052a4f60602
Diffstat (limited to 'nova')
-rw-r--r--nova/exception.py5
-rw-r--r--nova/network/quantumv2/api.py28
-rw-r--r--nova/tests/network/test_quantumv2.py38
3 files changed, 59 insertions, 12 deletions
diff --git a/nova/exception.py b/nova/exception.py
index c9f339e6c..4dfff73bd 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -605,6 +605,11 @@ class FixedIpAlreadyInUse(NovaException):
"%(instance_uuid)s.")
+class FixedIpAssociatedWithMultipleInstances(NovaException):
+ message = _("More than one instance is associated with fixed ip address "
+ "'%(address)s'.")
+
+
class FixedIpInvalid(Invalid):
message = _("Fixed IP address %(address)s is invalid.")
diff --git a/nova/network/quantumv2/api.py b/nova/network/quantumv2/api.py
index 5d657dc21..8a1259d3d 100644
--- a/nova/network/quantumv2/api.py
+++ b/nova/network/quantumv2/api.py
@@ -220,6 +220,18 @@ class API(base.Base):
id_str = id_str and id_str + ', ' + _id or _id
raise exception.NetworkNotFound(network_id=id_str)
+ def _get_instance_uuids_by_ip(self, context, address):
+ """Retrieve instance uuids associated with the given ip address.
+
+ :returns: A list of dicts containing the uuids keyed by 'instance_uuid'
+ e.g. [{'instance_uuid': uuid}, ...]
+ """
+ search_opts = {"fixed_ips": 'ip_address=%s' % address}
+ data = quantumv2.get_client(context).list_ports(**search_opts)
+ ports = data.get('ports', [])
+ return [{'instance_uuid': port['device_id']} for port in ports
+ if port['device_id']]
+
def get_instance_uuids_by_ip_filter(self, context, filters):
"""Return a list of dicts in the form of
[{'instance_uuid': uuid}] that matched the ip filter.
@@ -232,12 +244,7 @@ class API(base.Base):
if ip[-1] == '$':
ip = ip[:-1]
ip = ip.replace('\\.', '.')
- search_opts = {"fixed_ips": {'ip_address': ip}}
- data = quantumv2.get_client(context).list_ports(**search_opts)
- ports = data.get('ports', [])
-
- return [{'instance_uuid': port['device_id']} for port in ports
- if port['device_id']]
+ return self._get_instance_uuids_by_ip(context, ip)
def trigger_security_group_members_refresh(self, context, instance_ref):
@@ -277,7 +284,14 @@ class API(base.Base):
raise NotImplementedError()
def get_fixed_ip_by_address(self, context, address):
- raise NotImplementedError()
+ uuid_maps = self._get_instance_uuids_by_ip(context, address)
+ if len(uuid_maps) == 1:
+ return uuid_maps[0]
+ elif not uuid_maps:
+ raise exception.FixedIpNotFoundForAddress(address=address)
+ else:
+ raise exception.FixedIpAssociatedWithMultipleInstances(
+ address=address)
def get_floating_ip(self, context, id):
raise NotImplementedError()
diff --git a/nova/tests/network/test_quantumv2.py b/nova/tests/network/test_quantumv2.py
index 19ba84edf..e52eedd12 100644
--- a/nova/tests/network/test_quantumv2.py
+++ b/nova/tests/network/test_quantumv2.py
@@ -161,11 +161,12 @@ class TestQuantumv2(test.TestCase):
'tenant_id': 'his_tenantid'}]
self.nets = [self.nets1, self.nets2, self.nets3, self.nets4]
+ self.port_address = '10.0.1.2'
self.port_data1 = [{'network_id': 'my_netid1',
'device_id': 'device_id1',
'device_owner': 'compute:nova',
'id': 'my_portid1',
- 'fixed_ips': [{'ip_address': '10.0.1.2',
+ 'fixed_ips': [{'ip_address': self.port_address,
'subnet_id': 'my_subid1'}],
'mac_address': 'my_mac1', }]
self.dhcp_port_data1 = [{'fixed_ips': [{'ip_address': '10.0.1.9',
@@ -510,17 +511,44 @@ class TestQuantumv2(test.TestCase):
except exception.NetworkNotFound as ex:
self.assertTrue("my_netid2, my_netid3" in str(ex))
- def test_get_instance_uuids_by_ip_filter(self):
- filters = {'ip': '^10\\.0\\.1\\.2$'}
+ def _mock_list_ports(self, port_data=None):
+ if port_data is None:
+ port_data = self.port_data2
+ address = self.port_address
self.moxed_client.list_ports(
- fixed_ips=MyComparator({'ip_address': '10.0.1.2'})).AndReturn(
- {'ports': self.port_data2})
+ fixed_ips=MyComparator('ip_address=%s' % address)).AndReturn(
+ {'ports': port_data})
self.mox.ReplayAll()
+ return address
+
+ def test_get_instance_uuids_by_ip_filter(self):
+ self._mock_list_ports()
+ filters = {'ip': '^10\\.0\\.1\\.2$'}
api = quantumapi.API()
result = api.get_instance_uuids_by_ip_filter(self.context, filters)
self.assertEquals('device_id1', result[0]['instance_uuid'])
self.assertEquals('device_id2', result[1]['instance_uuid'])
+ def test_get_fixed_ip_by_address_fails_for_no_ports(self):
+ address = self._mock_list_ports(port_data=[])
+ api = quantumapi.API()
+ self.assertRaises(exception.FixedIpNotFoundForAddress,
+ api.get_fixed_ip_by_address,
+ self.context, address)
+
+ def test_get_fixed_ip_by_address_succeeds_for_1_port(self):
+ address = self._mock_list_ports(port_data=self.port_data1)
+ api = quantumapi.API()
+ result = api.get_fixed_ip_by_address(self.context, address)
+ self.assertEquals('device_id1', result['instance_uuid'])
+
+ def test_get_fixed_ip_by_address_fails_for_more_than_1_port(self):
+ address = self._mock_list_ports()
+ api = quantumapi.API()
+ self.assertRaises(exception.FixedIpAssociatedWithMultipleInstances,
+ api.get_fixed_ip_by_address,
+ self.context, address)
+
def _get_available_networks(self, prv_nets, pub_nets, req_ids=None):
api = quantumapi.API()
nets = prv_nets + pub_nets