Merge "NSX|P: Support bulk subnet create"
This commit is contained in:
commit
f1f4f1abe7
@ -1529,6 +1529,101 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
context, created_subnet['id'])
|
context, created_subnet['id'])
|
||||||
return created_subnet
|
return created_subnet
|
||||||
|
|
||||||
|
def _create_bulk_with_callback(self, resource, context, request_items,
|
||||||
|
post_create_func=None, rollback_func=None):
|
||||||
|
# This is a copy of the _create_bulk() in db_base_plugin_v2.py,
|
||||||
|
# but extended with user-provided callback functions.
|
||||||
|
objects = []
|
||||||
|
collection = "%ss" % resource
|
||||||
|
items = request_items[collection]
|
||||||
|
try:
|
||||||
|
with db_api.CONTEXT_WRITER.using(context):
|
||||||
|
for item in items:
|
||||||
|
obj_creator = getattr(self, 'create_%s' % resource)
|
||||||
|
obj = obj_creator(context, item)
|
||||||
|
objects.append(obj)
|
||||||
|
if post_create_func:
|
||||||
|
# The user-provided post_create function is called
|
||||||
|
# after a new object is created.
|
||||||
|
post_create_func(obj)
|
||||||
|
except Exception:
|
||||||
|
if rollback_func:
|
||||||
|
# The user-provided rollback function is called when an
|
||||||
|
# exception occurred.
|
||||||
|
for obj in objects:
|
||||||
|
rollback_func(obj)
|
||||||
|
|
||||||
|
# Note that the session.rollback() function is called here.
|
||||||
|
# session.rollback() will invoke transaction.rollback() on
|
||||||
|
# the transaction this session maintains. The latter will
|
||||||
|
# deactive the transaction and clear the session's cache.
|
||||||
|
#
|
||||||
|
# But depending on where the exception occurred,
|
||||||
|
# transaction.rollback() may have already been called
|
||||||
|
# internally before reaching here.
|
||||||
|
#
|
||||||
|
# For example, if the exception happened under a
|
||||||
|
# "with session.begin(subtransactions=True):" statement
|
||||||
|
# anywhere in the middle of processing obj_creator(),
|
||||||
|
# transaction.__exit__() will invoke transaction.rollback().
|
||||||
|
# Thus when the exception reaches here, the session's cache
|
||||||
|
# is already empty.
|
||||||
|
context.session.rollback()
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
LOG.error("An exception occurred while creating "
|
||||||
|
"the %(resource)s:%(item)s",
|
||||||
|
{'resource': resource, 'item': item})
|
||||||
|
return objects
|
||||||
|
|
||||||
|
def _post_create_subnet(self, context, subnet):
|
||||||
|
LOG.debug("Collect native DHCP entries for network %s",
|
||||||
|
subnet['network_id'])
|
||||||
|
dhcp_service = nsx_db.get_nsx_service_binding(
|
||||||
|
context.session, subnet['network_id'], nsxlib_consts.SERVICE_DHCP)
|
||||||
|
if dhcp_service:
|
||||||
|
_net_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
||||||
|
context.session, dhcp_service['port_id'])
|
||||||
|
return {'nsx_port_id': nsx_port_id,
|
||||||
|
'nsx_service_id': dhcp_service['nsx_service_id']}
|
||||||
|
|
||||||
|
def _rollback_subnet(self, subnet, dhcp_info):
|
||||||
|
LOG.debug("Rollback native DHCP entries for network %s",
|
||||||
|
subnet['network_id'])
|
||||||
|
if dhcp_info and self.nsxlib:
|
||||||
|
try:
|
||||||
|
self.nsxlib.logical_port.delete(dhcp_info['nsx_port_id'])
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error("Failed to delete logical port %(id)s "
|
||||||
|
"during rollback. Exception: %(e)s",
|
||||||
|
{'id': dhcp_info['nsx_port_id'], 'e': e})
|
||||||
|
try:
|
||||||
|
self.nsxlib.dhcp_server.delete(dhcp_info['nsx_service_id'])
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error("Failed to delete logical DHCP server %(id)s "
|
||||||
|
"during rollback. Exception: %(e)s",
|
||||||
|
{'id': dhcp_info['nsx_service_id'], 'e': e})
|
||||||
|
|
||||||
|
def create_subnet_bulk(self, context, subnets):
|
||||||
|
# Maintain a local cache here because when the rollback function
|
||||||
|
# is called, the cache in the session may have already been cleared.
|
||||||
|
_subnet_dhcp_info = {}
|
||||||
|
|
||||||
|
def _post_create(subnet):
|
||||||
|
if subnet['enable_dhcp']:
|
||||||
|
_subnet_dhcp_info[subnet['id']] = self._post_create_subnet(
|
||||||
|
context, subnet)
|
||||||
|
|
||||||
|
def _rollback(subnet):
|
||||||
|
if subnet['enable_dhcp'] and subnet['id'] in _subnet_dhcp_info:
|
||||||
|
self._rollback_subnet(subnet, _subnet_dhcp_info[subnet['id']])
|
||||||
|
del _subnet_dhcp_info[subnet['id']]
|
||||||
|
|
||||||
|
if self._has_native_dhcp_metadata():
|
||||||
|
return self._create_bulk_with_callback('subnet', context, subnets,
|
||||||
|
_post_create, _rollback)
|
||||||
|
else:
|
||||||
|
return self._create_bulk('subnet', context, subnets)
|
||||||
|
|
||||||
def _get_neutron_net_ids_by_nsx_id(self, context, nsx_id):
|
def _get_neutron_net_ids_by_nsx_id(self, context, nsx_id):
|
||||||
"""Should be implemented by each plugin"""
|
"""Should be implemented by each plugin"""
|
||||||
pass
|
pass
|
||||||
|
@ -1280,101 +1280,6 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
|
|||||||
LOG.warning("Failed to update network %(id)s dhcp server on "
|
LOG.warning("Failed to update network %(id)s dhcp server on "
|
||||||
"the NSX: %(e)s", {'id': network['id'], 'e': e})
|
"the NSX: %(e)s", {'id': network['id'], 'e': e})
|
||||||
|
|
||||||
def _create_bulk_with_callback(self, resource, context, request_items,
|
|
||||||
post_create_func=None, rollback_func=None):
|
|
||||||
# This is a copy of the _create_bulk() in db_base_plugin_v2.py,
|
|
||||||
# but extended with user-provided callback functions.
|
|
||||||
objects = []
|
|
||||||
collection = "%ss" % resource
|
|
||||||
items = request_items[collection]
|
|
||||||
try:
|
|
||||||
with db_api.CONTEXT_WRITER.using(context):
|
|
||||||
for item in items:
|
|
||||||
obj_creator = getattr(self, 'create_%s' % resource)
|
|
||||||
obj = obj_creator(context, item)
|
|
||||||
objects.append(obj)
|
|
||||||
if post_create_func:
|
|
||||||
# The user-provided post_create function is called
|
|
||||||
# after a new object is created.
|
|
||||||
post_create_func(obj)
|
|
||||||
except Exception:
|
|
||||||
if rollback_func:
|
|
||||||
# The user-provided rollback function is called when an
|
|
||||||
# exception occurred.
|
|
||||||
for obj in objects:
|
|
||||||
rollback_func(obj)
|
|
||||||
|
|
||||||
# Note that the session.rollback() function is called here.
|
|
||||||
# session.rollback() will invoke transaction.rollback() on
|
|
||||||
# the transaction this session maintains. The latter will
|
|
||||||
# deactive the transaction and clear the session's cache.
|
|
||||||
#
|
|
||||||
# But depending on where the exception occurred,
|
|
||||||
# transaction.rollback() may have already been called
|
|
||||||
# internally before reaching here.
|
|
||||||
#
|
|
||||||
# For example, if the exception happened under a
|
|
||||||
# "with session.begin(subtransactions=True):" statement
|
|
||||||
# anywhere in the middle of processing obj_creator(),
|
|
||||||
# transaction.__exit__() will invoke transaction.rollback().
|
|
||||||
# Thus when the exception reaches here, the session's cache
|
|
||||||
# is already empty.
|
|
||||||
context.session.rollback()
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
LOG.error("An exception occurred while creating "
|
|
||||||
"the %(resource)s:%(item)s",
|
|
||||||
{'resource': resource, 'item': item})
|
|
||||||
return objects
|
|
||||||
|
|
||||||
def _post_create_subnet(self, context, subnet):
|
|
||||||
LOG.debug("Collect native DHCP entries for network %s",
|
|
||||||
subnet['network_id'])
|
|
||||||
dhcp_service = nsx_db.get_nsx_service_binding(
|
|
||||||
context.session, subnet['network_id'], nsxlib_consts.SERVICE_DHCP)
|
|
||||||
if dhcp_service:
|
|
||||||
_net_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
|
||||||
context.session, dhcp_service['port_id'])
|
|
||||||
return {'nsx_port_id': nsx_port_id,
|
|
||||||
'nsx_service_id': dhcp_service['nsx_service_id']}
|
|
||||||
|
|
||||||
def _rollback_subnet(self, subnet, dhcp_info):
|
|
||||||
LOG.debug("Rollback native DHCP entries for network %s",
|
|
||||||
subnet['network_id'])
|
|
||||||
if dhcp_info:
|
|
||||||
try:
|
|
||||||
self.nsxlib.logical_port.delete(dhcp_info['nsx_port_id'])
|
|
||||||
except Exception as e:
|
|
||||||
LOG.error("Failed to delete logical port %(id)s "
|
|
||||||
"during rollback. Exception: %(e)s",
|
|
||||||
{'id': dhcp_info['nsx_port_id'], 'e': e})
|
|
||||||
try:
|
|
||||||
self.nsxlib.dhcp_server.delete(dhcp_info['nsx_service_id'])
|
|
||||||
except Exception as e:
|
|
||||||
LOG.error("Failed to delete logical DHCP server %(id)s "
|
|
||||||
"during rollback. Exception: %(e)s",
|
|
||||||
{'id': dhcp_info['nsx_service_id'], 'e': e})
|
|
||||||
|
|
||||||
def create_subnet_bulk(self, context, subnets):
|
|
||||||
# Maintain a local cache here because when the rollback function
|
|
||||||
# is called, the cache in the session may have already been cleared.
|
|
||||||
_subnet_dhcp_info = {}
|
|
||||||
|
|
||||||
def _post_create(subnet):
|
|
||||||
if subnet['enable_dhcp']:
|
|
||||||
_subnet_dhcp_info[subnet['id']] = self._post_create_subnet(
|
|
||||||
context, subnet)
|
|
||||||
|
|
||||||
def _rollback(subnet):
|
|
||||||
if subnet['enable_dhcp'] and subnet['id'] in _subnet_dhcp_info:
|
|
||||||
self._rollback_subnet(subnet, _subnet_dhcp_info[subnet['id']])
|
|
||||||
del _subnet_dhcp_info[subnet['id']]
|
|
||||||
|
|
||||||
if cfg.CONF.nsx_v3.native_dhcp_metadata:
|
|
||||||
return self._create_bulk_with_callback('subnet', context, subnets,
|
|
||||||
_post_create, _rollback)
|
|
||||||
else:
|
|
||||||
return self._create_bulk('subnet', context, subnets)
|
|
||||||
|
|
||||||
def create_subnet(self, context, subnet):
|
def create_subnet(self, context, subnet):
|
||||||
self._validate_host_routes_input(subnet)
|
self._validate_host_routes_input(subnet)
|
||||||
# TODO(berlin): public external subnet announcement
|
# TODO(berlin): public external subnet announcement
|
||||||
|
@ -206,8 +206,6 @@ class NsxNativeDhcpTestCase(test_plugin.NsxPPluginTestCaseMixin):
|
|||||||
True)
|
True)
|
||||||
|
|
||||||
def test_dhcp_service_with_create_dhcp_subnet_bulk(self):
|
def test_dhcp_service_with_create_dhcp_subnet_bulk(self):
|
||||||
# TODO(asarfaty) Enable this test once create_subnet_bulk is supported
|
|
||||||
return
|
|
||||||
# Test if DHCP service is enabled on all networks after a
|
# Test if DHCP service is enabled on all networks after a
|
||||||
# create_subnet_bulk operation.
|
# create_subnet_bulk operation.
|
||||||
with self.network() as network1, self.network() as network2:
|
with self.network() as network1, self.network() as network2:
|
||||||
@ -239,8 +237,6 @@ class NsxNativeDhcpTestCase(test_plugin.NsxPPluginTestCaseMixin):
|
|||||||
self.assertTrue(dhcp_service)
|
self.assertTrue(dhcp_service)
|
||||||
|
|
||||||
def test_dhcp_service_with_create_dhcp_subnet_bulk_failure(self):
|
def test_dhcp_service_with_create_dhcp_subnet_bulk_failure(self):
|
||||||
# TODO(asarfaty) Enable this test once create_subnet_bulk is supported
|
|
||||||
return
|
|
||||||
# Test if user-provided rollback function is invoked when
|
# Test if user-provided rollback function is invoked when
|
||||||
# exception occurred during a create_subnet_bulk operation.
|
# exception occurred during a create_subnet_bulk operation.
|
||||||
with self.network() as network1, self.network() as network2:
|
with self.network() as network1, self.network() as network2:
|
||||||
|
@ -836,7 +836,6 @@ class NsxPTestPorts(test_db_base_plugin_v2.TestPortsV2,
|
|||||||
|
|
||||||
class NsxPTestSubnets(test_db_base_plugin_v2.TestSubnetsV2,
|
class NsxPTestSubnets(test_db_base_plugin_v2.TestSubnetsV2,
|
||||||
NsxPPluginTestCaseMixin):
|
NsxPPluginTestCaseMixin):
|
||||||
# TODO(asarfaty) add NsxNativeDhcpTestCase tests here too
|
|
||||||
def setUp(self, plugin=PLUGIN_NAME, ext_mgr=None):
|
def setUp(self, plugin=PLUGIN_NAME, ext_mgr=None):
|
||||||
super(NsxPTestSubnets, self).setUp(plugin=plugin, ext_mgr=ext_mgr)
|
super(NsxPTestSubnets, self).setUp(plugin=plugin, ext_mgr=ext_mgr)
|
||||||
self.disable_dhcp = False
|
self.disable_dhcp = False
|
||||||
|
Loading…
x
Reference in New Issue
Block a user