Merge "NSXv3: Add plugin-specific create_subnet_bulk function"

This commit is contained in:
Jenkins 2016-10-13 12:31:19 +00:00 committed by Gerrit Code Review
commit 3cb3c9c09b
2 changed files with 135 additions and 0 deletions

View File

@ -1038,6 +1038,47 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
LOG.error(msg) LOG.error(msg)
raise n_exc.InvalidInput(error_message=msg) raise n_exc.InvalidInput(error_message=msg)
def _create_bulk_with_rollback(self, resource, context, request_items,
rollback_func=None):
# This is a copy of the _create_bulk() in db_base_plugin_v2.py,
# but extended with a user-provided rollback function.
objects = []
collection = "%ss" % resource
items = request_items[collection]
context.session.begin(subtransactions=True)
try:
for item in items:
obj_creator = getattr(self, 'create_%s' % resource)
objects.append(obj_creator(context, item))
context.session.commit()
except Exception:
if rollback_func:
# The rollback function is called before session is reset.
for obj in objects:
rollback_func(obj)
context.session.rollback()
with excutils.save_and_reraise_exception():
LOG.error(_LE("An exception occurred while creating "
"the %(resource)s:%(item)s"),
{'resource': resource, 'item': item})
return objects
def _rollback_subnet(self, context, subnet):
if subnet['enable_dhcp']:
LOG.debug("Rollback native DHCP entries for network %s",
subnet['network_id'])
self._disable_native_dhcp(context, subnet['network_id'])
def create_subnet_bulk(self, context, subnets):
def _rollback(subnet):
self._rollback_subnet(context, subnet)
if cfg.CONF.nsx_v3.native_dhcp_metadata:
return self._create_bulk_with_rollback('subnet', context, subnets,
_rollback)
else:
return self._create_bulk('subnet', context, subnets)
def create_subnet(self, context, subnet): def create_subnet(self, context, subnet):
self._validate_address_space(subnet['subnet']) self._validate_address_space(subnet['subnet'])

View File

@ -57,6 +57,31 @@ class NsxNativeDhcpTestCase(test_plugin.NsxV3PluginTestCaseMixin):
self._orig_native_dhcp_metadata, 'nsx_v3') self._orig_native_dhcp_metadata, 'nsx_v3')
super(NsxNativeDhcpTestCase, self).tearDown() super(NsxNativeDhcpTestCase, self).tearDown()
def _make_subnet_data(self,
name=None,
network_id=None,
cidr=None,
gateway_ip=None,
tenant_id=None,
allocation_pools=None,
enable_dhcp=True,
dns_nameservers=None,
ip_version=4,
host_routes=None,
shared=False):
return {'subnet': {
'name': name,
'network_id': network_id,
'cidr': cidr,
'gateway_ip': gateway_ip,
'tenant_id': tenant_id,
'allocation_pools': allocation_pools,
'ip_version': ip_version,
'enable_dhcp': enable_dhcp,
'dns_nameservers': dns_nameservers,
'host_routes': host_routes,
'shared': shared}}
def _verify_dhcp_service(self, network_id, tenant_id, enabled): def _verify_dhcp_service(self, network_id, tenant_id, enabled):
# Verify if DHCP service is enabled on a network. # Verify if DHCP service is enabled on a network.
port_res = self._list_ports('json', 200, network_id, port_res = self._list_ports('json', 200, network_id,
@ -157,6 +182,75 @@ class NsxNativeDhcpTestCase(test_plugin.NsxV3PluginTestCaseMixin):
network['network']['tenant_id'], network['network']['tenant_id'],
True) True)
def test_dhcp_service_with_create_dhcp_subnet_bulk(self):
# Test if DHCP service is enabled on all networks after a
# create_subnet_bulk operation.
with self.network() as network1, self.network() as network2:
subnet1 = self._make_subnet_data(
network_id=network1['network']['id'], cidr='10.0.0.0/24',
tenant_id=network1['network']['tenant_id'])
subnet2 = self._make_subnet_data(
network_id=network2['network']['id'], cidr='20.0.0.0/24',
tenant_id=network2['network']['tenant_id'])
subnets = {'subnets': [subnet1, subnet2]}
self.plugin.create_subnet_bulk(
context.get_admin_context(), subnets)
# Check if the bindings to backend DHCP entries are created.
dhcp_service = nsx_db.get_nsx_service_binding(
context.get_admin_context().session,
network1['network']['id'], nsx_constants.SERVICE_DHCP)
self.assertTrue(dhcp_service)
dhcp_service = nsx_db.get_nsx_service_binding(
context.get_admin_context().session,
network2['network']['id'], nsx_constants.SERVICE_DHCP)
self.assertTrue(dhcp_service)
def test_dhcp_service_with_create_dhcp_subnet_bulk_failure(self):
# Test if user-provided rollback function is invoked when
# exception occurred during a create_subnet_bulk operation.
with self.network() as network1, self.network() as network2:
subnet1 = self._make_subnet_data(
network_id=network1['network']['id'], cidr='10.0.0.0/24',
tenant_id=network1['network']['tenant_id'])
subnet2 = self._make_subnet_data(
network_id=network2['network']['id'], cidr='20.0.0.0/24',
tenant_id=network2['network']['tenant_id'])
subnets = {'subnets': [subnet1, subnet2]}
# Inject an exception on the second create_subnet call.
orig_create_subnet = self.plugin.create_subnet
with mock.patch.object(self.plugin,
'create_subnet') as create_subnet:
def side_effect(*args, **kwargs):
return self._fail_second_call(
create_subnet, orig_create_subnet, *args, **kwargs)
create_subnet.side_effect = side_effect
with mock.patch.object(self.plugin,
'_rollback_subnet') as rollback_subnet:
try:
admin_context = context.get_admin_context()
self.plugin.create_subnet_bulk(admin_context, subnets)
except Exception:
pass
# Check if rollback function has been called for
# the subnet in the first network.
rollback_subnet.assert_called_once_with(admin_context,
mock.ANY)
subnet_arg = rollback_subnet.call_args[0][1]
self.assertEqual(network1['network']['id'],
subnet_arg['network_id'])
# Check if the bindings to backend DHCP entries are
# removed.
dhcp_service = nsx_db.get_nsx_service_binding(
context.get_admin_context().session,
network1['network']['id'], nsx_constants.SERVICE_DHCP)
self.assertFalse(dhcp_service)
dhcp_service = nsx_db.get_nsx_service_binding(
context.get_admin_context().session,
network2['network']['id'], nsx_constants.SERVICE_DHCP)
self.assertFalse(dhcp_service)
def test_dhcp_service_with_create_multiple_dhcp_subnets(self): def test_dhcp_service_with_create_multiple_dhcp_subnets(self):
# Test if multiple DHCP-enabled subnets cannot be created in a network. # Test if multiple DHCP-enabled subnets cannot be created in a network.
with self.network() as network: with self.network() as network: