diff --git a/neutron/plugins/vmware/dhcp_meta/rpc.py b/neutron/plugins/vmware/dhcp_meta/rpc.py index 3b8ef0fec7..b3b960c7de 100644 --- a/neutron/plugins/vmware/dhcp_meta/rpc.py +++ b/neutron/plugins/vmware/dhcp_meta/rpc.py @@ -164,6 +164,8 @@ def _create_metadata_access_network(plugin, context, router_id): meta_net = plugin.create_network(context, {'network': net_data}) greenthread.sleep(0) # yield + plugin.schedule_network(context, meta_net) + greenthread.sleep(0) # yield # From this point on there will be resources to garbage-collect # in case of failures meta_sub = None @@ -187,6 +189,8 @@ def _create_metadata_access_network(plugin, context, router_id): plugin.add_router_interface(context, router_id, {'subnet_id': meta_sub['id']}) greenthread.sleep(0) # yield + # Tell to start the metadata agent proxy, only if we had success + _notify_rpc_agent(context, {'subnet': meta_sub}, 'subnet.create.end') except (ntn_exc.NeutronException, nsx_exc.NsxPluginException, api_exc.NsxApiException): @@ -194,9 +198,6 @@ def _create_metadata_access_network(plugin, context, router_id): # as it will be removed with the network plugin.delete_network(context, meta_net['id']) - # Tell to start the metadata agent proxy - _notify_rpc_agent(context, {'network': meta_net}, 'network.create.end') - def _destroy_metadata_access_network(plugin, context, router_id, ports): if not ports: diff --git a/neutron/tests/unit/vmware/test_nsx_plugin.py b/neutron/tests/unit/vmware/test_nsx_plugin.py index 4120345902..380c75ef21 100644 --- a/neutron/tests/unit/vmware/test_nsx_plugin.py +++ b/neutron/tests/unit/vmware/test_nsx_plugin.py @@ -767,25 +767,39 @@ class TestL3NatTestCase(L3NatTest, def test_metadatata_network_created_with_router_interface_add(self): self._metadata_setup() - with self.router() as r: - with self.subnet() as s: - self._router_interface_action('add', - r['router']['id'], - s['subnet']['id'], - None) - r_ports = self._list('ports')['ports'] - self.assertEqual(len(r_ports), 2) - ips = [] - for port in r_ports: - ips.extend([netaddr.IPAddress(fixed_ip['ip_address']) - for fixed_ip in port['fixed_ips']]) - meta_cidr = netaddr.IPNetwork('169.254.0.0/16') - self.assertTrue(any([ip in meta_cidr for ip in ips])) - # Needed to avoid 409 - self._router_interface_action('remove', - r['router']['id'], - s['subnet']['id'], - None) + with mock.patch.object(self._plugin_class, 'schedule_network') as f: + with self.router() as r: + with self.subnet() as s: + self._router_interface_action('add', + r['router']['id'], + s['subnet']['id'], + None) + r_ports = self._list('ports')['ports'] + self.assertEqual(len(r_ports), 2) + ips = [] + for port in r_ports: + ips.extend([netaddr.IPAddress(fixed_ip['ip_address']) + for fixed_ip in port['fixed_ips']]) + meta_cidr = netaddr.IPNetwork('169.254.0.0/16') + self.assertTrue(any([ip in meta_cidr for ip in ips])) + # Needed to avoid 409 + self._router_interface_action('remove', + r['router']['id'], + s['subnet']['id'], + None) + # Verify that the metadata network gets scheduled first, so that + # an active dhcp agent can pick it up + expected_meta_net = { + 'status': 'ACTIVE', + 'subnets': [], + 'name': 'meta-%s' % r['router']['id'], + 'admin_state_up': True, + 'tenant_id': '', + 'port_security_enabled': False, + 'shared': False, + 'id': mock.ANY + } + f.assert_called_once_with(mock.ANY, expected_meta_net) self._metadata_teardown() def test_metadata_network_create_rollback_on_create_subnet_failure(self):