Merge "NSXv3: Add plugin-specific create_subnet_bulk function"
This commit is contained in:
commit
3cb3c9c09b
@ -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'])
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user