diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index f1c77c81f7c..54927e73372 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -696,7 +696,14 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon, l3plugin.update_router(context, router_id, info) @db_api.retry_if_session_inactive() - def _create_subnet_postcommit(self, context, result, network, ipam_subnet): + def _create_subnet_postcommit(self, context, result, + network=None, ipam_subnet=None): + if not network: + network = self._get_network(context, + result['network_id']) + if not ipam_subnet: + ipam_subnet = self.ipam.get_subnet(context, result['id']) + if hasattr(network, 'external') and network.external: self._update_router_gw_ports(context, network, diff --git a/neutron/db/ipam_pluggable_backend.py b/neutron/db/ipam_pluggable_backend.py index 2fde5d26701..efa65f82101 100644 --- a/neutron/db/ipam_pluggable_backend.py +++ b/neutron/db/ipam_pluggable_backend.py @@ -159,6 +159,10 @@ class IpamPluggableBackend(ipam_backend_mixin.IpamBackendMixin): ipam_driver = driver.Pool.get_instance(None, context) ipam_driver.remove_subnet(subnet_id) + def get_subnet(self, context, subnet_id): + ipam_driver = driver.Pool.get_instance(None, context) + return ipam_driver.get_subnet(subnet_id) + def allocate_ips_for_port_and_store(self, context, port, port_id): # Make a copy of port dict to prevent changing # incoming dict by adding 'id' to it. diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 866b26379ed..9510f8698ae 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -1092,10 +1092,6 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, result, network) self.mechanism_manager.create_subnet_precommit(mech_context) - # TODO(kevinbenton): move this to '_after_subnet_create' - # db base plugin post commit ops - self._create_subnet_postcommit(context, result, net_db, ipam_sub) - return result, mech_context @utils.transaction_guard @@ -1106,6 +1102,9 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, return self._after_create_subnet(context, result, mech_context) def _after_create_subnet(self, context, result, mech_context): + # db base plugin post commit ops + self._create_subnet_postcommit(context, result) + kwargs = {'context': context, 'subnet': result} registry.notify(resources.SUBNET, events.AFTER_CREATE, self, **kwargs) try: diff --git a/neutron/tests/unit/db/test_db_base_plugin_v2.py b/neutron/tests/unit/db/test_db_base_plugin_v2.py index b57892c6022..1dffdfd5796 100644 --- a/neutron/tests/unit/db/test_db_base_plugin_v2.py +++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py @@ -372,10 +372,16 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase): base_data = {'subnet': {'network_id': net_id, 'ip_version': ip_version, 'tenant_id': self._tenant_id}} + if 'ipv6_mode' in kwargs: + base_data['subnet']['ipv6_ra_mode'] = kwargs['ipv6_mode'] + base_data['subnet']['ipv6_address_mode'] = kwargs['ipv6_mode'] # auto-generate cidrs as they should not overlap + base_cidr = "10.0.%s.0/24" + if ip_version == constants.IP_VERSION_6: + base_cidr = "fd%s::/64" overrides = dict((k, v) for (k, v) in zip(range(number), - [{'cidr': "10.0.%s.0/24" % num} + [{'cidr': base_cidr % num} for num in range(number)])) kwargs.update({'override': overrides}) return self._create_bulk(fmt, number, 'subnet', base_data, **kwargs) @@ -3316,6 +3322,18 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase): 'test') self._validate_behavior_on_bulk_success(res, 'subnets') + def test_create_subnets_bulk_native_ipv6(self): + if self._skip_native_bulk: + self.skipTest("Plugin does not support native bulk subnet create") + with self.network() as net: + res = self._create_subnet_bulk(self.fmt, + 2, + net['network']['id'], + 'test', + ip_version=constants.IP_VERSION_6, + ipv6_mode=constants.IPV6_SLAAC) + self._validate_behavior_on_bulk_success(res, 'subnets') + def test_create_subnets_bulk_emulated(self): real_has_attr = hasattr @@ -4422,6 +4440,25 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase): self._test_create_subnet_ipv6_auto_addr_with_port_on_network( constants.IPV6_SLAAC, insert_port_not_found=True) + def test_bulk_create_subnet_ipv6_auto_addr_with_port_on_network(self): + # Create a network with one IPv4 subnet and one port + with self.network() as network,\ + self.subnet(network=network) as v4_subnet,\ + self.port(subnet=v4_subnet, + device_owner=constants.DEVICE_OWNER_DHCP) as port: + # Add 2 IPv6 auto-address subnets in a bulk request + self._create_subnet_bulk( + self.fmt, 2, network['network']['id'], 'test', + ip_version=constants.IP_VERSION_6, + ipv6_mode=constants.IPV6_SLAAC) + # Confirm that the port has been updated with addresses + # from the new auto-address subnets + req = self.new_show_request('ports', port['port']['id'], + self.fmt) + sport = self.deserialize(self.fmt, req.get_response(self.api)) + fixed_ips = sport['port']['fixed_ips'] + self.assertEqual(3, len(fixed_ips)) + def test_update_subnet_no_gateway(self): with self.subnet() as subnet: data = {'subnet': {'gateway_ip': '10.0.0.1'}}