From a0bedb332c96b363f0fd6acfa81b5937a82244eb Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Thu, 20 Nov 2014 15:19:11 -0800 Subject: [PATCH] Make neutronapi get_floating*() methods return objects This makes the neutronapi module return NeutronFloatingIP objects from the relevant methods, instead of bare dicts. Note that the API is returning string floating ip identifiers when neutron is in use, as opposed to the integer ones returned when nova-network is in use. This patch does not address that problem, but uses the new NeutronFloatingIP. Needed for blueprint rm-object-dict-compat-newton Co-Authored-By: Ryan Rossiter Change-Id: Ie60fb8661195eec9c01a57129efe8145504789e1 --- nova/network/neutronv2/api.py | 40 +++++---- .../openstack/compute/test_floating_ips.py | 9 ++ nova/tests/unit/network/test_neutronv2.py | 90 +++++++++++++++++-- 3 files changed, 113 insertions(+), 26 deletions(-) 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):