Add port dns_domain processing logic
This patchset adds logic to the ML2 DNS integration extension to process a new dns_domain attribute associated to ports. This patchset belongs to a series that adds dns_domain attribute functionality to ports. DocImpact: Ports have a new dns_domain attribute, that takes precedence over networks dns_domain when published to an external DNS service. APIImpact: Users can now specify a dns_domain attribute in port POST and PUT operations. Change-Id: I02d8587d3a1f9f3f6b8cbc79dbe8df4b4b99a893 Partial-Bug: #1650678
This commit is contained in:
parent
37d33b2fcd
commit
4a77533259
@ -80,113 +80,167 @@ class DNSExtensionDriver(api.ExtensionDriver):
|
||||
db_data[dns.DNSDOMAIN] = new_value
|
||||
|
||||
def process_create_port(self, plugin_context, request_data, db_data):
|
||||
if not request_data.get(dns.DNSNAME):
|
||||
if not (request_data.get(dns.DNSNAME) or
|
||||
request_data.get(dns.DNSDOMAIN)):
|
||||
return
|
||||
dns_name, is_dns_domain_default = self._get_request_dns_name(
|
||||
request_data)
|
||||
if is_dns_domain_default:
|
||||
return
|
||||
network = self._get_network(plugin_context, db_data['network_id'])
|
||||
if self.external_dns_not_needed(
|
||||
plugin_context, network) or not network[dns.DNSDOMAIN]:
|
||||
current_dns_name = ''
|
||||
current_dns_domain = ''
|
||||
else:
|
||||
current_dns_name = dns_name
|
||||
current_dns_domain = network[dns.DNSDOMAIN]
|
||||
self._create_port_dns_record(plugin_context, request_data, db_data,
|
||||
network, dns_name)
|
||||
|
||||
port_obj.PortDNS(plugin_context,
|
||||
port_id=db_data['id'],
|
||||
current_dns_name=current_dns_name,
|
||||
current_dns_domain=current_dns_domain,
|
||||
previous_dns_name='',
|
||||
previous_dns_domain='',
|
||||
dns_name=dns_name,
|
||||
dns_domain='').create()
|
||||
def _create_port_dns_record(self, plugin_context, request_data, db_data,
|
||||
network, dns_name):
|
||||
external_dns_domain = (request_data.get(dns.DNSDOMAIN) or
|
||||
network.get(dns.DNSDOMAIN))
|
||||
current_dns_name, current_dns_domain = (
|
||||
self._calculate_current_dns_name_and_domain(
|
||||
dns_name, external_dns_domain,
|
||||
self.external_dns_not_needed(plugin_context, network)))
|
||||
|
||||
def _update_dns_db(self, dns_name, dns_domain, db_data,
|
||||
plugin_context, has_fixed_ips):
|
||||
dns_data_obj = port_obj.PortDNS(
|
||||
plugin_context,
|
||||
port_id=db_data['id'],
|
||||
current_dns_name=current_dns_name,
|
||||
current_dns_domain=current_dns_domain,
|
||||
previous_dns_name='',
|
||||
previous_dns_domain='',
|
||||
dns_name=dns_name,
|
||||
dns_domain=request_data.get(dns.DNSDOMAIN, ''))
|
||||
dns_data_obj.create()
|
||||
return dns_data_obj
|
||||
|
||||
def _calculate_current_dns_name_and_domain(self, dns_name,
|
||||
external_dns_domain,
|
||||
no_external_dns_service):
|
||||
# When creating a new PortDNS object, the current_dns_name and
|
||||
# current_dns_domain fields hold the data that the integration driver
|
||||
# will send to the external DNS service. They are set to non-blank
|
||||
# values only if all the following conditions are met:
|
||||
# 1) There is an external DNS integration driver configured
|
||||
# 2) The user request contains a valid non-blank value for the port's
|
||||
# dns_name
|
||||
# 3) The user request contains a valid non-blank value for the port's
|
||||
# dns_domain or the port's network has a non-blank value in its
|
||||
# dns_domain attribute
|
||||
are_both_dns_attributes_set = dns_name and external_dns_domain
|
||||
if no_external_dns_service or not are_both_dns_attributes_set:
|
||||
return '', ''
|
||||
return dns_name, external_dns_domain
|
||||
|
||||
def _update_dns_db(self, plugin_context, request_data, db_data, network):
|
||||
dns_name = request_data.get(dns.DNSNAME)
|
||||
dns_domain = request_data.get(dns.DNSDOMAIN)
|
||||
has_fixed_ips = 'fixed_ips' in request_data
|
||||
dns_data_db = port_obj.PortDNS.get_object(
|
||||
plugin_context,
|
||||
port_id=db_data['id'])
|
||||
if dns_data_db:
|
||||
is_dns_name_changed = (dns_name is not None and
|
||||
dns_data_db['current_dns_name'] != dns_name)
|
||||
|
||||
if is_dns_name_changed or (has_fixed_ips and
|
||||
dns_data_db['current_dns_name']):
|
||||
dns_data_db['previous_dns_name'] = (
|
||||
dns_data_db['current_dns_name'])
|
||||
dns_data_db['previous_dns_domain'] = (
|
||||
dns_data_db['current_dns_domain'])
|
||||
if is_dns_name_changed:
|
||||
dns_data_db[dns.DNSNAME] = dns_name
|
||||
dns_data_db['current_dns_name'] = dns_name
|
||||
if dns_name:
|
||||
dns_data_db['current_dns_domain'] = dns_domain
|
||||
else:
|
||||
dns_data_db['current_dns_domain'] = ''
|
||||
dns_data_db[dns.DNSNAME] != dns_name)
|
||||
is_dns_domain_changed = (dns_domain is not None and
|
||||
dns_data_db[dns.DNSDOMAIN] != dns_domain)
|
||||
if (is_dns_name_changed or is_dns_domain_changed or
|
||||
(has_fixed_ips and dns_data_db['current_dns_name'])):
|
||||
dns_data_db = self._populate_previous_external_dns_data(
|
||||
dns_data_db)
|
||||
dns_data_db = self._populate_current_external_dns_data(
|
||||
request_data, network, dns_data_db, dns_name, dns_domain,
|
||||
is_dns_name_changed, is_dns_domain_changed)
|
||||
elif not dns_data_db['current_dns_name']:
|
||||
# If port was removed from external DNS service in previous
|
||||
# update, make sure we don't attempt removal again
|
||||
dns_data_db['previous_dns_name'] = ''
|
||||
dns_data_db['previous_dns_domain'] = ''
|
||||
|
||||
dns_data_db.update()
|
||||
return dns_data_db
|
||||
if dns_name:
|
||||
dns_data_db = port_obj.PortDNS(plugin_context,
|
||||
port_id=db_data['id'],
|
||||
current_dns_name=dns_name,
|
||||
current_dns_domain=dns_domain,
|
||||
previous_dns_name='',
|
||||
previous_dns_domain='',
|
||||
dns_name=dns_name,
|
||||
dns_domain='')
|
||||
dns_data_db.create()
|
||||
if dns_name or dns_domain:
|
||||
dns_data_db = self._create_port_dns_record(plugin_context,
|
||||
request_data, db_data, network, dns_name or '')
|
||||
return dns_data_db
|
||||
|
||||
def _populate_previous_external_dns_data(self, dns_data_db):
|
||||
dns_data_db['previous_dns_name'] = (
|
||||
dns_data_db['current_dns_name'])
|
||||
dns_data_db['previous_dns_domain'] = (
|
||||
dns_data_db['current_dns_domain'])
|
||||
return dns_data_db
|
||||
|
||||
def _populate_current_external_dns_data(self, request_data, network,
|
||||
dns_data_db, dns_name, dns_domain,
|
||||
is_dns_name_changed,
|
||||
is_dns_domain_changed):
|
||||
if is_dns_name_changed or is_dns_domain_changed:
|
||||
if is_dns_name_changed:
|
||||
dns_data_db[dns.DNSNAME] = dns_name
|
||||
external_dns_domain = (dns_data_db[dns.DNSDOMAIN] or
|
||||
network.get(dns.DNSDOMAIN))
|
||||
if is_dns_domain_changed:
|
||||
dns_data_db[dns.DNSDOMAIN] = dns_domain
|
||||
external_dns_domain = request_data[dns.DNSDOMAIN]
|
||||
if not external_dns_domain:
|
||||
external_dns_domain = network.get(dns.DNSDOMAIN)
|
||||
dns_data_db['current_dns_name'] = dns_data_db[dns.DNSNAME]
|
||||
dns_data_db['current_dns_domain'] = external_dns_domain
|
||||
if not (dns_data_db['current_dns_name'] and
|
||||
dns_data_db['current_dns_domain']):
|
||||
dns_data_db['current_dns_name'] = ''
|
||||
dns_data_db['current_dns_domain'] = ''
|
||||
return dns_data_db
|
||||
|
||||
def process_update_port(self, plugin_context, request_data, db_data):
|
||||
dns_name = request_data.get(dns.DNSNAME)
|
||||
has_dns_name = dns.DNSNAME in request_data
|
||||
has_fixed_ips = 'fixed_ips' in request_data
|
||||
if dns_name is None and not has_fixed_ips:
|
||||
has_dns_domain = dns.DNSDOMAIN in request_data
|
||||
if not any((has_dns_name, has_fixed_ips, has_dns_domain)):
|
||||
return
|
||||
is_dns_domain_default = self._get_request_dns_name(
|
||||
request_data)[1]
|
||||
if is_dns_domain_default:
|
||||
self._extend_port_dict(plugin_context.session, db_data,
|
||||
db_data, None)
|
||||
return
|
||||
if dns_name is not None:
|
||||
dns_name, is_dns_domain_default = self._get_request_dns_name(
|
||||
request_data)
|
||||
if is_dns_domain_default:
|
||||
self._extend_port_dict(plugin_context.session, db_data,
|
||||
db_data, None)
|
||||
return
|
||||
network = self._get_network(plugin_context, db_data['network_id'])
|
||||
dns_domain = network[dns.DNSDOMAIN]
|
||||
dns_data_db = None
|
||||
if not dns_domain or self.external_dns_not_needed(plugin_context,
|
||||
network):
|
||||
if self.external_dns_not_needed(plugin_context, network):
|
||||
# No need to update external DNS service. Only process the port's
|
||||
# dns_name attribute if necessary
|
||||
if dns_name is not None:
|
||||
dns_data_db = self._process_only_dns_name_update(
|
||||
plugin_context, db_data, dns_name)
|
||||
# dns_name or dns_domain attributes if necessary
|
||||
if has_dns_name or has_dns_domain:
|
||||
dns_data_db = self._process_only_port_update(
|
||||
plugin_context, request_data, db_data)
|
||||
else:
|
||||
dns_data_db = self._update_dns_db(dns_name, dns_domain, db_data,
|
||||
plugin_context, has_fixed_ips)
|
||||
dns_data_db = self._update_dns_db(plugin_context, request_data,
|
||||
db_data, network)
|
||||
self._extend_port_dict(plugin_context.session, db_data, db_data,
|
||||
dns_data_db)
|
||||
|
||||
def _process_only_dns_name_update(self, plugin_context, db_data, dns_name):
|
||||
def _process_only_port_update(self, plugin_context, request_data,
|
||||
db_data):
|
||||
dns_name = request_data.get(dns.DNSNAME)
|
||||
dns_domain = request_data.get(dns.DNSDOMAIN)
|
||||
dns_data_db = port_obj.PortDNS.get_object(
|
||||
plugin_context,
|
||||
port_id=db_data['id'])
|
||||
if dns_data_db:
|
||||
dns_data_db['dns_name'] = dns_name
|
||||
if dns_name is not None and dns_data_db[dns.DNSNAME] != dns_name:
|
||||
dns_data_db[dns.DNSNAME] = dns_name
|
||||
if (dns_domain is not None and
|
||||
dns_data_db[dns.DNSDOMAIN] != dns_domain):
|
||||
dns_data_db[dns.DNSDOMAIN] = dns_domain
|
||||
dns_data_db.update()
|
||||
return dns_data_db
|
||||
if dns_name:
|
||||
dns_data_db = port_obj.PortDNS(plugin_context,
|
||||
port_id=db_data['id'],
|
||||
current_dns_name='',
|
||||
current_dns_domain='',
|
||||
previous_dns_name='',
|
||||
previous_dns_domain='',
|
||||
dns_name=dns_name,
|
||||
dns_domain='')
|
||||
dns_data_db.create()
|
||||
dns_data_db = port_obj.PortDNS(plugin_context,
|
||||
port_id=db_data['id'],
|
||||
current_dns_name='',
|
||||
current_dns_domain='',
|
||||
previous_dns_name='',
|
||||
previous_dns_domain='',
|
||||
dns_name=dns_name or '',
|
||||
dns_domain=dns_domain or '')
|
||||
dns_data_db.create()
|
||||
return dns_data_db
|
||||
|
||||
def external_dns_not_needed(self, context, network):
|
||||
@ -324,15 +378,24 @@ class DNSExtensionDriverML2(DNSExtensionDriver):
|
||||
|
||||
|
||||
class DNSDomainPortsExtensionDriver(DNSExtensionDriverML2):
|
||||
_supported_extension_alias = 'dns-domain-ports'
|
||||
_supported_extension_aliases = ['dns-integration', 'dns-domain-ports']
|
||||
|
||||
@property
|
||||
def extension_alias(self):
|
||||
return self._supported_extension_alias
|
||||
def extension_aliases(self):
|
||||
return self._supported_extension_aliases
|
||||
|
||||
def initialize(self):
|
||||
LOG.info(_LI("DNSDomainPortsExtensionDriver initialization complete"))
|
||||
|
||||
def extend_port_dict(self, session, db_data, response_data):
|
||||
response_data = (
|
||||
super(DNSDomainPortsExtensionDriver, self).extend_port_dict(
|
||||
session, db_data, response_data))
|
||||
dns_data_db = db_data.dns
|
||||
response_data[dns.DNSDOMAIN] = ''
|
||||
if dns_data_db:
|
||||
response_data[dns.DNSDOMAIN] = dns_data_db[dns.DNSDOMAIN]
|
||||
|
||||
|
||||
DNS_DRIVER = None
|
||||
|
||||
@ -411,11 +474,13 @@ def _update_port_in_external_dns_service(resource, event, trigger, **kwargs):
|
||||
return
|
||||
original_ips = [ip['ip_address'] for ip in original_port['fixed_ips']]
|
||||
updated_ips = [ip['ip_address'] for ip in updated_port['fixed_ips']]
|
||||
if (updated_port[dns.DNSNAME] == original_port[dns.DNSNAME] and
|
||||
set(original_ips) == set(updated_ips)):
|
||||
return
|
||||
if (updated_port[dns.DNSNAME] == original_port[dns.DNSNAME] and
|
||||
not original_port[dns.DNSNAME]):
|
||||
is_dns_name_changed = (updated_port[dns.DNSNAME] !=
|
||||
original_port[dns.DNSNAME])
|
||||
is_dns_domain_changed = (dns.DNSDOMAIN in updated_port and
|
||||
updated_port[dns.DNSDOMAIN] !=
|
||||
original_port[dns.DNSDOMAIN])
|
||||
ips_changed = set(original_ips) != set(updated_ips)
|
||||
if not any((is_dns_name_changed, is_dns_domain_changed, ips_changed)):
|
||||
return
|
||||
dns_data_db = port_obj.PortDNS.get_object(
|
||||
context, port_id=updated_port['id'])
|
||||
|
@ -438,10 +438,12 @@ class DNSIntegrationTestCase(test_plugin.Ml2PluginV2TestCase):
|
||||
dns_data_db_2['current_dns_name'])
|
||||
self.assertEqual(dns_data_db_1['current_dns_domain'],
|
||||
dns_data_db_2['current_dns_domain'])
|
||||
self.assertEqual(dns_data_db_1['previous_dns_name'],
|
||||
dns_data_db_2['previous_dns_name'])
|
||||
self.assertEqual(dns_data_db_1['previous_dns_domain'],
|
||||
dns_data_db_2['previous_dns_domain'])
|
||||
# The first update cleared this port's data from the external DNS
|
||||
# service. Therefore, the second update should have cleared
|
||||
# previous_dns_name and previous_dns_domain, which record what has
|
||||
# to be cleared from the external DNS service
|
||||
self.assertFalse(dns_data_db_2['previous_dns_name'])
|
||||
self.assertFalse(dns_data_db_2['previous_dns_domain'])
|
||||
self.assertFalse(mock_client.recordsets.create.call_args_list)
|
||||
self.assertFalse(
|
||||
mock_admin_client.recordsets.create.call_args_list)
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- Ports have now a ``dns_domain`` attribute. A port's ``dns_domain``
|
||||
attribute has precedence over the network's ``dns_domain``
|
||||
from the point of view of publishing it to the external DNS service.
|
Loading…
Reference in New Issue
Block a user