Fix transaction issues with network/subnet facade updates
Commit b8d98a57643d1b94b531ab600fd707e4a3ab8c8c 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):
|
if not request_data.get(dns.DNSNAME):
|
||||||
return
|
return
|
||||||
dns_name, is_dns_domain_default = self._get_request_dns_name(
|
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:
|
if is_dns_domain_default:
|
||||||
return
|
return
|
||||||
network = self._get_network(plugin_context, db_data['network_id'])
|
network = self._get_network(plugin_context, db_data['network_id'])
|
||||||
@ -145,10 +145,9 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
|||||||
return
|
return
|
||||||
if dns_name is not None:
|
if dns_name is not None:
|
||||||
dns_name, is_dns_domain_default = self._get_request_dns_name(
|
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:
|
if is_dns_domain_default:
|
||||||
self._extend_port_dict(plugin_context.session, db_data,
|
self._extend_port_dict(db_data, db_data, None, plugin_context)
|
||||||
db_data, None)
|
|
||||||
return
|
return
|
||||||
network = self._get_network(plugin_context, db_data['network_id'])
|
network = self._get_network(plugin_context, db_data['network_id'])
|
||||||
dns_domain = network[dns.DNSDOMAIN]
|
dns_domain = network[dns.DNSDOMAIN]
|
||||||
@ -163,8 +162,7 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
|||||||
else:
|
else:
|
||||||
dns_data_db = self._update_dns_db(dns_name, dns_domain, db_data,
|
dns_data_db = self._update_dns_db(dns_name, dns_domain, db_data,
|
||||||
plugin_context, has_fixed_ips)
|
plugin_context, has_fixed_ips)
|
||||||
self._extend_port_dict(plugin_context.session, db_data, db_data,
|
self._extend_port_dict(db_data, db_data, dns_data_db, plugin_context)
|
||||||
dns_data_db)
|
|
||||||
|
|
||||||
def _process_only_dns_name_update(self, plugin_context, db_data, dns_name):
|
def _process_only_dns_name_update(self, plugin_context, db_data, dns_name):
|
||||||
dns_data_db = port_obj.PortDNS.get_object(
|
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]
|
response_data[dns.DNSDOMAIN] = db_data.dns_domain[dns.DNSDOMAIN]
|
||||||
return response_data
|
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:
|
if not cfg.CONF.dns_domain:
|
||||||
return ''
|
return ''
|
||||||
if cfg.CONF.dns_domain.endswith('.'):
|
if cfg.CONF.dns_domain.endswith('.'):
|
||||||
return cfg.CONF.dns_domain
|
return cfg.CONF.dns_domain
|
||||||
return '%s.' % cfg.CONF.dns_domain
|
return '%s.' % cfg.CONF.dns_domain
|
||||||
|
|
||||||
def _get_request_dns_name(self, port, network_id):
|
def _get_request_dns_name(self, port, network_id, context):
|
||||||
dns_domain = self._get_dns_domain(network_id)
|
dns_domain = self._get_dns_domain(network_id, context)
|
||||||
if ((dns_domain and dns_domain != DNS_DOMAIN_DEFAULT)):
|
if ((dns_domain and dns_domain != DNS_DOMAIN_DEFAULT)):
|
||||||
return (port.get(dns.DNSNAME, ''), False)
|
return (port.get(dns.DNSNAME, ''), False)
|
||||||
return ('', True)
|
return ('', True)
|
||||||
|
|
||||||
def _get_request_dns_name_and_domain_name(self, dns_data_db, network_id):
|
def _get_request_dns_name_and_domain_name(self, dns_data_db,
|
||||||
dns_domain = self._get_dns_domain(network_id)
|
network_id, context):
|
||||||
|
dns_domain = self._get_dns_domain(network_id, context)
|
||||||
dns_name = ''
|
dns_name = ''
|
||||||
if ((dns_domain and dns_domain != DNS_DOMAIN_DEFAULT)):
|
if ((dns_domain and dns_domain != DNS_DOMAIN_DEFAULT)):
|
||||||
if dns_data_db:
|
if dns_data_db:
|
||||||
dns_name = dns_data_db.dns_name
|
dns_name = dns_data_db.dns_name
|
||||||
return dns_name, dns_domain
|
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_assignment = []
|
||||||
dns_name, dns_domain = self._get_request_dns_name_and_domain_name(
|
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:
|
for ip in ips:
|
||||||
if dns_name:
|
if dns_name:
|
||||||
hostname = dns_name
|
hostname = dns_name
|
||||||
@ -242,25 +241,26 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
|||||||
'fqdn': fqdn})
|
'fqdn': fqdn})
|
||||||
return dns_assignment
|
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']:
|
if port['fixed_ips']:
|
||||||
return self._get_dns_names_for_port(
|
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 []
|
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:
|
if not dns_data_db:
|
||||||
response_data[dns.DNSNAME] = ''
|
response_data[dns.DNSNAME] = ''
|
||||||
else:
|
else:
|
||||||
response_data[dns.DNSNAME] = dns_data_db[dns.DNSNAME]
|
response_data[dns.DNSNAME] = dns_data_db[dns.DNSNAME]
|
||||||
response_data['dns_assignment'] = self._get_dns_name_for_port_get(
|
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
|
return response_data
|
||||||
|
|
||||||
def extend_port_dict(self, session, db_data, response_data):
|
def extend_port_dict(self, session, db_data, response_data):
|
||||||
dns_data_db = db_data.dns
|
dns_data_db = db_data.dns
|
||||||
return self._extend_port_dict(session, db_data, response_data,
|
return self._extend_port_dict(db_data, response_data, dns_data_db)
|
||||||
dns_data_db)
|
|
||||||
|
|
||||||
def _get_network(self, context, network_id):
|
def _get_network(self, context, network_id):
|
||||||
plugin = directory.get_plugin()
|
plugin = directory.get_plugin()
|
||||||
@ -287,18 +287,19 @@ class DNSExtensionDriverNSXv3(DNSExtensionDriver):
|
|||||||
self._availability_zones = nsx_az.NsxV3AvailabilityZones()
|
self._availability_zones = nsx_az.NsxV3AvailabilityZones()
|
||||||
LOG.info("DNSExtensionDriverNSXv3 initialization complete")
|
LOG.info("DNSExtensionDriverNSXv3 initialization complete")
|
||||||
|
|
||||||
def _get_network_az(self, network_id):
|
def _get_network_az(self, network_id, context):
|
||||||
context = n_context.get_admin_context()
|
if not context:
|
||||||
|
context = n_context.get_admin_context()
|
||||||
network = self._get_network(context, network_id)
|
network = self._get_network(context, network_id)
|
||||||
if az_ext.AZ_HINTS in network and network[az_ext.AZ_HINTS]:
|
if az_ext.AZ_HINTS in network and network[az_ext.AZ_HINTS]:
|
||||||
az_name = network[az_ext.AZ_HINTS][0]
|
az_name = network[az_ext.AZ_HINTS][0]
|
||||||
return self._availability_zones.get_availability_zone(az_name)
|
return self._availability_zones.get_availability_zone(az_name)
|
||||||
return self._availability_zones.get_default_availability_zone()
|
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
|
# try to get the dns-domain from the specific availability zone
|
||||||
# of this network
|
# of this network
|
||||||
az = self._get_network_az(network_id)
|
az = self._get_network_az(network_id, context)
|
||||||
if az.dns_domain:
|
if az.dns_domain:
|
||||||
dns_domain = az.dns_domain
|
dns_domain = az.dns_domain
|
||||||
elif cfg.CONF.nsx_v3.dns_domain:
|
elif cfg.CONF.nsx_v3.dns_domain:
|
||||||
|
@ -1359,16 +1359,17 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
'Reason: %(e)s',
|
'Reason: %(e)s',
|
||||||
{'port_id': port_id, 'e': e})
|
{'port_id': port_id, 'e': e})
|
||||||
|
|
||||||
self._process_l3_delete(context, id)
|
with db_api.context_manager.writer.using(context):
|
||||||
# We would first delete subnet db if the backend dhcp service is
|
self._process_l3_delete(context, id)
|
||||||
# deleted in case of entering delete_subnet logic and retrying
|
# We would first delete subnet db if the backend dhcp service is
|
||||||
# to delete backend dhcp service again.
|
# deleted in case of entering delete_subnet logic and retrying
|
||||||
if is_dhcp_backend_deleted:
|
# to delete backend dhcp service again.
|
||||||
subnets = self._get_subnets_by_network(context, id)
|
if is_dhcp_backend_deleted:
|
||||||
for subnet in subnets:
|
subnets = self._get_subnets_by_network(context, id)
|
||||||
super(NsxVPluginV2, self).delete_subnet(
|
for subnet in subnets:
|
||||||
context, subnet['id'])
|
super(NsxVPluginV2, self).delete_subnet(
|
||||||
super(NsxVPluginV2, self).delete_network(context, id)
|
context, subnet['id'])
|
||||||
|
super(NsxVPluginV2, self).delete_network(context, id)
|
||||||
|
|
||||||
# Do not delete a predefined port group that was attached to
|
# Do not delete a predefined port group that was attached to
|
||||||
# an external network
|
# an external network
|
||||||
@ -1679,6 +1680,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
with db_api.context_manager.writer.using(context):
|
with db_api.context_manager.writer.using(context):
|
||||||
# First we allocate port in neutron database
|
# First we allocate port in neutron database
|
||||||
neutron_db = super(NsxVPluginV2, self).create_port(context, port)
|
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
|
# Port port-security is decided by the port-security state on the
|
||||||
# network it belongs to, unless specifically specified here
|
# network it belongs to, unless specifically specified here
|
||||||
if validators.is_attr_set(port_data.get(psec.PORTSECURITY)):
|
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(
|
self._process_port_create_extra_dhcp_opts(
|
||||||
context, port_data, 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:
|
try:
|
||||||
# Configure NSX - this should not be done in the DB transaction
|
# Configure NSX - this should not be done in the DB transaction
|
||||||
# Configure the DHCP Edge service
|
# Configure the DHCP Edge service
|
||||||
|
@ -884,9 +884,10 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
first_try = True
|
first_try = True
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
self._process_l3_delete(context, network_id)
|
with db_api.context_manager.writer.using(context):
|
||||||
return super(NsxV3Plugin, self).delete_network(
|
self._process_l3_delete(context, network_id)
|
||||||
context, network_id)
|
return super(NsxV3Plugin, self).delete_network(
|
||||||
|
context, network_id)
|
||||||
except n_exc.NetworkInUse:
|
except n_exc.NetworkInUse:
|
||||||
# There is a race condition in delete_network() that we need
|
# There is a race condition in delete_network() that we need
|
||||||
# to work around here. delete_network() issues a query to
|
# 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'))
|
port_data, port_data.get('device_owner'))
|
||||||
|
|
||||||
neutron_db = super(NsxV3Plugin, self).create_port(context, port)
|
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)
|
port["port"].update(neutron_db)
|
||||||
|
|
||||||
(is_psec_on, has_ip) = self._create_port_preprocess_security(
|
(is_psec_on, has_ip) = self._create_port_preprocess_security(
|
||||||
@ -2068,19 +2071,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
# ATTR_NOT_SPECIFIED
|
# ATTR_NOT_SPECIFIED
|
||||||
port_data.pop(mac_ext.MAC_LEARNING)
|
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.
|
# Operations to backend should be done outside of DB transaction.
|
||||||
# NOTE(arosen): ports on external networks are nat rules and do
|
# NOTE(arosen): ports on external networks are nat rules and do
|
||||||
# not result in ports on the backend.
|
# not result in ports on the backend.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user