diff --git a/nova/network/quantumv2/api.py b/nova/network/quantumv2/api.py index d3a94aa4912d..7cbcfd448f49 100644 --- a/nova/network/quantumv2/api.py +++ b/nova/network/quantumv2/api.py @@ -125,6 +125,7 @@ class API(base.Base): return nets + @refresh_cache def allocate_for_instance(self, context, instance, **kwargs): """Allocate network resources for the instance. @@ -281,8 +282,7 @@ class API(base.Base): self.trigger_security_group_members_refresh(context, instance) self.trigger_instance_add_security_group_refresh(context, instance) - nw_info = self.get_instance_nw_info(context, instance, networks=nets, - conductor_api=kwargs.get('conductor_api')) + nw_info = self._get_instance_nw_info(context, instance, networks=nets) # NOTE(danms): Only return info about ports we created in this run. # In the initial allocation case, this will be everything we created, # and in later runs will only be what was created that time. Thus, @@ -325,6 +325,7 @@ class API(base.Base): self.trigger_security_group_members_refresh(context, instance) self.trigger_instance_remove_security_group_refresh(context, instance) + @refresh_cache def allocate_port_for_instance(self, context, instance, port_id, network_id=None, requested_ip=None, conductor_api=None): @@ -332,6 +333,7 @@ class API(base.Base): requested_networks=[(network_id, requested_ip, port_id)], conductor_api=conductor_api) + @refresh_cache def deallocate_port_for_instance(self, context, instance, port_id, conductor_api=None): try: @@ -343,8 +345,7 @@ class API(base.Base): self.trigger_security_group_members_refresh(context, instance) self.trigger_instance_remove_security_group_refresh(context, instance) - return self.get_instance_nw_info(context, instance, - conductor_api=conductor_api) + return self._get_instance_nw_info(context, instance) def list_ports(self, context, **search_opts): return quantumv2.get_client(context).list_ports(**search_opts) @@ -365,6 +366,7 @@ class API(base.Base): nw_info = self._build_network_info_model(context, instance, networks) return network_model.NetworkInfo.hydrate(nw_info) + @refresh_cache def add_fixed_ip_to_instance(self, context, instance, network_id, conductor_api=None): """Add a fixed ip to the instance from specified network.""" @@ -400,6 +402,7 @@ class API(base.Base): raise exception.NetworkNotFoundForInstance( instance_id=instance['uuid']) + @refresh_cache def remove_fixed_ip_from_instance(self, context, instance, address, conductor_api=None): """Remove a fixed ip from the instance.""" @@ -714,6 +717,11 @@ class API(base.Base): raise exception.FloatingIpMultipleFoundForAddress(address=address) return fips[0] + def _get_floating_ips_by_fixed_and_port(self, client, fixed_ip, port): + """Get floatingips from fixed ip and port.""" + data = client.list_floatingips(fixed_ip_address=fixed_ip, port_id=port) + return data['floatingips'] + def release_floating_ip(self, context, address, affect_auto_assigned=False): """Remove a floating ip with the given address from a project.""" @@ -765,8 +773,8 @@ class API(base.Base): def _build_network_info_model(self, context, instance, networks=None): search_opts = {'tenant_id': instance['project_id'], 'device_id': instance['uuid'], } - data = quantumv2.get_client(context, - admin=True).list_ports(**search_opts) + client = quantumv2.get_client(context, admin=True) + data = client.list_ports(**search_opts) ports = data.get('ports', []) if networks is None: networks = self._get_available_networks(context, @@ -792,10 +800,16 @@ class API(base.Base): {'net': port['network_id'], 'port': port['id']}) - network_IPs = [network_model.FixedIP(address=ip_address) - for ip_address in [ip['ip_address'] - for ip in port['fixed_ips']]] - # TODO(gongysh) get floating_ips for each fixed_ip + network_IPs = [] + for fixed_ip in port['fixed_ips']: + fixed = network_model.FixedIP(address=fixed_ip['ip_address']) + floats = self._get_floating_ips_by_fixed_and_port( + client, fixed_ip['ip_address'], port['id']) + for ip in floats: + fip = network_model.IP(address=ip['floating_ip_address'], + type='floating') + fixed.add_floating_ip(fip) + network_IPs.append(fixed) subnets = self._get_subnets_from_port(context, port) for subnet in subnets: diff --git a/nova/tests/api/openstack/compute/contrib/test_quantum_security_groups.py b/nova/tests/api/openstack/compute/contrib/test_quantum_security_groups.py index a413babdf137..a8eadd2a60af 100644 --- a/nova/tests/api/openstack/compute/contrib/test_quantum_security_groups.py +++ b/nova/tests/api/openstack/compute/contrib/test_quantum_security_groups.py @@ -618,6 +618,9 @@ class MockClient(object): return {'subnets': [subnet for subnet in self._fake_subnets.values()]} + def list_floatingips(self, **_params): + return {'floatingips': []} + def delete_security_group(self, security_group): self.show_security_group(security_group) ports = self.list_ports() diff --git a/nova/tests/network/test_quantumv2.py b/nova/tests/network/test_quantumv2.py index 420de821bc2e..be5d5345590e 100644 --- a/nova/tests/network/test_quantumv2.py +++ b/nova/tests/network/test_quantumv2.py @@ -167,6 +167,9 @@ class TestQuantumv2(test.TestCase): 'fixed_ips': [{'ip_address': self.port_address, 'subnet_id': 'my_subid1'}], 'mac_address': 'my_mac1', }] + self.float_data1 = [{'port_id': 'my_portid1', + 'fixed_ip_address': self.port_address, + 'floating_ip_address': '172.0.1.2'}] self.dhcp_port_data1 = [{'fixed_ips': [{'ip_address': '10.0.1.9', 'subnet_id': 'my_subid1'}]}] self.port_data2 = [] @@ -178,6 +181,11 @@ class TestQuantumv2(test.TestCase): 'fixed_ips': [{'ip_address': '10.0.2.2', 'subnet_id': 'my_subid2'}], 'mac_address': 'my_mac2', }) + self.float_data2 = [] + self.float_data2.append(self.float_data1[0]) + self.float_data2.append({'port_id': 'my_portid2', + 'fixed_ip_address': '10.0.2.2', + 'floating_ip_address': '172.0.2.2'}) self.port_data3 = [{'network_id': 'my_netid1', 'device_id': 'device_id3', 'device_owner': 'compute:nova', @@ -242,6 +250,8 @@ class TestQuantumv2(test.TestCase): id_suffix = index + 1 self.assertEquals('10.0.%s.2' % id_suffix, nw_inf.fixed_ips()[index]['address']) + self.assertEquals('172.0.%s.2' % id_suffix, + nw_inf.fixed_ips()[index].floating_ip_addresses()[0]) self.assertEquals('my_netname%s' % id_suffix, nw_inf[index]['network']['label']) self.assertEquals('my_portid%s' % id_suffix, nw_inf[index]['id']) @@ -269,6 +279,14 @@ class TestQuantumv2(test.TestCase): self.moxed_client.list_networks( shared=True).AndReturn({'networks': []}) for i in xrange(1, number + 1): + float_data = number == 1 and self.float_data1 or self.float_data2 + for ip in port_data[i - 1]['fixed_ips']: + float_data = [x for x in float_data + if x['fixed_ip_address'] == ip['ip_address']] + self.moxed_client.list_floatingips( + fixed_ip_address=ip['ip_address'], + port_id=port_data[i - 1]['id']).AndReturn( + {'floatingips': float_data}) subnet_data = i == 1 and self.subnet_data1 or self.subnet_data2 self.moxed_client.list_subnets( id=mox.SameElementsAs(['my_subid%s' % i])).AndReturn( @@ -307,6 +325,12 @@ class TestQuantumv2(test.TestCase): tenant_id=self.instance['project_id'], device_id=self.instance['uuid']).AndReturn( {'ports': self.port_data1}) + port_data = self.port_data1 + for ip in port_data[0]['fixed_ips']: + self.moxed_client.list_floatingips( + fixed_ip_address=ip['ip_address'], + port_id=port_data[0]['id']).AndReturn( + {'floatingips': self.float_data1}) self.moxed_client.list_subnets( id=mox.SameElementsAs(['my_subid1'])).AndReturn( {'subnets': self.subnet_data1}) @@ -379,7 +403,7 @@ class TestQuantumv2(test.TestCase): def _stub_allocate_for_instance(self, net_idx=1, **kwargs): api = quantumapi.API() - self.mox.StubOutWithMock(api, 'get_instance_nw_info') + self.mox.StubOutWithMock(api, '_get_instance_nw_info') self.mox.StubOutWithMock(api, '_populate_quantum_extension_values') # Net idx is 1-based for compatibility with existing unit tests nets = self.nets[net_idx - 1] @@ -461,11 +485,10 @@ class TestQuantumv2(test.TestCase): if kwargs.get('_break') == 'pre_get_instance_nw_info': self.mox.ReplayAll() return api - api.get_instance_nw_info(mox.IgnoreArg(), - self.instance, - networks=nets, - conductor_api=mox.IgnoreArg()).AndReturn( - self._returned_nw_info) + api._get_instance_nw_info(mox.IgnoreArg(), + self.instance, + networks=nets).AndReturn( + self._returned_nw_info) self.mox.ReplayAll() return api @@ -702,6 +725,13 @@ class TestQuantumv2(test.TestCase): {'networks': [self.nets2[1]]}) self.moxed_client.list_networks(shared=True).AndReturn( {'networks': []}) + float_data = number == 1 and self.float_data1 or self.float_data2 + for data in port_data[1:]: + for ip in data['fixed_ips']: + self.moxed_client.list_floatingips( + fixed_ip_address=ip['ip_address'], + port_id=data['id']).AndReturn( + {'floatingips': float_data[1:]}) for port in port_data[1:]: self.moxed_client.list_subnets(id=['my_subid2']).AndReturn({}) @@ -1124,6 +1154,7 @@ class TestQuantumv2(test.TestCase): def test_add_fixed_ip_to_instance(self): api = quantumapi.API() + self._setup_mock_for_refresh_cache(api) network_id = 'my_netid1' search_opts = {'network_id': network_id} self.moxed_client.list_subnets( @@ -1151,6 +1182,7 @@ class TestQuantumv2(test.TestCase): def test_remove_fixed_ip_from_instance(self): api = quantumapi.API() + self._setup_mock_for_refresh_cache(api) address = '10.0.0.3' zone = 'compute:%s' % self.instance['availability_zone'] search_opts = {'device_id': self.instance['uuid'],