Fix transaction issues with network/subnet facade updates
Commit b8d98a5764
moved code
out of transactions to unblock the gate. This issues has been
resolved in the following:
1. Commit 61d0082f9ae9f9a935b5c3517c0b9036c40dbb00
2. Commit 72a2e9df96998f2198b2aba44e4daa2b466b1158
This also fixes dns transaction issues
Switch of context to admin context under db writer is causing
issues with table constraints.
Some usage of admin context for dns is still in place due to
extend_port_dict external API
Co-Authored-By: Anna Khmelnitsky <akhmelnitsky@vmware.com>
Change-Id: I21ec2df09c6b375973ce6f19e06e88318cf19452
This commit is contained in:
parent
232fb88221
commit
bf3bbb5c4c
@ -83,7 +83,7 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
if not request_data.get(dns.DNSNAME):
|
||||
return
|
||||
dns_name, is_dns_domain_default = self._get_request_dns_name(
|
||||
request_data, db_data['network_id'])
|
||||
request_data, db_data['network_id'], plugin_context)
|
||||
if is_dns_domain_default:
|
||||
return
|
||||
network = self._get_network(plugin_context, db_data['network_id'])
|
||||
@ -145,10 +145,9 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
return
|
||||
if dns_name is not None:
|
||||
dns_name, is_dns_domain_default = self._get_request_dns_name(
|
||||
request_data, db_data['network_id'])
|
||||
request_data, db_data['network_id'], plugin_context)
|
||||
if is_dns_domain_default:
|
||||
self._extend_port_dict(plugin_context.session, db_data,
|
||||
db_data, None)
|
||||
self._extend_port_dict(db_data, db_data, None, plugin_context)
|
||||
return
|
||||
network = self._get_network(plugin_context, db_data['network_id'])
|
||||
dns_domain = network[dns.DNSDOMAIN]
|
||||
@ -163,8 +162,7 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
else:
|
||||
dns_data_db = self._update_dns_db(dns_name, dns_domain, db_data,
|
||||
plugin_context, has_fixed_ips)
|
||||
self._extend_port_dict(plugin_context.session, db_data, db_data,
|
||||
dns_data_db)
|
||||
self._extend_port_dict(db_data, db_data, dns_data_db, plugin_context)
|
||||
|
||||
def _process_only_dns_name_update(self, plugin_context, db_data, dns_name):
|
||||
dns_data_db = port_obj.PortDNS.get_object(
|
||||
@ -200,31 +198,32 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
response_data[dns.DNSDOMAIN] = db_data.dns_domain[dns.DNSDOMAIN]
|
||||
return response_data
|
||||
|
||||
def _get_dns_domain(self, network_id):
|
||||
def _get_dns_domain(self, network_id, context=None):
|
||||
if not cfg.CONF.dns_domain:
|
||||
return ''
|
||||
if cfg.CONF.dns_domain.endswith('.'):
|
||||
return cfg.CONF.dns_domain
|
||||
return '%s.' % cfg.CONF.dns_domain
|
||||
|
||||
def _get_request_dns_name(self, port, network_id):
|
||||
dns_domain = self._get_dns_domain(network_id)
|
||||
def _get_request_dns_name(self, port, network_id, context):
|
||||
dns_domain = self._get_dns_domain(network_id, context)
|
||||
if ((dns_domain and dns_domain != DNS_DOMAIN_DEFAULT)):
|
||||
return (port.get(dns.DNSNAME, ''), False)
|
||||
return ('', True)
|
||||
|
||||
def _get_request_dns_name_and_domain_name(self, dns_data_db, network_id):
|
||||
dns_domain = self._get_dns_domain(network_id)
|
||||
def _get_request_dns_name_and_domain_name(self, dns_data_db,
|
||||
network_id, context):
|
||||
dns_domain = self._get_dns_domain(network_id, context)
|
||||
dns_name = ''
|
||||
if ((dns_domain and dns_domain != DNS_DOMAIN_DEFAULT)):
|
||||
if dns_data_db:
|
||||
dns_name = dns_data_db.dns_name
|
||||
return dns_name, dns_domain
|
||||
|
||||
def _get_dns_names_for_port(self, ips, dns_data_db, network_id):
|
||||
def _get_dns_names_for_port(self, ips, dns_data_db, network_id, context):
|
||||
dns_assignment = []
|
||||
dns_name, dns_domain = self._get_request_dns_name_and_domain_name(
|
||||
dns_data_db, network_id)
|
||||
dns_data_db, network_id, context)
|
||||
for ip in ips:
|
||||
if dns_name:
|
||||
hostname = dns_name
|
||||
@ -242,25 +241,26 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
'fqdn': fqdn})
|
||||
return dns_assignment
|
||||
|
||||
def _get_dns_name_for_port_get(self, port, dns_data_db):
|
||||
def _get_dns_name_for_port_get(self, port, dns_data_db, context):
|
||||
if port['fixed_ips']:
|
||||
return self._get_dns_names_for_port(
|
||||
port['fixed_ips'], dns_data_db, port['network_id'])
|
||||
port['fixed_ips'], dns_data_db,
|
||||
port['network_id'], context)
|
||||
return []
|
||||
|
||||
def _extend_port_dict(self, session, db_data, response_data, dns_data_db):
|
||||
def _extend_port_dict(self, db_data, response_data,
|
||||
dns_data_db, context=None):
|
||||
if not dns_data_db:
|
||||
response_data[dns.DNSNAME] = ''
|
||||
else:
|
||||
response_data[dns.DNSNAME] = dns_data_db[dns.DNSNAME]
|
||||
response_data['dns_assignment'] = self._get_dns_name_for_port_get(
|
||||
db_data, dns_data_db)
|
||||
db_data, dns_data_db, context)
|
||||
return response_data
|
||||
|
||||
def extend_port_dict(self, session, db_data, response_data):
|
||||
dns_data_db = db_data.dns
|
||||
return self._extend_port_dict(session, db_data, response_data,
|
||||
dns_data_db)
|
||||
return self._extend_port_dict(db_data, response_data, dns_data_db)
|
||||
|
||||
def _get_network(self, context, network_id):
|
||||
plugin = directory.get_plugin()
|
||||
@ -287,18 +287,19 @@ class DNSExtensionDriverNSXv3(DNSExtensionDriver):
|
||||
self._availability_zones = nsx_az.NsxV3AvailabilityZones()
|
||||
LOG.info("DNSExtensionDriverNSXv3 initialization complete")
|
||||
|
||||
def _get_network_az(self, network_id):
|
||||
context = n_context.get_admin_context()
|
||||
def _get_network_az(self, network_id, context):
|
||||
if not context:
|
||||
context = n_context.get_admin_context()
|
||||
network = self._get_network(context, network_id)
|
||||
if az_ext.AZ_HINTS in network and network[az_ext.AZ_HINTS]:
|
||||
az_name = network[az_ext.AZ_HINTS][0]
|
||||
return self._availability_zones.get_availability_zone(az_name)
|
||||
return self._availability_zones.get_default_availability_zone()
|
||||
|
||||
def _get_dns_domain(self, network_id):
|
||||
def _get_dns_domain(self, network_id, context=None):
|
||||
# try to get the dns-domain from the specific availability zone
|
||||
# of this network
|
||||
az = self._get_network_az(network_id)
|
||||
az = self._get_network_az(network_id, context)
|
||||
if az.dns_domain:
|
||||
dns_domain = az.dns_domain
|
||||
elif cfg.CONF.nsx_v3.dns_domain:
|
||||
|
@ -1359,16 +1359,17 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
'Reason: %(e)s',
|
||||
{'port_id': port_id, 'e': e})
|
||||
|
||||
self._process_l3_delete(context, id)
|
||||
# We would first delete subnet db if the backend dhcp service is
|
||||
# deleted in case of entering delete_subnet logic and retrying
|
||||
# to delete backend dhcp service again.
|
||||
if is_dhcp_backend_deleted:
|
||||
subnets = self._get_subnets_by_network(context, id)
|
||||
for subnet in subnets:
|
||||
super(NsxVPluginV2, self).delete_subnet(
|
||||
context, subnet['id'])
|
||||
super(NsxVPluginV2, self).delete_network(context, id)
|
||||
with db_api.context_manager.writer.using(context):
|
||||
self._process_l3_delete(context, id)
|
||||
# We would first delete subnet db if the backend dhcp service is
|
||||
# deleted in case of entering delete_subnet logic and retrying
|
||||
# to delete backend dhcp service again.
|
||||
if is_dhcp_backend_deleted:
|
||||
subnets = self._get_subnets_by_network(context, id)
|
||||
for subnet in subnets:
|
||||
super(NsxVPluginV2, self).delete_subnet(
|
||||
context, subnet['id'])
|
||||
super(NsxVPluginV2, self).delete_network(context, id)
|
||||
|
||||
# Do not delete a predefined port group that was attached to
|
||||
# an external network
|
||||
@ -1679,6 +1680,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
with db_api.context_manager.writer.using(context):
|
||||
# First we allocate port in neutron database
|
||||
neutron_db = super(NsxVPluginV2, self).create_port(context, port)
|
||||
self._extension_manager.process_create_port(
|
||||
context, port_data, neutron_db)
|
||||
# Port port-security is decided by the port-security state on the
|
||||
# network it belongs to, unless specifically specified here
|
||||
if validators.is_attr_set(port_data.get(psec.PORTSECURITY)):
|
||||
@ -1739,20 +1742,6 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
self._process_port_create_extra_dhcp_opts(
|
||||
context, port_data, dhcp_opts)
|
||||
|
||||
# Invoking the manager callback under transaction fails so here
|
||||
# we do it outside. If this fails we will blow away the port
|
||||
try:
|
||||
with db_api.context_manager.writer.using(context):
|
||||
self._extension_manager.process_create_port(
|
||||
context, port_data, neutron_db)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error('Failed to create port %(id)s. '
|
||||
'Exception: %(e)s',
|
||||
{'id': neutron_db['id'], 'e': e})
|
||||
# Revert what we have created and raise the exception
|
||||
self.delete_port(context, port_data['id'])
|
||||
|
||||
try:
|
||||
# Configure NSX - this should not be done in the DB transaction
|
||||
# Configure the DHCP Edge service
|
||||
|
@ -884,9 +884,10 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
first_try = True
|
||||
while True:
|
||||
try:
|
||||
self._process_l3_delete(context, network_id)
|
||||
return super(NsxV3Plugin, self).delete_network(
|
||||
context, network_id)
|
||||
with db_api.context_manager.writer.using(context):
|
||||
self._process_l3_delete(context, network_id)
|
||||
return super(NsxV3Plugin, self).delete_network(
|
||||
context, network_id)
|
||||
except n_exc.NetworkInUse:
|
||||
# There is a race condition in delete_network() that we need
|
||||
# to work around here. delete_network() issues a query to
|
||||
@ -2035,6 +2036,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
port_data, port_data.get('device_owner'))
|
||||
|
||||
neutron_db = super(NsxV3Plugin, self).create_port(context, port)
|
||||
self._extension_manager.process_create_port(
|
||||
context, port_data, neutron_db)
|
||||
port["port"].update(neutron_db)
|
||||
|
||||
(is_psec_on, has_ip) = self._create_port_preprocess_security(
|
||||
@ -2068,19 +2071,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
# ATTR_NOT_SPECIFIED
|
||||
port_data.pop(mac_ext.MAC_LEARNING)
|
||||
|
||||
# Invoking the manager callback under transaction fails so here
|
||||
# we do it outside. If this fails we will blow away the port
|
||||
try:
|
||||
with db_api.context_manager.writer.using(context):
|
||||
self._extension_manager.process_create_port(
|
||||
context, port_data, neutron_db)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error('Failed to create port %(id)s. '
|
||||
'Exception: %(e)s',
|
||||
{'id': neutron_db['id'], 'e': e})
|
||||
self._cleanup_port(context, neutron_db['id'], None)
|
||||
|
||||
# Operations to backend should be done outside of DB transaction.
|
||||
# NOTE(arosen): ports on external networks are nat rules and do
|
||||
# not result in ports on the backend.
|
||||
|
Loading…
Reference in New Issue
Block a user