diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py index f615664466a3..84325d669841 100644 --- a/nova/network/neutronv2/api.py +++ b/nova/network/neutronv2/api.py @@ -1362,7 +1362,7 @@ class API(base_api.NetworkAPI): pool_dict = self._setup_net_dict(client, fip['floating_network_id']) port_dict = self._setup_port_dict(context, client, fip['port_id']) - return self._format_floating_ip_model(fip, pool_dict, port_dict) + return self._make_floating_ip_obj(context, fip, pool_dict, port_dict) def _get_floating_ip_pools(self, client, project_id=None): search_opts = {constants.NET_EXTERNAL: True} @@ -1379,27 +1379,31 @@ class API(base_api.NetworkAPI): # nova.network.api.get_floating_ip_pools return [n['name'] or n['id'] for n in pools] - def _format_floating_ip_model(self, fip, pool_dict, port_dict): + def _make_floating_ip_obj(self, context, fip, pool_dict, port_dict): pool = pool_dict[fip['floating_network_id']] - result = {'id': fip['id'], - 'address': fip['floating_ip_address'], - 'pool': pool['name'] or pool['id'], - 'project_id': fip['tenant_id'], - # In Neutron v2, an exact fixed_ip_id does not exist. - 'fixed_ip_id': fip['port_id'], - } + # NOTE(danms): Don't give these objects a context, since they're + # not lazy-loadable anyway + floating = objects.floating_ip.NeutronFloatingIP( + id=fip['id'], address=fip['floating_ip_address'], + pool=(pool['name'] or pool['id']), project_id=fip['tenant_id'], + fixed_ip_id=fip['port_id']) # In Neutron v2 API fixed_ip_address and instance uuid # (= device_id) are known here, so pass it as a result. - result['fixed_ip'] = {'address': fip['fixed_ip_address']} + if fip['fixed_ip_address']: + floating.fixed_ip = objects.FixedIP( + address=fip['fixed_ip_address']) + else: + floating.fixed_ip = None if fip['port_id']: instance_uuid = port_dict[fip['port_id']]['device_id'] - result['instance'] = {'uuid': instance_uuid} - # TODO(mriedem): remove this workaround once the get_floating_ip* - # API methods are converted to use nova objects. - result['fixed_ip']['instance_uuid'] = instance_uuid + # NOTE(danms): This could be .refresh()d, so give it context + floating.instance = objects.Instance(context=context, + uuid=instance_uuid) + if floating.fixed_ip: + floating.fixed_ip.instance_uuid = instance_uuid else: - result['instance'] = None - return result + floating.instance = None + return floating def get_floating_ip_by_address(self, context, address): """Return a floating IP given an address.""" @@ -1408,7 +1412,7 @@ class API(base_api.NetworkAPI): pool_dict = self._setup_net_dict(client, fip['floating_network_id']) port_dict = self._setup_port_dict(context, client, fip['port_id']) - return self._format_floating_ip_model(fip, pool_dict, port_dict) + return self._make_floating_ip_obj(context, fip, pool_dict, port_dict) def get_floating_ips_by_project(self, context): client = get_client(context) @@ -1418,7 +1422,7 @@ class API(base_api.NetworkAPI): return [] pool_dict = self._setup_pools_dict(client) port_dict = self._setup_ports_dict(client, project_id) - return [self._format_floating_ip_model(fip, pool_dict, port_dict) + return [self._make_floating_ip_obj(context, fip, pool_dict, port_dict) for fip in fips] def get_instance_id_by_floating_address(self, context, address): diff --git a/nova/tests/unit/api/openstack/compute/test_floating_ips.py b/nova/tests/unit/api/openstack/compute/test_floating_ips.py index 8c5faa12e07f..6267e3f5ae2a 100644 --- a/nova/tests/unit/api/openstack/compute/test_floating_ips.py +++ b/nova/tests/unit/api/openstack/compute/test_floating_ips.py @@ -269,6 +269,15 @@ class FloatingIpTestV21(test.TestCase): self.assertIsNone(view['floating_ip']['fixed_ip']) self.assertIsNone(view['floating_ip']['instance_id']) + def test_translate_floating_ip_view_neutronesque(self): + uuid = 'ca469a10-fa76-11e5-86aa-5e5517507c66' + fixed_id = 'ae900cf4-fb73-11e5-86aa-5e5517507c66' + floating_ip = objects.floating_ip.NeutronFloatingIP(id=uuid, + address='1.2.3.4', pool='pool', context='ctxt', + fixed_ip_id=fixed_id) + view = self.floating_ips._translate_floating_ip_view(floating_ip) + self.assertEqual(uuid, view['floating_ip']['id']) + def test_translate_floating_ip_view_dict(self): floating_ip = {'id': 0, 'address': '10.0.0.10', 'pool': 'nova', 'fixed_ip': None} diff --git a/nova/tests/unit/network/test_neutronv2.py b/nova/tests/unit/network/test_neutronv2.py index cf60331c8f6a..1f8b8ddc5e5b 100644 --- a/nova/tests/unit/network/test_neutronv2.py +++ b/nova/tests/unit/network/test_neutronv2.py @@ -22,6 +22,7 @@ from keystoneauth1.fixture import V2Token from keystoneauth1 import loading as ks_loading import mock from mox3 import mox +import netaddr from neutronclient.common import exceptions from neutronclient.v2_0 import client from oslo_config import cfg @@ -2039,17 +2040,24 @@ class TestNeutronv2(TestNeutronv2Base): 'address': fip_data['floating_ip_address'], 'pool': self.fip_pool['name'], 'project_id': fip_data['tenant_id'], - 'fixed_ip_id': fip_data['port_id'], - 'fixed_ip': - {'address': fip_data['fixed_ip_address']}, + 'fixed_ip': None, 'instance': ({'uuid': self.port_data2[idx]['device_id']} if fip_data['port_id'] else None)} - if expected['instance'] is not None: - expected['fixed_ip']['instance_uuid'] = \ - expected['instance']['uuid'] + if fip_data['fixed_ip_address']: + expected['fixed_ip'] = {'address': fip_data['fixed_ip_address']} return expected + def _compare(self, obj, dic): + for key, value in dic.items(): + objvalue = obj[key] + if isinstance(value, dict): + self._compare(objvalue, value) + elif isinstance(objvalue, netaddr.IPAddress): + self.assertEqual(value, str(objvalue)) + else: + self.assertEqual(value, objvalue) + def _test_get_floating_ip(self, fip_data, idx=0, by_address=False): api = neutronapi.API() fip_id = fip_data['id'] @@ -2074,7 +2082,7 @@ class TestNeutronv2(TestNeutronv2Base): fip = api.get_floating_ip_by_address(self.context, address) else: fip = api.get_floating_ip(self.context, fip_id) - self.assertEqual(expected, fip) + self._compare(fip, expected) def test_get_floating_ip_unassociated(self): self._test_get_floating_ip(self.fip_unassociated, idx=0) @@ -2148,7 +2156,9 @@ class TestNeutronv2(TestNeutronv2Base): expected = [self._get_expected_fip_model(self.fip_unassociated), self._get_expected_fip_model(self.fip_associated, idx=1)] fips = api.get_floating_ips_by_project(self.context) - self.assertEqual(expected, fips) + self.assertEqual(len(expected), len(fips)) + for i, expected_value in enumerate(expected): + self._compare(fips[i], expected_value) def _test_get_instance_id_by_floating_address(self, fip_data, associated=False): @@ -3849,6 +3859,70 @@ class TestNeutronv2WithMock(test.TestCase): port_client.update_port.assert_called_once_with( uuids.port_id, port_req_body) + def test_make_floating_ip_obj(self): + self._test_make_floating_ip_obj() + + def test_make_floating_ip_obj_pool_id(self): + self._test_make_floating_ip_obj(set_pool_name=False) + + def test_make_floating_ip_obj_no_fixed_ip_address(self): + self._test_make_floating_ip_obj(set_fixed_ip=False) + + def test_make_floating_ip_obj_no_port_id(self): + self._test_make_floating_ip_obj(set_port=False) + + def _test_make_floating_ip_obj(self, set_port=True, set_fixed_ip=True, + set_pool_name=True): + net_id = '6cd58996-001a-11e6-86aa-5e5517507c66' + float_id = 'ea474936-0016-11e6-86aa-5e5517507c66' + tenant_id = '310b1db6-0017-11e6-86aa-5e5517507c66' + port_id = '40cfc710-0017-11e6-86aa-5e5517507c66' if set_port else None + device_id = '6b892334-0017-11e6-86aa-5e5517507c66' + floating_ip_address = '10.0.0.1' + fixed_ip_address = '192.168.100.100' if set_fixed_ip else None + pool_name = 'my_pool' if set_pool_name else None + pool_id = 'd7f7150e-001b-11e6-86aa-5e5517507c66' + + fip = {'id': float_id, + 'floating_ip_address': floating_ip_address, + 'tenant_id': tenant_id, + 'port_id': port_id, + 'fixed_ip_address': fixed_ip_address, + 'floating_network_id': net_id + } + + pool_dict = {net_id: {'name': pool_name, 'id': pool_id}} + + port_dict = {port_id: {'device_id': device_id}} + + actual_obj = self.api._make_floating_ip_obj(self.context, fip, + pool_dict, port_dict) + + expected_pool = pool_name if set_pool_name else pool_id + + if set_fixed_ip: + if set_port: + expected_fixed = objects.FixedIP(address=fixed_ip_address, + instance_uuid=device_id) + else: + expected_fixed = objects.FixedIP(address=fixed_ip_address) + else: + expected_fixed = None + + if set_port: + expected_instance = objects.Instance(context=context, + uuid=device_id) + else: + expected_instance = None + + expected_floating = objects.floating_ip.NeutronFloatingIP( + id=float_id, address=floating_ip_address, pool=expected_pool, + project_id=tenant_id, fixed_ip_id=port_id, + fixed_ip=expected_fixed, instance=expected_instance) + + self.assertEqual(expected_floating.obj_to_primitive(), + actual_obj.obj_to_primitive()) + class TestNeutronv2ModuleMethods(test.NoDBTestCase):