Rename all references of Domain to Zone
This is a pretty invasive change :) A non complete list of changes: * Database Tables * Database Columns * Designate Objects and fields on Objects * Designate Objects Adaptors stop doing some of the renames * All RPCAPI versions are bumped - totally backward incompatable (function names have changed) Change-Id: Ib99e918998a3909fa4aa92bf1ee0475f8a519196
This commit is contained in:
parent
3e9ec422ab
commit
c5949ccb28
@ -213,11 +213,11 @@ class IPABackend(base.Backend):
|
|||||||
self.ntries = cfg.CONF[self.name].ipa_connect_retries
|
self.ntries = cfg.CONF[self.name].ipa_connect_retries
|
||||||
self.force = cfg.CONF[self.name].ipa_force_ns_use
|
self.force = cfg.CONF[self.name].ipa_force_ns_use
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.debug('Create Domain %r' % domain)
|
LOG.debug('Create Zone %r' % zone)
|
||||||
ipareq = {'method': 'dnszone_add', 'id': 0}
|
ipareq = {'method': 'dnszone_add', 'id': 0}
|
||||||
params = [domain['name']]
|
params = [zone['name']]
|
||||||
servers = self.central_service.get_domain_servers(self.admin_context)
|
servers = self.central_service.get_zone_ns_records(self.admin_context)
|
||||||
# just use the first one for zone creation - add the others
|
# just use the first one for zone creation - add the others
|
||||||
# later, below - use force because designate assumes the NS
|
# later, below - use force because designate assumes the NS
|
||||||
# already exists somewhere, is resolvable, and already has
|
# already exists somewhere, is resolvable, and already has
|
||||||
@ -226,35 +226,35 @@ class IPABackend(base.Backend):
|
|||||||
if self.force:
|
if self.force:
|
||||||
args['force'] = True
|
args['force'] = True
|
||||||
for dkey, ipakey in list(domain2ipa.items()):
|
for dkey, ipakey in list(domain2ipa.items()):
|
||||||
if dkey in domain:
|
if dkey in zone:
|
||||||
args[ipakey] = domain[dkey]
|
args[ipakey] = zone[dkey]
|
||||||
ipareq['params'] = [params, args]
|
ipareq['params'] = [params, args]
|
||||||
self._call_and_handle_error(ipareq)
|
self._call_and_handle_error(ipareq)
|
||||||
# add NS records for all of the other servers
|
# add NS records for all of the other servers
|
||||||
if len(servers) > 1:
|
if len(servers) > 1:
|
||||||
ipareq = {'method': 'dnsrecord_add', 'id': 0}
|
ipareq = {'method': 'dnsrecord_add', 'id': 0}
|
||||||
params = [domain['name'], "@"]
|
params = [zone['name'], "@"]
|
||||||
args = {'nsrecord': servers[1:]}
|
args = {'nsrecord': servers[1:]}
|
||||||
if self.force:
|
if self.force:
|
||||||
args['force'] = True
|
args['force'] = True
|
||||||
ipareq['params'] = [params, args]
|
ipareq['params'] = [params, args]
|
||||||
self._call_and_handle_error(ipareq)
|
self._call_and_handle_error(ipareq)
|
||||||
|
|
||||||
def update_domain(self, context, domain):
|
def update_zone(self, context, zone):
|
||||||
LOG.debug('Update Domain %r' % domain)
|
LOG.debug('Update Zone %r' % zone)
|
||||||
ipareq = {'method': 'dnszone_mod', 'id': 0}
|
ipareq = {'method': 'dnszone_mod', 'id': 0}
|
||||||
params = [domain['name']]
|
params = [zone['name']]
|
||||||
args = {}
|
args = {}
|
||||||
for dkey, ipakey in list(domain2ipa.items()):
|
for dkey, ipakey in list(domain2ipa.items()):
|
||||||
if dkey in domain:
|
if dkey in zone:
|
||||||
args[ipakey] = domain[dkey]
|
args[ipakey] = zone[dkey]
|
||||||
ipareq['params'] = [params, args]
|
ipareq['params'] = [params, args]
|
||||||
self._call_and_handle_error(ipareq)
|
self._call_and_handle_error(ipareq)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
LOG.debug('Delete Domain %r' % domain)
|
LOG.debug('Delete Zone %r' % zone)
|
||||||
ipareq = {'method': 'dnszone_del', 'id': 0}
|
ipareq = {'method': 'dnszone_del', 'id': 0}
|
||||||
params = [domain['name']]
|
params = [zone['name']]
|
||||||
args = {}
|
args = {}
|
||||||
ipareq['params'] = [params, args]
|
ipareq['params'] = [params, args]
|
||||||
self._call_and_handle_error(ipareq)
|
self._call_and_handle_error(ipareq)
|
||||||
|
@ -97,54 +97,54 @@ class MultiBackend(base.Backend):
|
|||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self.slave.create_tsigkey(context, tsigkey)
|
self.slave.create_tsigkey(context, tsigkey)
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
self.master.create_domain(context, domain)
|
self.master.create_zone(context, zone)
|
||||||
try:
|
try:
|
||||||
self.slave.create_domain(context, domain)
|
self.slave.create_zone(context, zone)
|
||||||
except Exception:
|
except Exception:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self.master.delete_domain(context, domain)
|
self.master.delete_zone(context, zone)
|
||||||
|
|
||||||
def update_domain(self, context, domain):
|
def update_zone(self, context, zone):
|
||||||
self.master.update_domain(context, domain)
|
self.master.update_zone(context, zone)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
# Fetch the full domain from Central first, as we may
|
# Fetch the full zone from Central first, as we may
|
||||||
# have to recreate it on slave if delete on master fails
|
# have to recreate it on slave if delete on master fails
|
||||||
deleted_context = context.deepcopy()
|
deleted_context = context.deepcopy()
|
||||||
deleted_context.show_deleted = True
|
deleted_context.show_deleted = True
|
||||||
|
|
||||||
full_domain = self.central.find_domain(
|
full_domain = self.central.find_zone(
|
||||||
deleted_context, {'id': domain['id']})
|
deleted_context, {'id': zone['id']})
|
||||||
|
|
||||||
self.slave.delete_domain(context, domain)
|
self.slave.delete_zone(context, zone)
|
||||||
try:
|
try:
|
||||||
self.master.delete_domain(context, domain)
|
self.master.delete_zone(context, zone)
|
||||||
except Exception:
|
except Exception:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self.slave.create_domain(context, domain)
|
self.slave.create_zone(context, zone)
|
||||||
|
|
||||||
[self.slave.create_record(context, domain, record)
|
[self.slave.create_record(context, zone, record)
|
||||||
for record in self.central.find_records(
|
for record in self.central.find_records(
|
||||||
context, {'domain_id': full_domain['id']})]
|
context, {'domain_id': full_domain['id']})]
|
||||||
|
|
||||||
def create_recordset(self, context, domain, recordset):
|
def create_recordset(self, context, zone, recordset):
|
||||||
self.master.create_recordset(context, domain, recordset)
|
self.master.create_recordset(context, zone, recordset)
|
||||||
|
|
||||||
def update_recordset(self, context, domain, recordset):
|
def update_recordset(self, context, zone, recordset):
|
||||||
self.master.update_recordset(context, domain, recordset)
|
self.master.update_recordset(context, zone, recordset)
|
||||||
|
|
||||||
def delete_recordset(self, context, domain, recordset):
|
def delete_recordset(self, context, zone, recordset):
|
||||||
self.master.delete_recordset(context, domain, recordset)
|
self.master.delete_recordset(context, zone, recordset)
|
||||||
|
|
||||||
def create_record(self, context, domain, recordset, record):
|
def create_record(self, context, zone, recordset, record):
|
||||||
self.master.create_record(context, domain, recordset, record)
|
self.master.create_record(context, zone, recordset, record)
|
||||||
|
|
||||||
def update_record(self, context, domain, recordset, record):
|
def update_record(self, context, zone, recordset, record):
|
||||||
self.master.update_record(context, domain, recordset, record)
|
self.master.update_record(context, zone, recordset, record)
|
||||||
|
|
||||||
def delete_record(self, context, domain, recordset, record):
|
def delete_record(self, context, zone, recordset, record):
|
||||||
self.master.delete_record(context, domain, recordset, record)
|
self.master.delete_record(context, zone, recordset, record)
|
||||||
|
|
||||||
def ping(self, context):
|
def ping(self, context):
|
||||||
return {
|
return {
|
||||||
|
@ -242,7 +242,7 @@ def main():
|
|||||||
# create a fake domain in IPA
|
# create a fake domain in IPA
|
||||||
# create a fake server in Designate
|
# create a fake server in Designate
|
||||||
# try to create the same fake domain in Designate
|
# try to create the same fake domain in Designate
|
||||||
# if we get a DuplicateDomain error from Designate, then
|
# if we get a DuplicateZone error from Designate, then
|
||||||
# raise the CannotUseIPABackend error, after deleting
|
# raise the CannotUseIPABackend error, after deleting
|
||||||
# the fake server and fake domain
|
# the fake server and fake domain
|
||||||
# find the first non-reverse zone
|
# find the first non-reverse zone
|
||||||
|
@ -305,7 +305,7 @@ ComputeAdminGroup = [
|
|||||||
help="API key to use when authenticating as admin.",
|
help="API key to use when authenticating as admin.",
|
||||||
secret=True),
|
secret=True),
|
||||||
cfg.StrOpt('domain_name',
|
cfg.StrOpt('domain_name',
|
||||||
help="Domain name for authentication as admin (Keystone V3)."
|
help="Zone name for authentication as admin (Keystone V3)."
|
||||||
"The same domain applies to user and project"),
|
"The same domain applies to user and project"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -39,13 +39,13 @@ class DomainsClientJSON(rest_client.RestClient):
|
|||||||
"""Get the details of a domain."""
|
"""Get the details of a domain."""
|
||||||
resp, body = self.get("v1/domains/%s" % str(domain_id))
|
resp, body = self.get("v1/domains/%s" % str(domain_id))
|
||||||
body = json.loads(body)
|
body = json.loads(body)
|
||||||
self.validate_response(schema.get_domain, resp, body)
|
self.validate_response(schema.get_zone, resp, body)
|
||||||
return resp, body
|
return resp, body
|
||||||
|
|
||||||
def delete_domain(self, domain_id):
|
def delete_domain(self, domain_id):
|
||||||
"""Delete the given domain."""
|
"""Delete the given domain."""
|
||||||
resp, body = self.delete("v1/domains/%s" % str(domain_id))
|
resp, body = self.delete("v1/domains/%s" % str(domain_id))
|
||||||
self.validate_response(schema.delete_domain, resp, body)
|
self.validate_response(schema.delete_zone, resp, body)
|
||||||
return resp, body
|
return resp, body
|
||||||
|
|
||||||
def create_domain(self, name, email, **kwargs):
|
def create_domain(self, name, email, **kwargs):
|
||||||
@ -61,7 +61,7 @@ class DomainsClientJSON(rest_client.RestClient):
|
|||||||
post_body[post_param] = value
|
post_body[post_param] = value
|
||||||
resp, body = self.post('v1/domains', json.dumps(post_body))
|
resp, body = self.post('v1/domains', json.dumps(post_body))
|
||||||
body = json.loads(body)
|
body = json.loads(body)
|
||||||
self.validate_response(schema.create_domain, resp, body)
|
self.validate_response(schema.create_zone, resp, body)
|
||||||
return resp, body
|
return resp, body
|
||||||
|
|
||||||
def update_domain(self, domain_id, **kwargs):
|
def update_domain(self, domain_id, **kwargs):
|
||||||
@ -75,5 +75,5 @@ class DomainsClientJSON(rest_client.RestClient):
|
|||||||
resp, body = self.put('v1/domains/%s' % domain_id,
|
resp, body = self.put('v1/domains/%s' % domain_id,
|
||||||
json.dumps(post_body))
|
json.dumps(post_body))
|
||||||
body = json.loads(body)
|
body = json.loads(body)
|
||||||
self.validate_response(schema.update_domain, resp, body)
|
self.validate_response(schema.update_zone, resp, body)
|
||||||
return resp, body
|
return resp, body
|
||||||
|
@ -30,19 +30,19 @@ class DnsDomainsTest(base.BaseDnsTest):
|
|||||||
for i in range(2):
|
for i in range(2):
|
||||||
name = data_utils.rand_name('domain') + '.com.'
|
name = data_utils.rand_name('domain') + '.com.'
|
||||||
email = data_utils.rand_name('dns') + '@testmail.com'
|
email = data_utils.rand_name('dns') + '@testmail.com'
|
||||||
_, domain = cls.client.create_domain(name, email)
|
_, domain = cls.client.create_zone(name, email)
|
||||||
cls.setup_domains.append(domain)
|
cls.setup_domains.append(domain)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
for domain in cls.setup_domains:
|
for domain in cls.setup_domains:
|
||||||
cls.client.delete_domain(domain['id'])
|
cls.client.delete_zone(domain['id'])
|
||||||
super(DnsDomainsTest, cls).tearDownClass()
|
super(DnsDomainsTest, cls).tearDownClass()
|
||||||
|
|
||||||
def _delete_domain(self, domain_id):
|
def _delete_domain(self, domain_id):
|
||||||
self.client.delete_domain(domain_id)
|
self.client.delete_zone(domain_id)
|
||||||
self.assertRaises(exceptions.NotFound,
|
self.assertRaises(exceptions.NotFound,
|
||||||
self.client.get_domain, domain_id)
|
self.client.get_zone, domain_id)
|
||||||
|
|
||||||
@test.attr(type='gate')
|
@test.attr(type='gate')
|
||||||
def test_list_domains(self):
|
def test_list_domains(self):
|
||||||
@ -54,20 +54,20 @@ class DnsDomainsTest(base.BaseDnsTest):
|
|||||||
|
|
||||||
@test.attr(type='smoke')
|
@test.attr(type='smoke')
|
||||||
def test_create_update_get_domain(self):
|
def test_create_update_get_domain(self):
|
||||||
# Create Domain
|
# Create Zone
|
||||||
d_name = data_utils.rand_name('domain') + '.com.'
|
d_name = data_utils.rand_name('domain') + '.com.'
|
||||||
d_email = data_utils.rand_name('dns') + '@testmail.com'
|
d_email = data_utils.rand_name('dns') + '@testmail.com'
|
||||||
_, domain = self.client.create_domain(name=d_name, email=d_email)
|
_, domain = self.client.create_zone(name=d_name, email=d_email)
|
||||||
self.addCleanup(self._delete_domain, domain['id'])
|
self.addCleanup(self._delete_domain, domain['id'])
|
||||||
self.assertEqual(d_name, domain['name'])
|
self.assertEqual(d_name, domain['name'])
|
||||||
self.assertEqual(d_email, domain['email'])
|
self.assertEqual(d_email, domain['email'])
|
||||||
# Update Domain with ttl
|
# Update Zone with ttl
|
||||||
d_ttl = 3600
|
d_ttl = 3600
|
||||||
_, update_domain = self.client.update_domain(domain['id'],
|
_, update_domain = self.client.update_zone(domain['id'],
|
||||||
ttl=d_ttl)
|
ttl=d_ttl)
|
||||||
self.assertEqual(d_ttl, update_domain['ttl'])
|
self.assertEqual(d_ttl, update_domain['ttl'])
|
||||||
# Get the details of Domain
|
# Get the details of Zone
|
||||||
_, get_domain = self.client.get_domain(domain['id'])
|
_, get_domain = self.client.get_zone(domain['id'])
|
||||||
self.assertEqual(update_domain['name'], get_domain['name'])
|
self.assertEqual(update_domain['name'], get_domain['name'])
|
||||||
self.assertEqual(update_domain['email'], get_domain['email'])
|
self.assertEqual(update_domain['email'], get_domain['email'])
|
||||||
self.assertEqual(update_domain['ttl'], get_domain['ttl'])
|
self.assertEqual(update_domain['ttl'], get_domain['ttl'])
|
||||||
|
@ -30,7 +30,7 @@ class RecordsTest(base.BaseDnsTest):
|
|||||||
cls.setup_records = list()
|
cls.setup_records = list()
|
||||||
name = data_utils.rand_name('domain') + '.com.'
|
name = data_utils.rand_name('domain') + '.com.'
|
||||||
email = data_utils.rand_name('dns') + '@testmail.com'
|
email = data_utils.rand_name('dns') + '@testmail.com'
|
||||||
_, cls.domain = cls.dns_domains_client.create_domain(name, email)
|
_, cls.domain = cls.dns_domains_client.create_zone(name, email)
|
||||||
# Creates a record with type as A
|
# Creates a record with type as A
|
||||||
r_name = 'www.' + name
|
r_name = 'www.' + name
|
||||||
data1 = "192.0.2.3"
|
data1 = "192.0.2.3"
|
||||||
@ -49,7 +49,7 @@ class RecordsTest(base.BaseDnsTest):
|
|||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
for record in cls.setup_records:
|
for record in cls.setup_records:
|
||||||
cls.client.delete_record(cls.domain['id'], record['id'])
|
cls.client.delete_record(cls.domain['id'], record['id'])
|
||||||
cls.dns_domains_client.delete_domain(cls.domain['id'])
|
cls.dns_domains_client.delete_zone(cls.domain['id'])
|
||||||
|
|
||||||
def _delete_record(self, domain_id, record_id):
|
def _delete_record(self, domain_id, record_id):
|
||||||
self.client.delete_record(domain_id, record_id)
|
self.client.delete_record(domain_id, record_id)
|
||||||
@ -66,11 +66,11 @@ class RecordsTest(base.BaseDnsTest):
|
|||||||
|
|
||||||
@test.attr(type='smoke')
|
@test.attr(type='smoke')
|
||||||
def test_create_update_get_delete_record(self):
|
def test_create_update_get_delete_record(self):
|
||||||
# Create Domain
|
# Create Zone
|
||||||
name = data_utils.rand_name('domain') + '.com.'
|
name = data_utils.rand_name('domain') + '.com.'
|
||||||
email = data_utils.rand_name('dns') + '@testmail.com'
|
email = data_utils.rand_name('dns') + '@testmail.com'
|
||||||
_, domain = self.dns_domains_client.create_domain(name, email)
|
_, domain = self.dns_domains_client.create_zone(name, email)
|
||||||
self.addCleanup(self.dns_domains_client.delete_domain, domain['id'])
|
self.addCleanup(self.dns_domains_client.delete_zone, domain['id'])
|
||||||
# Create Record
|
# Create Record
|
||||||
r_name = 'www.' + name
|
r_name = 'www.' + name
|
||||||
r_data = "192.0.2.4"
|
r_data = "192.0.2.4"
|
||||||
|
@ -108,28 +108,28 @@ class RequestHandler(object):
|
|||||||
|
|
||||||
question = request.question[0]
|
question = request.question[0]
|
||||||
requester = request.environ['addr'][0]
|
requester = request.environ['addr'][0]
|
||||||
domain_name = question.name.to_text()
|
zone_name = question.name.to_text()
|
||||||
|
|
||||||
if not self._allowed(request, requester, "CREATE", domain_name):
|
if not self._allowed(request, requester, "CREATE", zone_name):
|
||||||
response.set_rcode(dns.rcode.from_text("REFUSED"))
|
response.set_rcode(dns.rcode.from_text("REFUSED"))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
serial = self.backend.find_domain_serial(domain_name)
|
serial = self.backend.find_zone_serial(zone_name)
|
||||||
|
|
||||||
if serial is not None:
|
if serial is not None:
|
||||||
LOG.warn(_LW("Not creating %(name)s, zone already exists") %
|
LOG.warn(_LW("Not creating %(name)s, zone already exists") %
|
||||||
{'name': domain_name})
|
{'name': zone_name})
|
||||||
# Provide an authoritative answer
|
# Provide an authoritative answer
|
||||||
response.flags |= dns.flags.AA
|
response.flags |= dns.flags.AA
|
||||||
return response
|
return response
|
||||||
|
|
||||||
LOG.debug("Received %(verb)s for %(name)s from %(host)s" %
|
LOG.debug("Received %(verb)s for %(name)s from %(host)s" %
|
||||||
{'verb': "CREATE", 'name': domain_name, 'host': requester})
|
{'verb': "CREATE", 'name': zone_name, 'host': requester})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
zone = dnsutils.do_axfr(domain_name, self.masters,
|
zone = dnsutils.do_axfr(zone_name, self.masters,
|
||||||
source=self.transfer_source)
|
source=self.transfer_source)
|
||||||
self.backend.create_domain(zone)
|
self.backend.create_zone(zone)
|
||||||
except Exception:
|
except Exception:
|
||||||
response.set_rcode(dns.rcode.from_text("SERVFAIL"))
|
response.set_rcode(dns.rcode.from_text("SERVFAIL"))
|
||||||
return response
|
return response
|
||||||
@ -152,35 +152,35 @@ class RequestHandler(object):
|
|||||||
|
|
||||||
question = request.question[0]
|
question = request.question[0]
|
||||||
requester = request.environ['addr'][0]
|
requester = request.environ['addr'][0]
|
||||||
domain_name = question.name.to_text()
|
zone_name = question.name.to_text()
|
||||||
|
|
||||||
if not self._allowed(request, requester, "NOTIFY", domain_name):
|
if not self._allowed(request, requester, "NOTIFY", zone_name):
|
||||||
response.set_rcode(dns.rcode.from_text("REFUSED"))
|
response.set_rcode(dns.rcode.from_text("REFUSED"))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
serial = self.backend.find_domain_serial(domain_name)
|
serial = self.backend.find_zone_serial(zone_name)
|
||||||
|
|
||||||
if serial is None:
|
if serial is None:
|
||||||
LOG.warn(_LW("Refusing NOTIFY for %(name)s, doesn't exist") %
|
LOG.warn(_LW("Refusing NOTIFY for %(name)s, doesn't exist") %
|
||||||
{'name': domain_name})
|
{'name': zone_name})
|
||||||
response.set_rcode(dns.rcode.from_text("REFUSED"))
|
response.set_rcode(dns.rcode.from_text("REFUSED"))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
LOG.debug("Received %(verb)s for %(name)s from %(host)s" %
|
LOG.debug("Received %(verb)s for %(name)s from %(host)s" %
|
||||||
{'verb': "NOTIFY", 'name': domain_name, 'host': requester})
|
{'verb': "NOTIFY", 'name': zone_name, 'host': requester})
|
||||||
|
|
||||||
# According to RFC we should query the server that sent the NOTIFY
|
# According to RFC we should query the server that sent the NOTIFY
|
||||||
# TODO(Tim): Reenable this when it makes more sense
|
# TODO(Tim): Reenable this when it makes more sense
|
||||||
# resolver = dns.resolver.Resolver()
|
# resolver = dns.resolver.Resolver()
|
||||||
# resolver.nameservers = [requester]
|
# resolver.nameservers = [requester]
|
||||||
# This assumes that the Master is running on port 53
|
# This assumes that the Master is running on port 53
|
||||||
# soa_answer = resolver.query(domain_name, 'SOA')
|
# soa_answer = resolver.query(zone_name, 'SOA')
|
||||||
# Check that the serial is < serial above
|
# Check that the serial is < serial above
|
||||||
|
|
||||||
try:
|
try:
|
||||||
zone = dnsutils.do_axfr(domain_name, self.masters,
|
zone = dnsutils.do_axfr(zone_name, self.masters,
|
||||||
source=self.transfer_source)
|
source=self.transfer_source)
|
||||||
self.backend.update_domain(zone)
|
self.backend.update_zone(zone)
|
||||||
except Exception:
|
except Exception:
|
||||||
response.set_rcode(dns.rcode.from_text("SERVFAIL"))
|
response.set_rcode(dns.rcode.from_text("SERVFAIL"))
|
||||||
return response
|
return response
|
||||||
@ -203,44 +203,44 @@ class RequestHandler(object):
|
|||||||
|
|
||||||
question = request.question[0]
|
question = request.question[0]
|
||||||
requester = request.environ['addr'][0]
|
requester = request.environ['addr'][0]
|
||||||
domain_name = question.name.to_text()
|
zone_name = question.name.to_text()
|
||||||
|
|
||||||
if not self._allowed(request, requester, "DELETE", domain_name):
|
if not self._allowed(request, requester, "DELETE", zone_name):
|
||||||
response.set_rcode(dns.rcode.from_text("REFUSED"))
|
response.set_rcode(dns.rcode.from_text("REFUSED"))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
serial = self.backend.find_domain_serial(domain_name)
|
serial = self.backend.find_zone_serial(zone_name)
|
||||||
|
|
||||||
if serial is None:
|
if serial is None:
|
||||||
LOG.warn(_LW("Not deleting %(name)s, zone doesn't exist") %
|
LOG.warn(_LW("Not deleting %(name)s, zone doesn't exist") %
|
||||||
{'name': domain_name})
|
{'name': zone_name})
|
||||||
# Provide an authoritative answer
|
# Provide an authoritative answer
|
||||||
response.flags |= dns.flags.AA
|
response.flags |= dns.flags.AA
|
||||||
return response
|
return response
|
||||||
|
|
||||||
LOG.debug("Received DELETE for %(name)s from %(host)s" %
|
LOG.debug("Received DELETE for %(name)s from %(host)s" %
|
||||||
{'name': domain_name, 'host': requester})
|
{'name': zone_name, 'host': requester})
|
||||||
|
|
||||||
# Provide an authoritative answer
|
# Provide an authoritative answer
|
||||||
response.flags |= dns.flags.AA
|
response.flags |= dns.flags.AA
|
||||||
|
|
||||||
# Call into the backend to Delete
|
# Call into the backend to Delete
|
||||||
try:
|
try:
|
||||||
self.backend.delete_domain(domain_name)
|
self.backend.delete_zone(zone_name)
|
||||||
except Exception:
|
except Exception:
|
||||||
response.set_rcode(dns.rcode.from_text("SERVFAIL"))
|
response.set_rcode(dns.rcode.from_text("SERVFAIL"))
|
||||||
return response
|
return response
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def _allowed(self, request, requester, op, domain_name):
|
def _allowed(self, request, requester, op, zone_name):
|
||||||
# If there are no explict notifiers specified, allow all
|
# If there are no explict notifiers specified, allow all
|
||||||
if not self.allow_notify:
|
if not self.allow_notify:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if requester not in self.allow_notify:
|
if requester not in self.allow_notify:
|
||||||
LOG.warn(_LW("%(verb)s for %(name)s from %(server)s refused") %
|
LOG.warn(_LW("%(verb)s for %(name)s from %(server)s refused") %
|
||||||
{'verb': op, 'name': domain_name, 'server': requester})
|
{'verb': op, 'name': zone_name, 'server': requester})
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -33,7 +33,7 @@ class BaseView(object):
|
|||||||
as part of the API call.
|
as part of the API call.
|
||||||
|
|
||||||
For example, in the V2 API, we did s/domain/zone/. Adapting a record
|
For example, in the V2 API, we did s/domain/zone/. Adapting a record
|
||||||
resources "domain_id" <-> "zone_id" is the responsibility of a View.
|
resources "tenant_id" <-> "project_id" is the responsibility of a View.
|
||||||
"""
|
"""
|
||||||
_resource_name = None
|
_resource_name = None
|
||||||
_collection_name = None
|
_collection_name = None
|
||||||
|
@ -30,24 +30,15 @@ class QuotasView(base_view.BaseView):
|
|||||||
def show_basic(self, context, request, quota):
|
def show_basic(self, context, request, quota):
|
||||||
"""Basic view of a quota"""
|
"""Basic view of a quota"""
|
||||||
return {
|
return {
|
||||||
"zones": quota['domains'],
|
"zones": quota['zones'],
|
||||||
"zone_records": quota['domain_records'],
|
"zone_records": quota['zone_records'],
|
||||||
"zone_recordsets": quota['domain_recordsets'],
|
"zone_recordsets": quota['zone_recordsets'],
|
||||||
"recordset_records": quota['recordset_records']
|
"recordset_records": quota['recordset_records']
|
||||||
}
|
}
|
||||||
|
|
||||||
def load(self, context, request, body):
|
def load(self, context, request, body):
|
||||||
"""Extract a "central" compatible dict from an API call"""
|
"""Extract a "central" compatible dict from an API call"""
|
||||||
valid_keys = ('domain_records', 'domain_recordsets', 'domains',
|
valid_keys = ('zone_records', 'zone_recordsets', 'zones',
|
||||||
'recordset_records')
|
'recordset_records')
|
||||||
|
|
||||||
mapping = {
|
|
||||||
'zones': 'domains',
|
|
||||||
'zone_records': 'domain_records',
|
|
||||||
'zone_recordsets': 'domain_recordsets',
|
|
||||||
'recordset_records': 'recordset_records'
|
|
||||||
}
|
|
||||||
|
|
||||||
body["quota"] = {mapping[k]: body["quota"][k] for k in body["quota"]}
|
|
||||||
|
|
||||||
return self._load(context, request, body, valid_keys)
|
return self._load(context, request, body, valid_keys)
|
||||||
|
@ -51,7 +51,7 @@ class TenantsView(base_view.BaseView):
|
|||||||
"""Basic view of the Tenants Report"""
|
"""Basic view of the Tenants Report"""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"zone_count": tenants['domain_count'],
|
"zone_count": tenants['zone_count'],
|
||||||
"id": tenants['id'],
|
"id": tenants['id'],
|
||||||
"links": self._get_resource_links(request, tenants)
|
"links": self._get_resource_links(request, tenants)
|
||||||
}
|
}
|
||||||
@ -60,8 +60,8 @@ class TenantsView(base_view.BaseView):
|
|||||||
"""Detail view of the Tenants Report"""
|
"""Detail view of the Tenants Report"""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"zones_count": tenant['domain_count'],
|
"zones_count": tenant['zone_count'],
|
||||||
"zones": tenant['domains'],
|
"zones": tenant['zones'],
|
||||||
"id": tenant['id'],
|
"id": tenant['id'],
|
||||||
"links": self._get_resource_links(request, tenant)
|
"links": self._get_resource_links(request, tenant)
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ def create_domain():
|
|||||||
# A V1 zone only supports being a primary (No notion of a type)
|
# A V1 zone only supports being a primary (No notion of a type)
|
||||||
values['type'] = 'PRIMARY'
|
values['type'] = 'PRIMARY'
|
||||||
|
|
||||||
domain = central_api.create_domain(context, objects.Domain(**values))
|
domain = central_api.create_zone(context, objects.Zone(**values))
|
||||||
|
|
||||||
response = flask.jsonify(domain_schema.filter(domain))
|
response = flask.jsonify(domain_schema.filter(domain))
|
||||||
response.status_int = 201
|
response.status_int = 201
|
||||||
@ -80,7 +80,7 @@ def get_domains():
|
|||||||
|
|
||||||
central_api = central_rpcapi.CentralAPI.get_instance()
|
central_api = central_rpcapi.CentralAPI.get_instance()
|
||||||
|
|
||||||
domains = central_api.find_domains(context, criterion={"type": "PRIMARY"})
|
domains = central_api.find_zones(context, criterion={"type": "PRIMARY"})
|
||||||
|
|
||||||
return flask.jsonify(domains_schema.filter({'domains': domains}))
|
return flask.jsonify(domains_schema.filter({'domains': domains}))
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ def get_domain(domain_id):
|
|||||||
central_api = central_rpcapi.CentralAPI.get_instance()
|
central_api = central_rpcapi.CentralAPI.get_instance()
|
||||||
|
|
||||||
criterion = {"id": domain_id, "type": "PRIMARY"}
|
criterion = {"id": domain_id, "type": "PRIMARY"}
|
||||||
domain = central_api.find_domain(context, criterion=criterion)
|
domain = central_api.find_zone(context, criterion=criterion)
|
||||||
|
|
||||||
return flask.jsonify(domain_schema.filter(domain))
|
return flask.jsonify(domain_schema.filter(domain))
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ def update_domain(domain_id):
|
|||||||
|
|
||||||
# Fetch the existing resource
|
# Fetch the existing resource
|
||||||
criterion = {"id": domain_id, "type": "PRIMARY"}
|
criterion = {"id": domain_id, "type": "PRIMARY"}
|
||||||
domain = central_api.find_domain(context, criterion=criterion)
|
domain = central_api.find_zone(context, criterion=criterion)
|
||||||
|
|
||||||
# Prepare a dict of fields for validation
|
# Prepare a dict of fields for validation
|
||||||
domain_data = domain_schema.filter(domain)
|
domain_data = domain_schema.filter(domain)
|
||||||
@ -117,7 +117,7 @@ def update_domain(domain_id):
|
|||||||
|
|
||||||
# Update and persist the resource
|
# Update and persist the resource
|
||||||
domain.update(values)
|
domain.update(values)
|
||||||
domain = central_api.update_domain(context, domain)
|
domain = central_api.update_zone(context, domain)
|
||||||
|
|
||||||
return flask.jsonify(domain_schema.filter(domain))
|
return flask.jsonify(domain_schema.filter(domain))
|
||||||
|
|
||||||
@ -130,9 +130,9 @@ def delete_domain(domain_id):
|
|||||||
|
|
||||||
# TODO(ekarlso): Fix this to something better.
|
# TODO(ekarlso): Fix this to something better.
|
||||||
criterion = {"id": domain_id, "type": "PRIMARY"}
|
criterion = {"id": domain_id, "type": "PRIMARY"}
|
||||||
central_api.find_domain(context, criterion=criterion)
|
central_api.find_zone(context, criterion=criterion)
|
||||||
|
|
||||||
central_api.delete_domain(context, domain_id)
|
central_api.delete_zone(context, domain_id)
|
||||||
|
|
||||||
return flask.Response(status=200)
|
return flask.Response(status=200)
|
||||||
|
|
||||||
@ -145,9 +145,9 @@ def get_domain_servers(domain_id):
|
|||||||
|
|
||||||
# TODO(ekarlso): Fix this to something better.
|
# TODO(ekarlso): Fix this to something better.
|
||||||
criterion = {"id": domain_id, "type": "PRIMARY"}
|
criterion = {"id": domain_id, "type": "PRIMARY"}
|
||||||
central_api.find_domain(context, criterion=criterion)
|
central_api.find_zone(context, criterion=criterion)
|
||||||
|
|
||||||
nameservers = central_api.get_domain_servers(context, domain_id)
|
nameservers = central_api.get_zone_ns_records(context, domain_id)
|
||||||
|
|
||||||
servers = objects.ServerList()
|
servers = objects.ServerList()
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ def reports_counts():
|
|||||||
context = flask.request.environ.get('context')
|
context = flask.request.environ.get('context')
|
||||||
|
|
||||||
tenants = central_api.count_tenants(context)
|
tenants = central_api.count_tenants(context)
|
||||||
domains = central_api.count_domains(context)
|
domains = central_api.count_zones(context)
|
||||||
records = central_api.count_records(context)
|
records = central_api.count_records(context)
|
||||||
|
|
||||||
return flask.jsonify(tenants=tenants, domains=domains, records=records)
|
return flask.jsonify(tenants=tenants, domains=domains, records=records)
|
||||||
@ -66,7 +66,7 @@ def reports_counts_tenants():
|
|||||||
def reports_counts_domains():
|
def reports_counts_domains():
|
||||||
context = flask.request.environ.get('context')
|
context = flask.request.environ.get('context')
|
||||||
|
|
||||||
count = central_api.count_domains(context)
|
count = central_api.count_zones(context)
|
||||||
|
|
||||||
return flask.jsonify(domains=count)
|
return flask.jsonify(domains=count)
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ blueprint = flask.Blueprint('sync', __name__)
|
|||||||
def sync_domains():
|
def sync_domains():
|
||||||
context = flask.request.environ.get('context')
|
context = flask.request.environ.get('context')
|
||||||
|
|
||||||
central_api.sync_domains(context)
|
central_api.sync_zones(context)
|
||||||
|
|
||||||
return flask.Response(status=200)
|
return flask.Response(status=200)
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ def sync_domains():
|
|||||||
def sync_domain(domain_id):
|
def sync_domain(domain_id):
|
||||||
context = flask.request.environ.get('context')
|
context = flask.request.environ.get('context')
|
||||||
|
|
||||||
central_api.sync_domain(context, domain_id)
|
central_api.sync_zone(context, domain_id)
|
||||||
|
|
||||||
return flask.Response(status=200)
|
return flask.Response(status=200)
|
||||||
|
|
||||||
|
@ -26,6 +26,6 @@ blueprint = flask.Blueprint('touch', __name__)
|
|||||||
def touch_domain(domain_id):
|
def touch_domain(domain_id):
|
||||||
context = flask.request.environ.get('context')
|
context = flask.request.environ.get('context')
|
||||||
|
|
||||||
central_api.touch_domain(context, domain_id)
|
central_api.touch_zone(context, domain_id)
|
||||||
|
|
||||||
return flask.Response(status=200)
|
return flask.Response(status=200)
|
||||||
|
@ -41,8 +41,8 @@ def get_limits():
|
|||||||
return flask.jsonify(limits_schema.filter({
|
return flask.jsonify(limits_schema.filter({
|
||||||
"limits": {
|
"limits": {
|
||||||
"absolute": {
|
"absolute": {
|
||||||
"maxDomains": absolute_limits['domains'],
|
"maxDomains": absolute_limits['zones'],
|
||||||
"maxDomainRecords": absolute_limits['domain_records']
|
"maxDomainRecords": absolute_limits['zone_records']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -33,7 +33,7 @@ def _find_recordset(context, domain_id, name, type):
|
|||||||
central_api = central_rpcapi.CentralAPI.get_instance()
|
central_api = central_rpcapi.CentralAPI.get_instance()
|
||||||
|
|
||||||
return central_api.find_recordset(context, {
|
return central_api.find_recordset(context, {
|
||||||
'domain_id': domain_id,
|
'zone_id': domain_id,
|
||||||
'name': name,
|
'name': name,
|
||||||
'type': type,
|
'type': type,
|
||||||
})
|
})
|
||||||
@ -43,7 +43,7 @@ def _find_or_create_recordset(context, domain_id, name, type, ttl):
|
|||||||
central_api = central_rpcapi.CentralAPI.get_instance()
|
central_api = central_rpcapi.CentralAPI.get_instance()
|
||||||
|
|
||||||
criterion = {"id": domain_id, "type": "PRIMARY"}
|
criterion = {"id": domain_id, "type": "PRIMARY"}
|
||||||
central_api.find_domain(context, criterion=criterion)
|
central_api.find_zone(context, criterion=criterion)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Attempt to create an empty recordset
|
# Attempt to create an empty recordset
|
||||||
@ -83,6 +83,10 @@ def _format_record_v1(record, recordset):
|
|||||||
record['priority'], record['data'] = utils.extract_priority_from_data(
|
record['priority'], record['data'] = utils.extract_priority_from_data(
|
||||||
recordset.type, record)
|
recordset.type, record)
|
||||||
|
|
||||||
|
record['domain_id'] = record['zone_id']
|
||||||
|
|
||||||
|
del record['zone_id']
|
||||||
|
|
||||||
record.update({
|
record.update({
|
||||||
'name': recordset['name'],
|
'name': recordset['name'],
|
||||||
'type': recordset['type'],
|
'type': recordset['type'],
|
||||||
@ -122,8 +126,8 @@ def create_record(domain_id):
|
|||||||
|
|
||||||
central_api = central_rpcapi.CentralAPI.get_instance()
|
central_api = central_rpcapi.CentralAPI.get_instance()
|
||||||
record = central_api.create_record(context, domain_id,
|
record = central_api.create_record(context, domain_id,
|
||||||
recordset['id'],
|
recordset['id'],
|
||||||
record)
|
record)
|
||||||
|
|
||||||
record = _format_record_v1(record, recordset)
|
record = _format_record_v1(record, recordset)
|
||||||
|
|
||||||
@ -143,9 +147,9 @@ def get_records(domain_id):
|
|||||||
|
|
||||||
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
||||||
# return an empty records array instead of a domain not found
|
# return an empty records array instead of a domain not found
|
||||||
central_api.get_domain(context, domain_id)
|
central_api.get_zone(context, domain_id)
|
||||||
|
|
||||||
recordsets = central_api.find_recordsets(context, {'domain_id': domain_id})
|
recordsets = central_api.find_recordsets(context, {'zone_id': domain_id})
|
||||||
|
|
||||||
records = []
|
records = []
|
||||||
|
|
||||||
@ -164,9 +168,9 @@ def get_record(domain_id, record_id):
|
|||||||
|
|
||||||
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
||||||
# return an record not found instead of a domain not found
|
# return an record not found instead of a domain not found
|
||||||
central_api.get_domain(context, domain_id)
|
central_api.get_zone(context, domain_id)
|
||||||
|
|
||||||
criterion = {'domain_id': domain_id, 'id': record_id}
|
criterion = {'zone_id': domain_id, 'id': record_id}
|
||||||
record = central_api.find_record(context, criterion)
|
record = central_api.find_record(context, criterion)
|
||||||
|
|
||||||
recordset = central_api.get_recordset(
|
recordset = central_api.get_recordset(
|
||||||
@ -188,12 +192,12 @@ def update_record(domain_id, record_id):
|
|||||||
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
||||||
# return a record not found instead of a domain not found
|
# return a record not found instead of a domain not found
|
||||||
criterion = {"id": domain_id, "type": "PRIMARY"}
|
criterion = {"id": domain_id, "type": "PRIMARY"}
|
||||||
central_api.find_domain(context, criterion)
|
central_api.find_zone(context, criterion)
|
||||||
|
|
||||||
# Fetch the existing resource
|
# Fetch the existing resource
|
||||||
# NOTE(kiall): We use "find_record" rather than "get_record" as we do not
|
# NOTE(kiall): We use "find_record" rather than "get_record" as we do not
|
||||||
# have the recordset_id.
|
# have the recordset_id.
|
||||||
criterion = {'domain_id': domain_id, 'id': record_id}
|
criterion = {'zone_id': domain_id, 'id': record_id}
|
||||||
record = central_api.find_record(context, criterion)
|
record = central_api.find_record(context, criterion)
|
||||||
|
|
||||||
# TODO(graham): Move this further down the stack
|
# TODO(graham): Move this further down the stack
|
||||||
@ -247,10 +251,10 @@ def delete_record(domain_id, record_id):
|
|||||||
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
||||||
# return a record not found instead of a domain not found
|
# return a record not found instead of a domain not found
|
||||||
criterion = {"id": domain_id, "type": "PRIMARY"}
|
criterion = {"id": domain_id, "type": "PRIMARY"}
|
||||||
central_api.find_domain(context, criterion=criterion)
|
central_api.find_zone(context, criterion=criterion)
|
||||||
|
|
||||||
# Find the record
|
# Find the record
|
||||||
criterion = {'domain_id': domain_id, 'id': record_id}
|
criterion = {'zone_id': domain_id, 'id': record_id}
|
||||||
record = central_api.find_record(context, criterion)
|
record = central_api.find_record(context, criterion)
|
||||||
|
|
||||||
central_api.delete_record(
|
central_api.delete_record(
|
||||||
|
@ -35,15 +35,15 @@ class LimitsController(rest.RestController):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
# Resource Creation Limits
|
# Resource Creation Limits
|
||||||
"max_zones": absolute_limits['domains'],
|
"max_zones": absolute_limits['zones'],
|
||||||
"max_zone_recordsets": absolute_limits['domain_recordsets'],
|
"max_zone_recordsets": absolute_limits['zone_recordsets'],
|
||||||
"max_zone_records": absolute_limits['domain_records'],
|
"max_zone_records": absolute_limits['zone_records'],
|
||||||
"max_recordset_records": absolute_limits['recordset_records'],
|
"max_recordset_records": absolute_limits['recordset_records'],
|
||||||
|
|
||||||
# Resource Field Value Limits
|
# Resource Field Value Limits
|
||||||
"min_ttl": CONF['service:central'].min_ttl,
|
"min_ttl": CONF['service:central'].min_ttl,
|
||||||
"max_zone_name_length":
|
"max_zone_name_length":
|
||||||
CONF['service:central'].max_domain_name_len,
|
CONF['service:central'].max_zone_name_len,
|
||||||
"max_recordset_name_length":
|
"max_recordset_name_length":
|
||||||
CONF['service:central'].max_recordset_name_len,
|
CONF['service:central'].max_recordset_name_len,
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class RecordSetsController(rest.RestController):
|
class RecordSetsController(rest.RestController):
|
||||||
SORT_KEYS = ['created_at', 'id', 'updated_at', 'domain_id', 'tenant_id',
|
SORT_KEYS = ['created_at', 'id', 'updated_at', 'zone_id', 'tenant_id',
|
||||||
'name', 'type', 'ttl', 'records']
|
'name', 'type', 'ttl', 'records']
|
||||||
|
|
||||||
@pecan.expose(template='json:', content_type='application/json')
|
@pecan.expose(template='json:', content_type='application/json')
|
||||||
@ -50,9 +50,9 @@ class RecordSetsController(rest.RestController):
|
|||||||
request = pecan.request
|
request = pecan.request
|
||||||
context = request.environ['context']
|
context = request.environ['context']
|
||||||
|
|
||||||
# NOTE: We need to ensure the domain actually exists, otherwise we may
|
# NOTE: We need to ensure the zone actually exists, otherwise we may
|
||||||
# return deleted recordsets instead of a domain not found
|
# return deleted recordsets instead of a zone not found
|
||||||
self.central_api.get_domain(context, zone_id)
|
self.central_api.get_zone(context, zone_id)
|
||||||
|
|
||||||
# Extract the pagination params
|
# Extract the pagination params
|
||||||
marker, limit, sort_key, sort_dir = utils.get_paging_params(
|
marker, limit, sort_key, sort_dir = utils.get_paging_params(
|
||||||
@ -64,7 +64,7 @@ class RecordSetsController(rest.RestController):
|
|||||||
criterion = self._apply_filter_params(
|
criterion = self._apply_filter_params(
|
||||||
params, accepted_filters, {})
|
params, accepted_filters, {})
|
||||||
|
|
||||||
criterion['domain_id'] = zone_id
|
criterion['zone_id'] = zone_id
|
||||||
|
|
||||||
# Data must be filtered separately, through the Records table
|
# Data must be filtered separately, through the Records table
|
||||||
data = criterion.pop('data', None)
|
data = criterion.pop('data', None)
|
||||||
@ -77,7 +77,7 @@ class RecordSetsController(rest.RestController):
|
|||||||
# 'data' filter param: only return recordsets with matching data
|
# 'data' filter param: only return recordsets with matching data
|
||||||
if data:
|
if data:
|
||||||
records = self.central_api.find_records(
|
records = self.central_api.find_records(
|
||||||
context, criterion={'data': data, 'domain_id': zone_id})
|
context, criterion={'data': data, 'zone_id': zone_id})
|
||||||
recordset_with_data_ids = set(record.recordset_id
|
recordset_with_data_ids = set(record.recordset_id
|
||||||
for record in records)
|
for record in records)
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ class RecordSetsController(rest.RestController):
|
|||||||
|
|
||||||
# NS recordsets at the zone root cannot be manually updated
|
# NS recordsets at the zone root cannot be manually updated
|
||||||
if recordset['type'] == 'NS':
|
if recordset['type'] == 'NS':
|
||||||
zone = self.central_api.get_domain(context, zone_id)
|
zone = self.central_api.get_zone(context, zone_id)
|
||||||
if recordset['name'] == zone['name']:
|
if recordset['name'] == zone['name']:
|
||||||
raise exceptions.BadRequest(
|
raise exceptions.BadRequest(
|
||||||
'Updating a root zone NS record is not allowed')
|
'Updating a root zone NS record is not allowed')
|
||||||
|
@ -49,7 +49,7 @@ class ZonesController(rest.RestController):
|
|||||||
|
|
||||||
return DesignateAdapter.render(
|
return DesignateAdapter.render(
|
||||||
'API_v2',
|
'API_v2',
|
||||||
self.central_api.get_domain(context, zone_id),
|
self.central_api.get_zone(context, zone_id),
|
||||||
request=request)
|
request=request)
|
||||||
|
|
||||||
@pecan.expose(template='json:', content_type='application/json')
|
@pecan.expose(template='json:', content_type='application/json')
|
||||||
@ -70,7 +70,7 @@ class ZonesController(rest.RestController):
|
|||||||
|
|
||||||
return DesignateAdapter.render(
|
return DesignateAdapter.render(
|
||||||
'API_v2',
|
'API_v2',
|
||||||
self.central_api.find_domains(
|
self.central_api.find_zones(
|
||||||
context, criterion, marker, limit, sort_key, sort_dir),
|
context, criterion, marker, limit, sort_key, sort_dir),
|
||||||
request=request)
|
request=request)
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ class ZonesController(rest.RestController):
|
|||||||
if 'type' not in zone:
|
if 'type' not in zone:
|
||||||
zone['type'] = 'PRIMARY'
|
zone['type'] = 'PRIMARY'
|
||||||
|
|
||||||
zone = DesignateAdapter.parse('API_v2', zone, objects.Domain())
|
zone = DesignateAdapter.parse('API_v2', zone, objects.Zone())
|
||||||
zone.validate()
|
zone.validate()
|
||||||
|
|
||||||
if zone.type == 'SECONDARY':
|
if zone.type == 'SECONDARY':
|
||||||
@ -98,7 +98,7 @@ class ZonesController(rest.RestController):
|
|||||||
zone['email'] = mgmt_email
|
zone['email'] = mgmt_email
|
||||||
|
|
||||||
# Create the zone
|
# Create the zone
|
||||||
zone = self.central_api.create_domain(context, zone)
|
zone = self.central_api.create_zone(context, zone)
|
||||||
|
|
||||||
# Prepare the response headers
|
# Prepare the response headers
|
||||||
# If the zone has been created asynchronously
|
# If the zone has been created asynchronously
|
||||||
@ -129,7 +129,7 @@ class ZonesController(rest.RestController):
|
|||||||
# TODO(kiall): Validate we have a sane UUID for zone_id
|
# TODO(kiall): Validate we have a sane UUID for zone_id
|
||||||
|
|
||||||
# Fetch the existing zone
|
# Fetch the existing zone
|
||||||
zone = self.central_api.get_domain(context, zone_id)
|
zone = self.central_api.get_zone(context, zone_id)
|
||||||
|
|
||||||
# Don't allow updates to zones that are being deleted
|
# Don't allow updates to zones that are being deleted
|
||||||
if zone.action == "DELETE":
|
if zone.action == "DELETE":
|
||||||
@ -166,7 +166,7 @@ class ZonesController(rest.RestController):
|
|||||||
raise exceptions.InvalidObject(msg)
|
raise exceptions.InvalidObject(msg)
|
||||||
|
|
||||||
increment_serial = zone.type == 'PRIMARY'
|
increment_serial = zone.type == 'PRIMARY'
|
||||||
zone = self.central_api.update_domain(
|
zone = self.central_api.update_zone(
|
||||||
context, zone, increment_serial=increment_serial)
|
context, zone, increment_serial=increment_serial)
|
||||||
|
|
||||||
if zone.status == 'PENDING':
|
if zone.status == 'PENDING':
|
||||||
@ -184,7 +184,7 @@ class ZonesController(rest.RestController):
|
|||||||
response = pecan.response
|
response = pecan.response
|
||||||
context = request.environ['context']
|
context = request.environ['context']
|
||||||
|
|
||||||
zone = self.central_api.delete_domain(context, zone_id)
|
zone = self.central_api.delete_zone(context, zone_id)
|
||||||
response.status_int = 202
|
response.status_int = 202
|
||||||
|
|
||||||
return DesignateAdapter.render('API_v2', zone, request=request)
|
return DesignateAdapter.render('API_v2', zone, request=request)
|
||||||
|
@ -37,5 +37,5 @@ class NameServersController(rest.RestController):
|
|||||||
return {
|
return {
|
||||||
"nameservers": DesignateAdapter.render(
|
"nameservers": DesignateAdapter.render(
|
||||||
'API_v2',
|
'API_v2',
|
||||||
self.central_api.get_domain_servers(context, zone_id),
|
self.central_api.get_zone_ns_records(context, zone_id),
|
||||||
request=request)}
|
request=request)}
|
||||||
|
@ -30,7 +30,7 @@ class AbandonController(rest.RestController):
|
|||||||
context.abandon = 'True'
|
context.abandon = 'True'
|
||||||
|
|
||||||
# abandon the zone
|
# abandon the zone
|
||||||
zone = self.central_api.delete_domain(context, zone_id)
|
zone = self.central_api.delete_zone(context, zone_id)
|
||||||
if zone.deleted_at:
|
if zone.deleted_at:
|
||||||
response.status_int = 204
|
response.status_int = 204
|
||||||
else:
|
else:
|
||||||
|
@ -40,7 +40,7 @@ class ZoneExportController(rest.RestController):
|
|||||||
|
|
||||||
if export.location and export.location.startswith('designate://'):
|
if export.location and export.location.startswith('designate://'):
|
||||||
return self.zone_manager_api.\
|
return self.zone_manager_api.\
|
||||||
render_zone(context, export['domain_id'])
|
render_zone(context, export['zone_id'])
|
||||||
else:
|
else:
|
||||||
msg = 'Zone can not be exported synchronously'
|
msg = 'Zone can not be exported synchronously'
|
||||||
raise exceptions.BadRequest(msg)
|
raise exceptions.BadRequest(msg)
|
||||||
|
@ -29,7 +29,7 @@ class XfrController(rest.RestController):
|
|||||||
response = pecan.response
|
response = pecan.response
|
||||||
context = request.environ['context']
|
context = request.environ['context']
|
||||||
|
|
||||||
self.central_api.xfr_domain(context, zone_id)
|
self.central_api.xfr_zone(context, zone_id)
|
||||||
response.status_int = 202
|
response.status_int = 202
|
||||||
|
|
||||||
# NOTE: This is a hack and a half.. But Pecan needs it.
|
# NOTE: This is a hack and a half.. But Pecan needs it.
|
||||||
|
@ -67,10 +67,10 @@ class AgentPoolBackend(base.Backend):
|
|||||||
def mdns_api(self):
|
def mdns_api(self):
|
||||||
return mdns_api.MdnsAPI.get_instance()
|
return mdns_api.MdnsAPI.get_instance()
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.debug('Create Domain')
|
LOG.debug('Create Zone')
|
||||||
response, retry = self._make_and_send_dns_message(
|
response, retry = self._make_and_send_dns_message(
|
||||||
domain.name,
|
zone.name,
|
||||||
self.timeout,
|
self.timeout,
|
||||||
CC,
|
CC,
|
||||||
CREATE,
|
CREATE,
|
||||||
@ -81,12 +81,12 @@ class AgentPoolBackend(base.Backend):
|
|||||||
if response is None:
|
if response is None:
|
||||||
raise exceptions.Backend()
|
raise exceptions.Backend()
|
||||||
|
|
||||||
def update_domain(self, context, domain):
|
def update_zone(self, context, zone):
|
||||||
LOG.debug('Update Domain')
|
LOG.debug('Update Zone')
|
||||||
|
|
||||||
self.mdns_api.notify_zone_changed(
|
self.mdns_api.notify_zone_changed(
|
||||||
context,
|
context,
|
||||||
domain,
|
zone,
|
||||||
self.host,
|
self.host,
|
||||||
self.port,
|
self.port,
|
||||||
self.timeout,
|
self.timeout,
|
||||||
@ -95,10 +95,10 @@ class AgentPoolBackend(base.Backend):
|
|||||||
self.delay
|
self.delay
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
LOG.debug('Delete Domain')
|
LOG.debug('Delete Zone')
|
||||||
response, retry = self._make_and_send_dns_message(
|
response, retry = self._make_and_send_dns_message(
|
||||||
domain.name,
|
zone.name,
|
||||||
self.timeout,
|
self.timeout,
|
||||||
CC,
|
CC,
|
||||||
DELETE,
|
DELETE,
|
||||||
@ -109,10 +109,10 @@ class AgentPoolBackend(base.Backend):
|
|||||||
if response is None:
|
if response is None:
|
||||||
raise exceptions.Backend()
|
raise exceptions.Backend()
|
||||||
|
|
||||||
def _make_and_send_dns_message(self, domain_name, timeout, opcode,
|
def _make_and_send_dns_message(self, zone_name, timeout, opcode,
|
||||||
rdatatype, rdclass, dest_ip,
|
rdatatype, rdclass, dest_ip,
|
||||||
dest_port):
|
dest_port):
|
||||||
dns_message = self._make_dns_message(domain_name, opcode, rdatatype,
|
dns_message = self._make_dns_message(zone_name, opcode, rdatatype,
|
||||||
rdclass)
|
rdclass)
|
||||||
|
|
||||||
retry = 0
|
retry = 0
|
||||||
@ -121,7 +121,7 @@ class AgentPoolBackend(base.Backend):
|
|||||||
LOG.info(_LI("Sending '%(msg)s' for '%(zone)s' to '%(server)s:"
|
LOG.info(_LI("Sending '%(msg)s' for '%(zone)s' to '%(server)s:"
|
||||||
"%(port)d'.") %
|
"%(port)d'.") %
|
||||||
{'msg': str(opcode),
|
{'msg': str(opcode),
|
||||||
'zone': domain_name, 'server': dest_ip,
|
'zone': zone_name, 'server': dest_ip,
|
||||||
'port': dest_port})
|
'port': dest_port})
|
||||||
response = self._send_dns_message(
|
response = self._send_dns_message(
|
||||||
dns_message, dest_ip, dest_port, timeout)
|
dns_message, dest_ip, dest_port, timeout)
|
||||||
@ -131,7 +131,7 @@ class AgentPoolBackend(base.Backend):
|
|||||||
"'%(zone)s' to '%(server)s:%(port)d'. Timeout="
|
"'%(zone)s' to '%(server)s:%(port)d'. Timeout="
|
||||||
"'%(timeout)d' seconds. Retry='%(retry)d'") %
|
"'%(timeout)d' seconds. Retry='%(retry)d'") %
|
||||||
{'msg': str(opcode),
|
{'msg': str(opcode),
|
||||||
'zone': domain_name, 'server': dest_ip,
|
'zone': zone_name, 'server': dest_ip,
|
||||||
'port': dest_port, 'timeout': timeout,
|
'port': dest_port, 'timeout': timeout,
|
||||||
'retry': retry})
|
'retry': retry})
|
||||||
response = None
|
response = None
|
||||||
@ -140,7 +140,7 @@ class AgentPoolBackend(base.Backend):
|
|||||||
"for '%(zone)s' to '%(server)s:%(port)d'. Timeout"
|
"for '%(zone)s' to '%(server)s:%(port)d'. Timeout"
|
||||||
"='%(timeout)d' seconds. Retry='%(retry)d'") %
|
"='%(timeout)d' seconds. Retry='%(retry)d'") %
|
||||||
{'msg': str(opcode),
|
{'msg': str(opcode),
|
||||||
'zone': domain_name, 'server': dest_ip,
|
'zone': zone_name, 'server': dest_ip,
|
||||||
'port': dest_port, 'timeout': timeout,
|
'port': dest_port, 'timeout': timeout,
|
||||||
'retry': retry})
|
'retry': retry})
|
||||||
response = None
|
response = None
|
||||||
@ -153,7 +153,7 @@ class AgentPoolBackend(base.Backend):
|
|||||||
"send '%(msg)s' for '%(zone)s' to '%(server)s:"
|
"send '%(msg)s' for '%(zone)s' to '%(server)s:"
|
||||||
"%(port)d'. Response message: %(resp)s") %
|
"%(port)d'. Response message: %(resp)s") %
|
||||||
{'msg': str(opcode),
|
{'msg': str(opcode),
|
||||||
'zone': domain_name, 'server': dest_ip,
|
'zone': zone_name, 'server': dest_ip,
|
||||||
'port': dest_port, 'resp': str(response)})
|
'port': dest_port, 'resp': str(response)})
|
||||||
response = None
|
response = None
|
||||||
return (response, retry)
|
return (response, retry)
|
||||||
|
@ -39,19 +39,19 @@ class AgentBackend(DriverPlugin):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def find_domain_serial(self, domain_name):
|
def find_zone_serial(self, zone_name):
|
||||||
"""Find a DNS Domain"""
|
"""Find a DNS Zone"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def create_domain(self, domain):
|
def create_zone(self, zone):
|
||||||
"""Create a DNS domain"""
|
"""Create a DNS zone"""
|
||||||
"""Domain is a DNSPython Zone object"""
|
"""Zone is a DNSPython Zone object"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def update_domain(self, domain):
|
def update_zone(self, zone):
|
||||||
"""Update a DNS domain"""
|
"""Update a DNS zone"""
|
||||||
"""Domain is a DNSPython Zone object"""
|
"""Zone is a DNSPython Zone object"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def delete_domain(self, domain_name):
|
def delete_zone(self, zone_name):
|
||||||
"""Delete a DNS domain"""
|
"""Delete a DNS zone"""
|
||||||
|
@ -50,7 +50,7 @@ class Bind9Backend(base.AgentBackend):
|
|||||||
cfg.StrOpt('zone-file-path', default='$state_path/zones',
|
cfg.StrOpt('zone-file-path', default='$state_path/zones',
|
||||||
help='Path where zone files are stored'),
|
help='Path where zone files are stored'),
|
||||||
cfg.StrOpt('query-destination', default='127.0.0.1',
|
cfg.StrOpt('query-destination', default='127.0.0.1',
|
||||||
help='Host to query when finding domains')
|
help='Host to query when finding zones')
|
||||||
]
|
]
|
||||||
|
|
||||||
return [(group, opts)]
|
return [(group, opts)]
|
||||||
@ -58,30 +58,30 @@ class Bind9Backend(base.AgentBackend):
|
|||||||
def start(self):
|
def start(self):
|
||||||
LOG.info(_LI("Started bind9 backend"))
|
LOG.info(_LI("Started bind9 backend"))
|
||||||
|
|
||||||
def find_domain_serial(self, domain_name):
|
def find_zone_serial(self, zone_name):
|
||||||
LOG.debug("Finding %s" % domain_name)
|
LOG.debug("Finding %s" % zone_name)
|
||||||
resolver = dns.resolver.Resolver()
|
resolver = dns.resolver.Resolver()
|
||||||
resolver.nameservers = [cfg.CONF[CFG_GROUP].query_destination]
|
resolver.nameservers = [cfg.CONF[CFG_GROUP].query_destination]
|
||||||
try:
|
try:
|
||||||
rdata = resolver.query(domain_name, 'SOA')[0]
|
rdata = resolver.query(zone_name, 'SOA')[0]
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
return rdata.serial
|
return rdata.serial
|
||||||
|
|
||||||
def create_domain(self, domain):
|
def create_zone(self, zone):
|
||||||
LOG.debug("Creating %s" % domain.origin.to_text())
|
LOG.debug("Creating %s" % zone.origin.to_text())
|
||||||
self._sync_domain(domain, new_domain_flag=True)
|
self._sync_zone(zone, new_zone_flag=True)
|
||||||
|
|
||||||
def update_domain(self, domain):
|
def update_zone(self, zone):
|
||||||
LOG.debug("Updating %s" % domain.origin.to_text())
|
LOG.debug("Updating %s" % zone.origin.to_text())
|
||||||
self._sync_domain(domain)
|
self._sync_zone(zone)
|
||||||
|
|
||||||
def delete_domain(self, domain_name):
|
def delete_zone(self, zone_name):
|
||||||
LOG.debug('Delete Domain: %s' % domain_name)
|
LOG.debug('Delete Zone: %s' % zone_name)
|
||||||
|
|
||||||
rndc_op = 'delzone'
|
rndc_op = 'delzone'
|
||||||
# RNDC doesn't like the trailing dot on the domain name
|
# RNDC doesn't like the trailing dot on the zone name
|
||||||
rndc_call = self._rndc_base() + [rndc_op, domain_name.rstrip('.')]
|
rndc_call = self._rndc_base() + [rndc_op, zone_name.rstrip('.')]
|
||||||
|
|
||||||
utils.execute(*rndc_call)
|
utils.execute(*rndc_call)
|
||||||
|
|
||||||
@ -102,39 +102,39 @@ class Bind9Backend(base.AgentBackend):
|
|||||||
|
|
||||||
return rndc_call
|
return rndc_call
|
||||||
|
|
||||||
def _sync_domain(self, domain, new_domain_flag=False):
|
def _sync_zone(self, zone, new_zone_flag=False):
|
||||||
"""Sync a single domain's zone file and reload bind config"""
|
"""Sync a single zone's zone file and reload bind config"""
|
||||||
|
|
||||||
# NOTE: Different versions of BIND9 behave differently with a trailing
|
# NOTE: Different versions of BIND9 behave differently with a trailing
|
||||||
# dot, so we're just going to take it off.
|
# dot, so we're just going to take it off.
|
||||||
domain_name = domain.origin.to_text().rstrip('.')
|
zone_name = zone.origin.to_text().rstrip('.')
|
||||||
|
|
||||||
# NOTE: Only one thread should be working with the Zonefile at a given
|
# NOTE: Only one thread should be working with the Zonefile at a given
|
||||||
# time. The sleep(1) below introduces a not insignificant risk
|
# time. The sleep(1) below introduces a not insignificant risk
|
||||||
# of more than 1 thread working with a zonefile at a given time.
|
# of more than 1 thread working with a zonefile at a given time.
|
||||||
with lockutils.lock('bind9-%s' % domain_name):
|
with lockutils.lock('bind9-%s' % zone_name):
|
||||||
LOG.debug('Synchronising Domain: %s' % domain_name)
|
LOG.debug('Synchronising Zone: %s' % zone_name)
|
||||||
|
|
||||||
zone_path = cfg.CONF[CFG_GROUP].zone_file_path
|
zone_path = cfg.CONF[CFG_GROUP].zone_file_path
|
||||||
|
|
||||||
output_path = os.path.join(zone_path,
|
output_path = os.path.join(zone_path,
|
||||||
'%s.zone' % domain_name)
|
'%s.zone' % zone_name)
|
||||||
|
|
||||||
domain.to_file(output_path, relativize=False)
|
zone.to_file(output_path, relativize=False)
|
||||||
|
|
||||||
rndc_call = self._rndc_base()
|
rndc_call = self._rndc_base()
|
||||||
|
|
||||||
if new_domain_flag:
|
if new_zone_flag:
|
||||||
rndc_op = [
|
rndc_op = [
|
||||||
'addzone',
|
'addzone',
|
||||||
'%s { type master; file "%s"; };' % (domain_name,
|
'%s { type master; file "%s"; };' % (zone_name,
|
||||||
output_path),
|
output_path),
|
||||||
]
|
]
|
||||||
rndc_call.extend(rndc_op)
|
rndc_call.extend(rndc_op)
|
||||||
else:
|
else:
|
||||||
rndc_op = 'reload'
|
rndc_op = 'reload'
|
||||||
rndc_call.extend([rndc_op])
|
rndc_call.extend([rndc_op])
|
||||||
rndc_call.extend([domain_name])
|
rndc_call.extend([zone_name])
|
||||||
|
|
||||||
LOG.debug('Calling RNDC with: %s' % " ".join(rndc_call))
|
LOG.debug('Calling RNDC with: %s' % " ".join(rndc_call))
|
||||||
self._execute_rndc(rndc_call)
|
self._execute_rndc(rndc_call)
|
||||||
|
@ -118,14 +118,14 @@ class DenominatorBackend(base.AgentBackend):
|
|||||||
def stop(self):
|
def stop(self):
|
||||||
LOG.info(_LI("Stopped Denominator backend"))
|
LOG.info(_LI("Stopped Denominator backend"))
|
||||||
|
|
||||||
def find_domain_serial(self, domain_name):
|
def find_zone_serial(self, zone_name):
|
||||||
LOG.debug("Finding %s" % domain_name)
|
LOG.debug("Finding %s" % zone_name)
|
||||||
|
|
||||||
domain_name = domain_name.rstrip('.')
|
zone_name = zone_name.rstrip('.')
|
||||||
output = self.denominator.get_record(
|
output = self.denominator.get_record(
|
||||||
zone=domain_name,
|
zone=zone_name,
|
||||||
type='SOA',
|
type='SOA',
|
||||||
name=domain_name)
|
name=zone_name)
|
||||||
try:
|
try:
|
||||||
text = ' '.join(output.split()[3:])
|
text = ' '.join(output.split()[3:])
|
||||||
rdata = dns.rdata.from_text(dns.rdataclass.IN,
|
rdata = dns.rdata.from_text(dns.rdataclass.IN,
|
||||||
@ -135,109 +135,109 @@ class DenominatorBackend(base.AgentBackend):
|
|||||||
return None
|
return None
|
||||||
return rdata.serial
|
return rdata.serial
|
||||||
|
|
||||||
def create_domain(self, domain):
|
def create_zone(self, zone):
|
||||||
LOG.debug("Creating %s" % domain.origin.to_text())
|
LOG.debug("Creating %s" % zone.origin.to_text())
|
||||||
domain_name = domain.origin.to_text(omit_final_dot=True)
|
zone_name = zone.origin.to_text(omit_final_dot=True)
|
||||||
|
|
||||||
# Use SOA TTL as zone default TTL
|
# Use SOA TTL as zone default TTL
|
||||||
soa_record = domain.find_rrset(domain.origin, dns.rdatatype.SOA)
|
soa_record = zone.find_rrset(zone.origin, dns.rdatatype.SOA)
|
||||||
rname = soa_record.items[0].rname.derelativize(origin=domain.origin)
|
rname = soa_record.items[0].rname.derelativize(origin=zone.origin)
|
||||||
|
|
||||||
# Lock domain to prevent concurrent changes.
|
# Lock zone to prevent concurrent changes.
|
||||||
with self._sync_domain(domain.origin):
|
with self._sync_zone(zone.origin):
|
||||||
# NOTE: If zone already exists, denominator will update it with
|
# NOTE: If zone already exists, denominator will update it with
|
||||||
# new values, in other a duplicate zone will be created if
|
# new values, in other a duplicate zone will be created if
|
||||||
# provider supports such functionality.
|
# provider supports such functionality.
|
||||||
self.denominator.create_zone(
|
self.denominator.create_zone(
|
||||||
name=domain_name,
|
name=zone_name,
|
||||||
ttl=soa_record.ttl,
|
ttl=soa_record.ttl,
|
||||||
email=rname)
|
email=rname)
|
||||||
|
|
||||||
# Add records one by one.
|
# Add records one by one.
|
||||||
for name, ttl, rtype, data in self._iterate_records(domain):
|
for name, ttl, rtype, data in self._iterate_records(zone):
|
||||||
# Some providers do not support creationg of SOA record.
|
# Some providers do not support creationg of SOA record.
|
||||||
rdatatype = dns.rdatatype.from_text(rtype)
|
rdatatype = dns.rdatatype.from_text(rtype)
|
||||||
if rdatatype == dns.rdatatype.SOA:
|
if rdatatype == dns.rdatatype.SOA:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.denominator.create_record(
|
self.denominator.create_record(
|
||||||
zone=domain_name,
|
zone=zone_name,
|
||||||
name=name,
|
name=name,
|
||||||
type=rtype,
|
type=rtype,
|
||||||
ttl=ttl,
|
ttl=ttl,
|
||||||
data=data)
|
data=data)
|
||||||
|
|
||||||
def update_domain(self, domain):
|
def update_zone(self, zone):
|
||||||
LOG.debug("Updating %s" % domain.origin)
|
LOG.debug("Updating %s" % zone.origin)
|
||||||
domain_name = domain.origin.to_text(omit_final_dot=True)
|
zone_name = zone.origin.to_text(omit_final_dot=True)
|
||||||
|
|
||||||
soa_record = domain.find_rrset(domain.origin, dns.rdatatype.SOA)
|
soa_record = zone.find_rrset(zone.origin, dns.rdatatype.SOA)
|
||||||
rname = soa_record.items[0].rname.derelativize(origin=domain.origin)
|
rname = soa_record.items[0].rname.derelativize(origin=zone.origin)
|
||||||
|
|
||||||
with self._sync_domain(domain.origin):
|
with self._sync_zone(zone.origin):
|
||||||
# Update zone with a new parameters
|
# Update zone with a new parameters
|
||||||
self.denominator.update_zone(
|
self.denominator.update_zone(
|
||||||
id=domain_name,
|
id=zone_name,
|
||||||
ttl=soa_record.ttl,
|
ttl=soa_record.ttl,
|
||||||
email=rname)
|
email=rname)
|
||||||
|
|
||||||
# Fetch records to create a differential update of a zone.
|
# Fetch records to create a differential update of a zone.
|
||||||
output = self.denominator.get_records(domain_name)
|
output = self.denominator.get_records(zone_name)
|
||||||
subdomains = dict()
|
subzones = dict()
|
||||||
|
|
||||||
# Subdomains dict will contain names of subdomains without
|
# subzones dict will contain names of subzones without
|
||||||
# trailing dot.
|
# trailing dot.
|
||||||
for raw in output.splitlines():
|
for raw in output.splitlines():
|
||||||
data = raw.split()
|
data = raw.split()
|
||||||
name, rtype = data[0], data[1]
|
name, rtype = data[0], data[1]
|
||||||
|
|
||||||
rtypes = subdomains.get(name, set())
|
rtypes = subzones.get(name, set())
|
||||||
rtypes.add(rtype)
|
rtypes.add(rtype)
|
||||||
subdomains[name] = rtypes
|
subzones[name] = rtypes
|
||||||
|
|
||||||
for name, ttl, rtype, data in self._iterate_records(domain):
|
for name, ttl, rtype, data in self._iterate_records(zone):
|
||||||
record_action = self.denominator.create_record
|
record_action = self.denominator.create_record
|
||||||
|
|
||||||
if name in subdomains and rtype in subdomains[name]:
|
if name in subzones and rtype in subzones[name]:
|
||||||
# When RR set already exists, replace it with a new one.
|
# When RR set already exists, replace it with a new one.
|
||||||
rdatatype = dns.rdatatype.from_text(rtype)
|
rdatatype = dns.rdatatype.from_text(rtype)
|
||||||
record_action = self.denominator.update_record
|
record_action = self.denominator.update_record
|
||||||
|
|
||||||
# So next call will ADD a new record to record set
|
# So next call will ADD a new record to record set
|
||||||
# instead of replacing of the existing one.
|
# instead of replacing of the existing one.
|
||||||
subdomains[name].remove(rtype)
|
subzones[name].remove(rtype)
|
||||||
|
|
||||||
# NOTE: DynECT does not support deleting of the SOA
|
# NOTE: DynECT does not support deleting of the SOA
|
||||||
# record. Skip updating of the SOA record.
|
# record. Skip updating of the SOA record.
|
||||||
if rdatatype == dns.rdatatype.SOA:
|
if rdatatype == dns.rdatatype.SOA:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
record_action(zone=domain_name,
|
record_action(zone=zone_name,
|
||||||
name=name,
|
name=name,
|
||||||
type=rtype,
|
type=rtype,
|
||||||
ttl=ttl,
|
ttl=ttl,
|
||||||
data=data)
|
data=data)
|
||||||
|
|
||||||
# Remaining records should be deleted
|
# Remaining records should be deleted
|
||||||
for name, types in subdomains.items():
|
for name, types in subzones.items():
|
||||||
for rtype in types:
|
for rtype in types:
|
||||||
self.denominator.delete_record(
|
self.denominator.delete_record(
|
||||||
zone=domain_name, id=name, type=rtype)
|
zone=zone_name, id=name, type=rtype)
|
||||||
|
|
||||||
def delete_domain(self, domain_name):
|
def delete_zone(self, zone_name):
|
||||||
LOG.debug('Delete Domain: %s' % domain_name)
|
LOG.debug('Delete Zone: %s' % zone_name)
|
||||||
|
|
||||||
with self._sync_domain(domain_name):
|
with self._sync_zone(zone_name):
|
||||||
self.denominator.delete_zone(id=domain_name)
|
self.denominator.delete_zone(id=zone_name)
|
||||||
|
|
||||||
def _sync_domain(self, domain_name):
|
def _sync_zone(self, zone_name):
|
||||||
LOG.debug('Synchronising domain: %s' % domain_name)
|
LOG.debug('Synchronising zone: %s' % zone_name)
|
||||||
return lockutils.lock('denominator-%s' % domain_name)
|
return lockutils.lock('denominator-%s' % zone_name)
|
||||||
|
|
||||||
def _iterate_records(self, domain):
|
def _iterate_records(self, zone):
|
||||||
for rname, ttl, rdata in domain.iterate_rdatas():
|
for rname, ttl, rdata in zone.iterate_rdatas():
|
||||||
name = rname.derelativize(origin=domain.origin)
|
name = rname.derelativize(origin=zone.origin)
|
||||||
name = name.to_text(omit_final_dot=True)
|
name = name.to_text(omit_final_dot=True)
|
||||||
|
|
||||||
data = rdata.to_text(origin=domain.origin, relativize=False)
|
data = rdata.to_text(origin=zone.origin, relativize=False)
|
||||||
yield name, ttl, dns.rdatatype.to_text(rdata.rdtype), data
|
yield name, ttl, dns.rdatatype.to_text(rdata.rdtype), data
|
||||||
|
@ -30,15 +30,15 @@ class FakeBackend(base.AgentBackend):
|
|||||||
def stop(self):
|
def stop(self):
|
||||||
LOG.info(_LI("Stopped fake backend"))
|
LOG.info(_LI("Stopped fake backend"))
|
||||||
|
|
||||||
def find_domain_serial(self, domain_name):
|
def find_zone_serial(self, zone_name):
|
||||||
LOG.debug("Finding %s" % domain_name)
|
LOG.debug("Finding %s" % zone_name)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def create_domain(self, domain):
|
def create_zone(self, zone):
|
||||||
LOG.debug("Creating %s" % domain.origin.to_text())
|
LOG.debug("Creating %s" % zone.origin.to_text())
|
||||||
|
|
||||||
def update_domain(self, domain):
|
def update_zone(self, zone):
|
||||||
LOG.debug("Updating %s" % domain.origin.to_text())
|
LOG.debug("Updating %s" % zone.origin.to_text())
|
||||||
|
|
||||||
def delete_domain(self, domain_name):
|
def delete_zone(self, zone_name):
|
||||||
LOG.debug('Delete Domain: %s' % domain_name)
|
LOG.debug('Delete Zone: %s' % zone_name)
|
||||||
|
@ -67,34 +67,34 @@ class Backend(DriverPlugin):
|
|||||||
|
|
||||||
# Core Backend Interface
|
# Core Backend Interface
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
Create a DNS domain.
|
Create a DNS zone.
|
||||||
|
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param domain: the DNS domain.
|
:param zone: the DNS zone.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def update_domain(self, context, domain):
|
def update_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
Update a DNS domain.
|
Update a DNS zone.
|
||||||
|
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param domain: the DNS domain.
|
:param zone: the DNS zone.
|
||||||
"""
|
"""
|
||||||
LOG.debug('Update Domain')
|
LOG.debug('Update Zone')
|
||||||
|
|
||||||
self.mdns_api.notify_zone_changed(
|
self.mdns_api.notify_zone_changed(
|
||||||
context, domain, self.host, self.port, self.timeout,
|
context, zone, self.host, self.port, self.timeout,
|
||||||
self.retry_interval, self.max_retries, self.delay)
|
self.retry_interval, self.max_retries, self.delay)
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
Delete a DNS domain.
|
Delete a DNS zone.
|
||||||
|
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param domain: the DNS domain.
|
:param zone: the DNS zone.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def ping(self, context):
|
def ping(self, context):
|
||||||
|
@ -47,7 +47,7 @@ class DelegationExists(exceptions.BadRequest, EnhancedDNSException):
|
|||||||
error_type = 'delegation_exists'
|
error_type = 'delegation_exists'
|
||||||
|
|
||||||
|
|
||||||
class DuplicateDomain(exceptions.DuplicateDomain, EnhancedDNSException):
|
class DuplicateZone(exceptions.DuplicateZone, EnhancedDNSException):
|
||||||
"""
|
"""
|
||||||
Raised when an attempt to create a zone which is registered to another
|
Raised when an attempt to create a zone which is registered to another
|
||||||
Akamai account is made
|
Akamai account is made
|
||||||
@ -60,7 +60,7 @@ class Forbidden(exceptions.Forbidden, EnhancedDNSException):
|
|||||||
Raised when an attempt to modify a zone which is registered to another
|
Raised when an attempt to modify a zone which is registered to another
|
||||||
Akamai account is made.
|
Akamai account is made.
|
||||||
|
|
||||||
This appears to be returned when creating a new subdomain of domain which
|
This appears to be returned when creating a new subzone of zone which
|
||||||
already exists in another Akamai account.
|
already exists in another Akamai account.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@ -142,7 +142,7 @@ class EnhancedDNSClient(object):
|
|||||||
return self.client.service.setZones(zones=zones)
|
return self.client.service.setZones(zones=zones)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if 'You do not have permission to view this zone' in str(e):
|
if 'You do not have permission to view this zone' in str(e):
|
||||||
raise DuplicateDomain()
|
raise DuplicateZone()
|
||||||
elif 'You do not have access to edit this zone' in str(e):
|
elif 'You do not have access to edit this zone' in str(e):
|
||||||
raise Forbidden()
|
raise Forbidden()
|
||||||
elif 'basic auth failed' in str(e):
|
elif 'basic auth failed' in str(e):
|
||||||
@ -158,7 +158,7 @@ class EnhancedDNSClient(object):
|
|||||||
self.client.service.setZone(zone=zone)
|
self.client.service.setZone(zone=zone)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if 'You do not have permission to view this zone' in str(e):
|
if 'You do not have permission to view this zone' in str(e):
|
||||||
raise DuplicateDomain()
|
raise DuplicateZone()
|
||||||
elif 'You do not have access to edit this zone' in str(e):
|
elif 'You do not have access to edit this zone' in str(e):
|
||||||
raise Forbidden()
|
raise Forbidden()
|
||||||
elif 'basic auth failed' in str(e):
|
elif 'basic auth failed' in str(e):
|
||||||
@ -197,22 +197,22 @@ class EnhancedDNSClient(object):
|
|||||||
return zoneName.rstrip('.').lower()
|
return zoneName.rstrip('.').lower()
|
||||||
|
|
||||||
|
|
||||||
def build_zone(client, target, domain):
|
def build_zone(client, target, zone):
|
||||||
masters = [m.host for m in target.masters]
|
masters = [m.host for m in target.masters]
|
||||||
|
|
||||||
if target.options.get("tsig_key_name", None):
|
if target.options.get("tsig_key_name", None):
|
||||||
return client.buildZone(
|
return client.buildZone(
|
||||||
domain.name,
|
zone.name,
|
||||||
masters,
|
masters,
|
||||||
domain.id,
|
zone.id,
|
||||||
target.options["tsig_key_name"],
|
target.options["tsig_key_name"],
|
||||||
target.options.get("tsig_key_secret", None),
|
target.options.get("tsig_key_secret", None),
|
||||||
target.options.get("tsig_key_algorithm", None))
|
target.options.get("tsig_key_algorithm", None))
|
||||||
else:
|
else:
|
||||||
return client.buildZone(
|
return client.buildZone(
|
||||||
domain.name,
|
zone.name,
|
||||||
masters,
|
masters,
|
||||||
domain.id)
|
zone.id)
|
||||||
|
|
||||||
|
|
||||||
class AkamaiBackend(base.Backend):
|
class AkamaiBackend(base.Backend):
|
||||||
@ -247,12 +247,12 @@ class AkamaiBackend(base.Backend):
|
|||||||
raise exceptions.ConfigurationError(
|
raise exceptions.ConfigurationError(
|
||||||
"Akamai only supports mDNS instances on port 53")
|
"Akamai only supports mDNS instances on port 53")
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
"""Create a DNS domain"""
|
"""Create a DNS zone"""
|
||||||
zone = build_zone(self.client, self.target, domain)
|
zone = build_zone(self.client, self.target, zone)
|
||||||
|
|
||||||
self.client.setZone(zone=zone)
|
self.client.setZone(zone=zone)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
"""Delete a DNS domain"""
|
"""Delete a DNS zone"""
|
||||||
self.client.deleteZone(zoneName=domain['name'])
|
self.client.deleteZone(zoneName=zone['name'])
|
||||||
|
@ -48,8 +48,8 @@ class Bind9Backend(base.Backend):
|
|||||||
self.clean_zonefile = strutils.bool_from_string(
|
self.clean_zonefile = strutils.bool_from_string(
|
||||||
self.options.get('clean_zonefile', 'false'))
|
self.options.get('clean_zonefile', 'false'))
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.debug('Create Domain')
|
LOG.debug('Create Zone')
|
||||||
masters = []
|
masters = []
|
||||||
for master in self.masters:
|
for master in self.masters:
|
||||||
host = master['host']
|
host = master['host']
|
||||||
@ -62,26 +62,26 @@ class Bind9Backend(base.Backend):
|
|||||||
rndc_op = [
|
rndc_op = [
|
||||||
'addzone',
|
'addzone',
|
||||||
'%s { type slave; masters { %s;}; file "slave.%s%s"; };' %
|
'%s { type slave; masters { %s;}; file "slave.%s%s"; };' %
|
||||||
(domain['name'].rstrip('.'), '; '.join(masters), domain['name'],
|
(zone['name'].rstrip('.'), '; '.join(masters), zone['name'],
|
||||||
domain['id']),
|
zone['id']),
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._execute_rndc(rndc_op)
|
self._execute_rndc(rndc_op)
|
||||||
except exceptions.Backend as e:
|
except exceptions.Backend as e:
|
||||||
# If create fails because the domain exists, don't reraise
|
# If create fails because the zone exists, don't reraise
|
||||||
if "already exists" not in six.text_type(e):
|
if "already exists" not in six.text_type(e):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
self.mdns_api.notify_zone_changed(
|
self.mdns_api.notify_zone_changed(
|
||||||
context, domain, self.host, self.port, self.timeout,
|
context, zone, self.host, self.port, self.timeout,
|
||||||
self.retry_interval, self.max_retries, self.delay)
|
self.retry_interval, self.max_retries, self.delay)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
LOG.debug('Delete Domain')
|
LOG.debug('Delete Zone')
|
||||||
rndc_op = [
|
rndc_op = [
|
||||||
'delzone',
|
'delzone',
|
||||||
'%s' % domain['name'].rstrip('.'),
|
'%s' % zone['name'].rstrip('.'),
|
||||||
]
|
]
|
||||||
if self.clean_zonefile:
|
if self.clean_zonefile:
|
||||||
rndc_op.insert(1, '-clean')
|
rndc_op.insert(1, '-clean')
|
||||||
@ -89,7 +89,7 @@ class Bind9Backend(base.Backend):
|
|||||||
try:
|
try:
|
||||||
self._execute_rndc(rndc_op)
|
self._execute_rndc(rndc_op)
|
||||||
except exceptions.Backend as e:
|
except exceptions.Backend as e:
|
||||||
# If domain is already deleted, don't reraise
|
# If zone is already deleted, don't reraise
|
||||||
if "not found" not in six.text_type(e):
|
if "not found" not in six.text_type(e):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -87,20 +87,20 @@ class DesignateBackend(base.Backend):
|
|||||||
session=session, service_type=self.service_type)
|
session=session, service_type=self.service_type)
|
||||||
return self._client
|
return self._client
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
msg = _LI('Creating domain %(d_id)s / %(d_name)s')
|
msg = _LI('Creating zone %(d_id)s / %(d_name)s')
|
||||||
LOG.info(msg, {'d_id': domain['id'], 'd_name': domain['name']})
|
LOG.info(msg, {'d_id': zone['id'], 'd_name': zone['name']})
|
||||||
|
|
||||||
masters = ["%s:%s" % (i.host, i.port) for i in self.masters]
|
masters = ["%s:%s" % (i.host, i.port) for i in self.masters]
|
||||||
self.client.zones.create(
|
self.client.zones.create(
|
||||||
domain.name, 'SECONDARY', masters=masters)
|
zone.name, 'SECONDARY', masters=masters)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
msg = _LI('Deleting domain %(d_id)s / %(d_name)s')
|
msg = _LI('Deleting zone %(d_id)s / %(d_name)s')
|
||||||
LOG.info(msg, {'d_id': domain['id'], 'd_name': domain['name']})
|
LOG.info(msg, {'d_id': zone['id'], 'd_name': zone['name']})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.client.zones.delete(domain.name)
|
self.client.zones.delete(zone.name)
|
||||||
except exceptions.NotFound:
|
except exceptions.NotFound:
|
||||||
msg = _LW("Zone %s not found on remote Designate, Ignoring")
|
msg = _LW("Zone %s not found on remote Designate, Ignoring")
|
||||||
LOG.warn(msg, domain.id)
|
LOG.warn(msg, zone.id)
|
||||||
|
@ -344,11 +344,11 @@ class DynECTBackend(base.Backend):
|
|||||||
timeout=CONF[CFG_GROUP].timeout,
|
timeout=CONF[CFG_GROUP].timeout,
|
||||||
timings=CONF[CFG_GROUP].timings)
|
timings=CONF[CFG_GROUP].timings)
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.info(_LI('Creating domain %(d_id)s / %(d_name)s') %
|
LOG.info(_LI('Creating zone %(d_id)s / %(d_name)s') %
|
||||||
{'d_id': domain['id'], 'd_name': domain['name']})
|
{'d_id': zone['id'], 'd_name': zone['name']})
|
||||||
|
|
||||||
url = '/Secondary/%s' % domain['name'].rstrip('.')
|
url = '/Secondary/%s' % zone['name'].rstrip('.')
|
||||||
data = {
|
data = {
|
||||||
'masters': [m.host for m in self.masters]
|
'masters': [m.host for m in self.masters]
|
||||||
}
|
}
|
||||||
@ -366,9 +366,9 @@ class DynECTBackend(base.Backend):
|
|||||||
except DynClientError as e:
|
except DynClientError as e:
|
||||||
for emsg in e.msgs:
|
for emsg in e.msgs:
|
||||||
if emsg['ERR_CD'] == 'TARGET_EXISTS':
|
if emsg['ERR_CD'] == 'TARGET_EXISTS':
|
||||||
msg = _LI("Domain already exists, updating existing "
|
msg = _LI("Zone already exists, updating existing "
|
||||||
"domain instead %s")
|
"zone instead %s")
|
||||||
LOG.info(msg % domain['name'])
|
LOG.info(msg % zone['name'])
|
||||||
client.put(url, data=data)
|
client.put(url, data=data)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
@ -377,10 +377,10 @@ class DynECTBackend(base.Backend):
|
|||||||
client.put(url, data={'activate': True})
|
client.put(url, data={'activate': True})
|
||||||
client.logout()
|
client.logout()
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
LOG.info(_LI('Deleting domain %(d_id)s / %(d_name)s') %
|
LOG.info(_LI('Deleting zone %(d_id)s / %(d_name)s') %
|
||||||
{'d_id': domain['id'], 'd_name': domain['name']})
|
{'d_id': zone['id'], 'd_name': zone['name']})
|
||||||
url = '/Zone/%s' % domain['name'].rstrip('.')
|
url = '/Zone/%s' % zone['name'].rstrip('.')
|
||||||
client = self.get_client()
|
client = self.get_client()
|
||||||
try:
|
try:
|
||||||
client.delete(url)
|
client.delete(url)
|
||||||
@ -388,26 +388,8 @@ class DynECTBackend(base.Backend):
|
|||||||
if e.http_status == 404:
|
if e.http_status == 404:
|
||||||
LOG.warn(_LW("Attempt to delete %(d_id)s / %(d_name)s "
|
LOG.warn(_LW("Attempt to delete %(d_id)s / %(d_name)s "
|
||||||
"caused 404, ignoring.") %
|
"caused 404, ignoring.") %
|
||||||
{'d_id': domain['id'], 'd_name': domain['name']})
|
{'d_id': zone['id'], 'd_name': zone['name']})
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
client.logout()
|
client.logout()
|
||||||
|
|
||||||
def create_recordset(self, context, domain, recordset):
|
|
||||||
LOG.debug('Discarding create_recordset call, not-applicable')
|
|
||||||
|
|
||||||
def update_recordset(self, context, domain, recordset):
|
|
||||||
LOG.debug('Discarding update_recordset call, not-applicable')
|
|
||||||
|
|
||||||
def delete_recordset(self, context, domain, recordset):
|
|
||||||
LOG.debug('Discarding delete_recordset call, not-applicable')
|
|
||||||
|
|
||||||
def create_record(self, context, domain, recordset, record):
|
|
||||||
LOG.debug('Discarding create_record call, not-applicable')
|
|
||||||
|
|
||||||
def update_record(self, context, domain, recordset, record):
|
|
||||||
LOG.debug('Discarding update_record call, not-applicable')
|
|
||||||
|
|
||||||
def delete_record(self, context, domain, recordset, record):
|
|
||||||
LOG.debug('Discarding delete_record call, not-applicable')
|
|
||||||
|
@ -25,8 +25,8 @@ LOG = logging.getLogger(__name__)
|
|||||||
class FakeBackend(base.Backend):
|
class FakeBackend(base.Backend):
|
||||||
__plugin_name__ = 'fake'
|
__plugin_name__ = 'fake'
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.info(_LI('Create Domain %r') % domain)
|
LOG.info(_LI('Create Zone %r') % zone)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
LOG.info(_LI('Delete Domain %r') % domain)
|
LOG.info(_LI('Delete Zone %r') % zone)
|
||||||
|
@ -42,18 +42,18 @@ class InfobloxBackend(base.Backend):
|
|||||||
raise exceptions.ConfigurationError(
|
raise exceptions.ConfigurationError(
|
||||||
"Infoblox only supports mDNS instances on port 53")
|
"Infoblox only supports mDNS instances on port 53")
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.info(_LI('Create Domain %r') % domain)
|
LOG.info(_LI('Create Zone %r') % zone)
|
||||||
|
|
||||||
dns_net_view = self.infoblox.get_dns_view(context.tenant)
|
dns_net_view = self.infoblox.get_dns_view(context.tenant)
|
||||||
self.infoblox.create_zone_auth(
|
self.infoblox.create_zone_auth(
|
||||||
fqdn=domain['name'][0:-1],
|
fqdn=zone['name'][0:-1],
|
||||||
dns_view=dns_net_view
|
dns_view=dns_net_view
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
LOG.info(_LI('Delete Domain %r') % domain)
|
LOG.info(_LI('Delete Zone %r') % zone)
|
||||||
self.infoblox.delete_zone_auth(domain['name'][0:-1])
|
self.infoblox.delete_zone_auth(zone['name'][0:-1])
|
||||||
|
|
||||||
def ping(self, context):
|
def ping(self, context):
|
||||||
LOG.info(_LI('Ping'))
|
LOG.info(_LI('Ping'))
|
||||||
|
@ -75,8 +75,8 @@ class NSD4Backend(base.Backend):
|
|||||||
if result != 'ok':
|
if result != 'ok':
|
||||||
raise exceptions.Backend(result)
|
raise exceptions.Backend(result)
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.debug('Create Domain')
|
LOG.debug('Create Zone')
|
||||||
masters = []
|
masters = []
|
||||||
for master in self.masters:
|
for master in self.masters:
|
||||||
host = master['host']
|
host = master['host']
|
||||||
@ -86,22 +86,22 @@ class NSD4Backend(base.Backend):
|
|||||||
# Ensure different MiniDNS instances are targeted for AXFRs
|
# Ensure different MiniDNS instances are targeted for AXFRs
|
||||||
random.shuffle(masters)
|
random.shuffle(masters)
|
||||||
|
|
||||||
command = 'addzone %s %s' % (domain['name'], self.pattern)
|
command = 'addzone %s %s' % (zone['name'], self.pattern)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._execute_nsd4(command)
|
self._execute_nsd4(command)
|
||||||
except exceptions.Backend as e:
|
except exceptions.Backend as e:
|
||||||
# If create fails because the domain exists, don't reraise
|
# If create fails because the zone exists, don't reraise
|
||||||
if "already exists" not in six.text_type(e):
|
if "already exists" not in six.text_type(e):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
LOG.debug('Delete Domain')
|
LOG.debug('Delete Zone')
|
||||||
command = 'delzone %s' % domain['name']
|
command = 'delzone %s' % zone['name']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._execute_nsd4(command)
|
self._execute_nsd4(command)
|
||||||
except exceptions.Backend as e:
|
except exceptions.Backend as e:
|
||||||
# If domain is already deleted, don't reraise
|
# If zone is already deleted, don't reraise
|
||||||
if "not found" not in six.text_type(e):
|
if "not found" not in six.text_type(e):
|
||||||
raise
|
raise
|
||||||
|
@ -118,8 +118,8 @@ class PowerDNSBackend(base.Backend):
|
|||||||
if resultproxy.rowcount != 1:
|
if resultproxy.rowcount != 1:
|
||||||
raise exc_notfound()
|
raise exc_notfound()
|
||||||
|
|
||||||
# Domain Methods
|
# Zone Methods
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
try:
|
try:
|
||||||
self.session.begin()
|
self.session.begin()
|
||||||
|
|
||||||
@ -128,8 +128,8 @@ class PowerDNSBackend(base.Backend):
|
|||||||
masters = six.moves.map(_parse_master, self.masters)
|
masters = six.moves.map(_parse_master, self.masters)
|
||||||
|
|
||||||
domain_values = {
|
domain_values = {
|
||||||
'designate_id': domain['id'],
|
'designate_id': zone['id'],
|
||||||
'name': domain['name'].rstrip('.'),
|
'name': zone['name'].rstrip('.'),
|
||||||
'master': ','.join(masters),
|
'master': ','.join(masters),
|
||||||
'type': 'SLAVE',
|
'type': 'SLAVE',
|
||||||
'account': context.tenant
|
'account': context.tenant
|
||||||
@ -143,23 +143,23 @@ class PowerDNSBackend(base.Backend):
|
|||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
self.mdns_api.notify_zone_changed(
|
self.mdns_api.notify_zone_changed(
|
||||||
context, domain, self.host, self.port, self.timeout,
|
context, zone, self.host, self.port, self.timeout,
|
||||||
self.retry_interval, self.max_retries, self.delay)
|
self.retry_interval, self.max_retries, self.delay)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
# TODO(kiall): We should make this match create_domain with regard to
|
# TODO(kiall): We should make this match create_zone with regard to
|
||||||
# transactions.
|
# transactions.
|
||||||
try:
|
try:
|
||||||
self._get(tables.domains, domain['id'], exceptions.DomainNotFound,
|
self._get(tables.domains, zone['id'], exceptions.ZoneNotFound,
|
||||||
id_col=tables.domains.c.designate_id)
|
id_col=tables.domains.c.designate_id)
|
||||||
except exceptions.DomainNotFound:
|
except exceptions.ZoneNotFound:
|
||||||
# If the Domain is already gone, that's ok. We're deleting it
|
# If the Zone is already gone, that's ok. We're deleting it
|
||||||
# anyway, so just log and continue.
|
# anyway, so just log and continue.
|
||||||
LOG.critical(_LC('Attempted to delete a domain which is '
|
LOG.critical(_LC('Attempted to delete a zone which is '
|
||||||
'not present in the backend. ID: %s') %
|
'not present in the backend. ID: %s') %
|
||||||
domain['id'])
|
zone['id'])
|
||||||
return
|
return
|
||||||
|
|
||||||
self._delete(tables.domains, domain['id'],
|
self._delete(tables.domains, zone['id'],
|
||||||
exceptions.DomainNotFound,
|
exceptions.ZoneNotFound,
|
||||||
id_col=tables.domains.c.designate_id)
|
id_col=tables.domains.c.designate_id)
|
||||||
|
@ -28,8 +28,8 @@ cfg.CONF.register_opts([
|
|||||||
help='The storage driver to use'),
|
help='The storage driver to use'),
|
||||||
cfg.ListOpt('enabled-notification-handlers', default=[],
|
cfg.ListOpt('enabled-notification-handlers', default=[],
|
||||||
help='Enabled Notification Handlers'),
|
help='Enabled Notification Handlers'),
|
||||||
cfg.IntOpt('max_domain_name_len', default=255,
|
cfg.IntOpt('max_zone_name_len', default=255,
|
||||||
help="Maximum domain name length"),
|
help="Maximum zone name length"),
|
||||||
cfg.IntOpt('max_recordset_name_len', default=255,
|
cfg.IntOpt('max_recordset_name_len', default=255,
|
||||||
help="Maximum recordset name length",
|
help="Maximum recordset name length",
|
||||||
deprecated_name='max_record_name_len'),
|
deprecated_name='max_record_name_len'),
|
||||||
|
@ -47,20 +47,21 @@ class CentralAPI(object):
|
|||||||
4.2 - Add methods for pool manager integration
|
4.2 - Add methods for pool manager integration
|
||||||
4.3 - Added Zone Transfer Methods
|
4.3 - Added Zone Transfer Methods
|
||||||
5.0 - Remove dead server code
|
5.0 - Remove dead server code
|
||||||
5.1 - Add xfr_domain
|
5.1 - Add xfr_zone
|
||||||
5.2 - Add Zone Import methods
|
5.2 - Add Zone Import methods
|
||||||
5.3 - Add Zone Export method
|
5.3 - Add Zone Export method
|
||||||
5.4 - Add asynchronous Zone Export methods
|
5.4 - Add asynchronous Zone Export methods
|
||||||
5.5 - Add deleted zone purging task
|
5.5 - Add deleted zone purging task
|
||||||
5.6 - Changed 'purge_domains' function args
|
5.6 - Changed 'purge_zones' function args
|
||||||
|
6.0 - Renamed domains to zones
|
||||||
"""
|
"""
|
||||||
RPC_API_VERSION = '5.6'
|
RPC_API_VERSION = '6.0'
|
||||||
|
|
||||||
def __init__(self, topic=None):
|
def __init__(self, topic=None):
|
||||||
topic = topic if topic else cfg.CONF.central_topic
|
topic = topic if topic else cfg.CONF.central_topic
|
||||||
|
|
||||||
target = messaging.Target(topic=topic, version=self.RPC_API_VERSION)
|
target = messaging.Target(topic=topic, version=self.RPC_API_VERSION)
|
||||||
self.client = rpc.get_client(target, version_cap='5.6')
|
self.client = rpc.get_client(target, version_cap='6.0')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_instance(cls):
|
def get_instance(cls):
|
||||||
@ -144,56 +145,55 @@ class CentralAPI(object):
|
|||||||
LOG.info(_LI("count_tenants: Calling central's count_tenants."))
|
LOG.info(_LI("count_tenants: Calling central's count_tenants."))
|
||||||
return self.client.call(context, 'count_tenants')
|
return self.client.call(context, 'count_tenants')
|
||||||
|
|
||||||
# Domain Methods
|
# Zone Methods
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.info(_LI("create_domain: Calling central's create_domain."))
|
LOG.info(_LI("create_zone: Calling central's create_zone."))
|
||||||
return self.client.call(context, 'create_domain', domain=domain)
|
return self.client.call(context, 'create_zone', zone=zone)
|
||||||
|
|
||||||
def get_domain(self, context, domain_id):
|
def get_zone(self, context, zone_id):
|
||||||
LOG.info(_LI("get_domain: Calling central's get_domain."))
|
LOG.info(_LI("get_zone: Calling central's get_zone."))
|
||||||
return self.client.call(context, 'get_domain', domain_id=domain_id)
|
return self.client.call(context, 'get_zone', zone_id=zone_id)
|
||||||
|
|
||||||
def get_domain_servers(self, context, domain_id):
|
def get_zone_ns_records(self, context, zone_id):
|
||||||
LOG.info(_LI("get_domain_servers: "
|
LOG.info(_LI("get_zone_ns_records: "
|
||||||
"Calling central's get_domain_servers."))
|
"Calling central's get_zone_ns_records."))
|
||||||
return self.client.call(context, 'get_domain_servers',
|
return self.client.call(context, 'get_zone_ns_records',
|
||||||
domain_id=domain_id)
|
zone_id=zone_id)
|
||||||
|
|
||||||
def find_domains(self, context, criterion=None, marker=None, limit=None,
|
def find_zones(self, context, criterion=None, marker=None, limit=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None):
|
||||||
LOG.info(_LI("find_domains: Calling central's find_domains."))
|
LOG.info(_LI("find_zones: Calling central's find_zones."))
|
||||||
return self.client.call(context, 'find_domains', criterion=criterion,
|
return self.client.call(context, 'find_zones', criterion=criterion,
|
||||||
marker=marker, limit=limit, sort_key=sort_key,
|
marker=marker, limit=limit, sort_key=sort_key,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir)
|
||||||
|
|
||||||
def find_domain(self, context, criterion=None):
|
def find_zone(self, context, criterion=None):
|
||||||
LOG.info(_LI("find_domain: Calling central's find_domain."))
|
LOG.info(_LI("find_zone: Calling central's find_zone."))
|
||||||
return self.client.call(context, 'find_domain', criterion=criterion)
|
return self.client.call(context, 'find_zone', criterion=criterion)
|
||||||
|
|
||||||
def update_domain(self, context, domain, increment_serial=True):
|
def update_zone(self, context, zone, increment_serial=True):
|
||||||
LOG.info(_LI("update_domain: Calling central's update_domain."))
|
LOG.info(_LI("update_zone: Calling central's update_zone."))
|
||||||
return self.client.call(context, 'update_domain', domain=domain,
|
return self.client.call(context, 'update_zone', zone=zone,
|
||||||
increment_serial=increment_serial)
|
increment_serial=increment_serial)
|
||||||
|
|
||||||
def delete_domain(self, context, domain_id):
|
def delete_zone(self, context, zone_id):
|
||||||
LOG.info(_LI("delete_domain: Calling central's delete_domain."))
|
LOG.info(_LI("delete_zone: Calling central's delete_zone."))
|
||||||
return self.client.call(context, 'delete_domain', domain_id=domain_id)
|
return self.client.call(context, 'delete_zone', zone_id=zone_id)
|
||||||
|
|
||||||
def purge_domains(self, context, criterion, limit=None):
|
def purge_zones(self, context, criterion, limit=None):
|
||||||
LOG.info(_LI(
|
LOG.info(_LI(
|
||||||
"purge_domains: Calling central's purge_domains."
|
"purge_zones: Calling central's purge_zones."
|
||||||
))
|
))
|
||||||
cctxt = self.client.prepare(version='5.6')
|
return self.client.call(context, 'purge_zones',
|
||||||
return cctxt.call(context, 'purge_domains',
|
|
||||||
criterion=criterion, limit=limit)
|
criterion=criterion, limit=limit)
|
||||||
|
|
||||||
def count_domains(self, context, criterion=None):
|
def count_zones(self, context, criterion=None):
|
||||||
LOG.info(_LI("count_domains: Calling central's count_domains."))
|
LOG.info(_LI("count_zones: Calling central's count_zones."))
|
||||||
return self.client.call(context, 'count_domains', criterion=criterion)
|
return self.client.call(context, 'count_zones', criterion=criterion)
|
||||||
|
|
||||||
def touch_domain(self, context, domain_id):
|
def touch_zone(self, context, zone_id):
|
||||||
LOG.info(_LI("touch_domain: Calling central's touch_domain."))
|
LOG.info(_LI("touch_zone: Calling central's touch_zone."))
|
||||||
return self.client.call(context, 'touch_domain', domain_id=domain_id)
|
return self.client.call(context, 'touch_zone', zone_id=zone_id)
|
||||||
|
|
||||||
# TLD Methods
|
# TLD Methods
|
||||||
def create_tld(self, context, tld):
|
def create_tld(self, context, tld):
|
||||||
@ -220,14 +220,14 @@ class CentralAPI(object):
|
|||||||
return self.client.call(context, 'delete_tld', tld_id=tld_id)
|
return self.client.call(context, 'delete_tld', tld_id=tld_id)
|
||||||
|
|
||||||
# RecordSet Methods
|
# RecordSet Methods
|
||||||
def create_recordset(self, context, domain_id, recordset):
|
def create_recordset(self, context, zone_id, recordset):
|
||||||
LOG.info(_LI("create_recordset: Calling central's create_recordset."))
|
LOG.info(_LI("create_recordset: Calling central's create_recordset."))
|
||||||
return self.client.call(context, 'create_recordset',
|
return self.client.call(context, 'create_recordset',
|
||||||
domain_id=domain_id, recordset=recordset)
|
zone_id=zone_id, recordset=recordset)
|
||||||
|
|
||||||
def get_recordset(self, context, domain_id, recordset_id):
|
def get_recordset(self, context, zone_id, recordset_id):
|
||||||
LOG.info(_LI("get_recordset: Calling central's get_recordset."))
|
LOG.info(_LI("get_recordset: Calling central's get_recordset."))
|
||||||
return self.client.call(context, 'get_recordset', domain_id=domain_id,
|
return self.client.call(context, 'get_recordset', zone_id=zone_id,
|
||||||
recordset_id=recordset_id)
|
recordset_id=recordset_id)
|
||||||
|
|
||||||
def find_recordsets(self, context, criterion=None, marker=None, limit=None,
|
def find_recordsets(self, context, criterion=None, marker=None, limit=None,
|
||||||
@ -252,11 +252,11 @@ class CentralAPI(object):
|
|||||||
recordset=recordset,
|
recordset=recordset,
|
||||||
increment_serial=increment_serial)
|
increment_serial=increment_serial)
|
||||||
|
|
||||||
def delete_recordset(self, context, domain_id, recordset_id,
|
def delete_recordset(self, context, zone_id, recordset_id,
|
||||||
increment_serial=True):
|
increment_serial=True):
|
||||||
LOG.info(_LI("delete_recordset: Calling central's delete_recordset."))
|
LOG.info(_LI("delete_recordset: Calling central's delete_recordset."))
|
||||||
return self.client.call(context, 'delete_recordset',
|
return self.client.call(context, 'delete_recordset',
|
||||||
domain_id=domain_id,
|
zone_id=zone_id,
|
||||||
recordset_id=recordset_id,
|
recordset_id=recordset_id,
|
||||||
increment_serial=increment_serial)
|
increment_serial=increment_serial)
|
||||||
|
|
||||||
@ -266,19 +266,19 @@ class CentralAPI(object):
|
|||||||
criterion=criterion)
|
criterion=criterion)
|
||||||
|
|
||||||
# Record Methods
|
# Record Methods
|
||||||
def create_record(self, context, domain_id, recordset_id, record,
|
def create_record(self, context, zone_id, recordset_id, record,
|
||||||
increment_serial=True):
|
increment_serial=True):
|
||||||
LOG.info(_LI("create_record: Calling central's create_record."))
|
LOG.info(_LI("create_record: Calling central's create_record."))
|
||||||
return self.client.call(context, 'create_record',
|
return self.client.call(context, 'create_record',
|
||||||
domain_id=domain_id,
|
zone_id=zone_id,
|
||||||
recordset_id=recordset_id,
|
recordset_id=recordset_id,
|
||||||
record=record,
|
record=record,
|
||||||
increment_serial=increment_serial)
|
increment_serial=increment_serial)
|
||||||
|
|
||||||
def get_record(self, context, domain_id, recordset_id, record_id):
|
def get_record(self, context, zone_id, recordset_id, record_id):
|
||||||
LOG.info(_LI("get_record: Calling central's get_record."))
|
LOG.info(_LI("get_record: Calling central's get_record."))
|
||||||
return self.client.call(context, 'get_record',
|
return self.client.call(context, 'get_record',
|
||||||
domain_id=domain_id,
|
zone_id=zone_id,
|
||||||
recordset_id=recordset_id,
|
recordset_id=recordset_id,
|
||||||
record_id=record_id)
|
record_id=record_id)
|
||||||
|
|
||||||
@ -299,11 +299,11 @@ class CentralAPI(object):
|
|||||||
record=record,
|
record=record,
|
||||||
increment_serial=increment_serial)
|
increment_serial=increment_serial)
|
||||||
|
|
||||||
def delete_record(self, context, domain_id, recordset_id, record_id,
|
def delete_record(self, context, zone_id, recordset_id, record_id,
|
||||||
increment_serial=True):
|
increment_serial=True):
|
||||||
LOG.info(_LI("delete_record: Calling central's delete_record."))
|
LOG.info(_LI("delete_record: Calling central's delete_record."))
|
||||||
return self.client.call(context, 'delete_record',
|
return self.client.call(context, 'delete_record',
|
||||||
domain_id=domain_id,
|
zone_id=zone_id,
|
||||||
recordset_id=recordset_id,
|
recordset_id=recordset_id,
|
||||||
record_id=record_id,
|
record_id=record_id,
|
||||||
increment_serial=increment_serial)
|
increment_serial=increment_serial)
|
||||||
@ -312,24 +312,24 @@ class CentralAPI(object):
|
|||||||
LOG.info(_LI("count_records: Calling central's count_records."))
|
LOG.info(_LI("count_records: Calling central's count_records."))
|
||||||
return self.client.call(context, 'count_records', criterion=criterion)
|
return self.client.call(context, 'count_records', criterion=criterion)
|
||||||
|
|
||||||
# Misc. Report combining counts for tenants, domains and records
|
# Misc. Report combining counts for tenants, zones and records
|
||||||
def count_report(self, context, criterion=None):
|
def count_report(self, context, criterion=None):
|
||||||
LOG.info(_LI("count_report: Calling central's count_report."))
|
LOG.info(_LI("count_report: Calling central's count_report."))
|
||||||
return self.client.call(context, 'count_report', criterion=criterion)
|
return self.client.call(context, 'count_report', criterion=criterion)
|
||||||
|
|
||||||
# Sync Methods
|
# Sync Methods
|
||||||
def sync_domains(self, context):
|
def sync_zones(self, context):
|
||||||
LOG.info(_LI("sync_domains: Calling central's sync_domains."))
|
LOG.info(_LI("sync_zones: Calling central's sync_zones."))
|
||||||
return self.client.call(context, 'sync_domains')
|
return self.client.call(context, 'sync_zones')
|
||||||
|
|
||||||
def sync_domain(self, context, domain_id):
|
def sync_zone(self, context, zone_id):
|
||||||
LOG.info(_LI("sync_domain: Calling central's sync_domains."))
|
LOG.info(_LI("sync_zone: Calling central's sync_zones."))
|
||||||
return self.client.call(context, 'sync_domain', domain_id=domain_id)
|
return self.client.call(context, 'sync_zone', zone_id=zone_id)
|
||||||
|
|
||||||
def sync_record(self, context, domain_id, recordset_id, record_id):
|
def sync_record(self, context, zone_id, recordset_id, record_id):
|
||||||
LOG.info(_LI("sync_record: Calling central's sync_record."))
|
LOG.info(_LI("sync_record: Calling central's sync_record."))
|
||||||
return self.client.call(context, 'sync_record',
|
return self.client.call(context, 'sync_record',
|
||||||
domain_id=domain_id,
|
zone_id=zone_id,
|
||||||
recordset_id=recordset_id,
|
recordset_id=recordset_id,
|
||||||
record_id=record_id)
|
record_id=record_id)
|
||||||
|
|
||||||
@ -348,7 +348,7 @@ class CentralAPI(object):
|
|||||||
return self.client.call(context, 'update_floatingip', region=region,
|
return self.client.call(context, 'update_floatingip', region=region,
|
||||||
floatingip_id=floatingip_id, values=values)
|
floatingip_id=floatingip_id, values=values)
|
||||||
|
|
||||||
# Blacklisted Domain Methods
|
# Blacklisted Zone Methods
|
||||||
def create_blacklist(self, context, blacklist):
|
def create_blacklist(self, context, blacklist):
|
||||||
LOG.info(_LI("create_blacklist: Calling central's create_blacklist"))
|
LOG.info(_LI("create_blacklist: Calling central's create_blacklist"))
|
||||||
return self.client.call(context, 'create_blacklist',
|
return self.client.call(context, 'create_blacklist',
|
||||||
@ -409,11 +409,11 @@ class CentralAPI(object):
|
|||||||
return self.client.call(context, 'delete_pool', pool_id=pool_id)
|
return self.client.call(context, 'delete_pool', pool_id=pool_id)
|
||||||
|
|
||||||
# Pool Manager Integration Methods
|
# Pool Manager Integration Methods
|
||||||
def update_status(self, context, domain_id, status, serial):
|
def update_status(self, context, zone_id, status, serial):
|
||||||
LOG.info(_LI("update_status: Calling central's update_status "
|
LOG.info(_LI("update_status: Calling central's update_status "
|
||||||
"for %(domain_id)s : %(status)s : %(serial)s") %
|
"for %(zone_id)s : %(status)s : %(serial)s") %
|
||||||
{'domain_id': domain_id, 'status': status, 'serial': serial})
|
{'zone_id': zone_id, 'status': status, 'serial': serial})
|
||||||
self.client.cast(context, 'update_status', domain_id=domain_id,
|
self.client.cast(context, 'update_status', zone_id=zone_id,
|
||||||
status=status, serial=serial)
|
status=status, serial=serial)
|
||||||
|
|
||||||
# Zone Ownership Transfers
|
# Zone Ownership Transfers
|
||||||
@ -509,10 +509,9 @@ class CentralAPI(object):
|
|||||||
'delete_zone_transfer_accept',
|
'delete_zone_transfer_accept',
|
||||||
zone_transfer_accept_id=zone_transfer_accept_id)
|
zone_transfer_accept_id=zone_transfer_accept_id)
|
||||||
|
|
||||||
def xfr_domain(self, context, domain_id):
|
def xfr_zone(self, context, zone_id):
|
||||||
LOG.info(_LI("xfr_domain: Calling central's xfr_domain"))
|
LOG.info(_LI("xfr_zone: Calling central's xfr_zone"))
|
||||||
cctxt = self.client.prepare(version='5.3')
|
return self.client.call(context, 'xfr_zone', zone_id=zone_id)
|
||||||
return cctxt.call(context, 'xfr_domain', domain_id=domain_id)
|
|
||||||
|
|
||||||
# Zone Import Methods
|
# Zone Import Methods
|
||||||
def create_zone_import(self, context, request_body):
|
def create_zone_import(self, context, request_body):
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -169,7 +169,7 @@ class DesignateContext(context.RequestContext):
|
|||||||
@abandon.setter
|
@abandon.setter
|
||||||
def abandon(self, value):
|
def abandon(self, value):
|
||||||
if value:
|
if value:
|
||||||
policy.check('abandon_domain', self)
|
policy.check('abandon_zone', self)
|
||||||
self._abandon = value
|
self._abandon = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -281,7 +281,7 @@ def from_dnspython_zone(dnspython_zone):
|
|||||||
'expire': soa[0].expire
|
'expire': soa[0].expire
|
||||||
}
|
}
|
||||||
|
|
||||||
zone = objects.Domain(**values)
|
zone = objects.Zone(**values)
|
||||||
|
|
||||||
rrsets = dnspyrecords_to_recordsetlist(dnspython_zone.nodes)
|
rrsets = dnspyrecords_to_recordsetlist(dnspython_zone.nodes)
|
||||||
zone.recordsets = rrsets
|
zone.recordsets = rrsets
|
||||||
@ -348,7 +348,7 @@ def do_axfr(zone_name, servers, timeout=None, source=None):
|
|||||||
LOG.error(msg % log_info)
|
LOG.error(msg % log_info)
|
||||||
continue
|
continue
|
||||||
except dns.exception.FormError:
|
except dns.exception.FormError:
|
||||||
msg = _LE("Domain %(name)s is not present on %(host)s."
|
msg = _LE("Zone %(name)s is not present on %(host)s."
|
||||||
"Trying next server.")
|
"Trying next server.")
|
||||||
LOG.error(msg % log_info)
|
LOG.error(msg % log_info)
|
||||||
except socket.error:
|
except socket.error:
|
||||||
|
@ -179,9 +179,9 @@ class UnsupportedContentType(BadRequest):
|
|||||||
error_type = 'unsupported_content_type'
|
error_type = 'unsupported_content_type'
|
||||||
|
|
||||||
|
|
||||||
class InvalidDomainName(Base):
|
class InvalidZoneName(Base):
|
||||||
error_code = 400
|
error_code = 400
|
||||||
error_type = 'invalid_domain_name'
|
error_type = 'invalid_zone_name'
|
||||||
expected = True
|
expected = True
|
||||||
|
|
||||||
|
|
||||||
@ -205,9 +205,9 @@ class InvalidTTL(Base):
|
|||||||
error_type = 'invalid_ttl'
|
error_type = 'invalid_ttl'
|
||||||
|
|
||||||
|
|
||||||
class DomainHasSubdomain(Base):
|
class ZoneHasSubZone(Base):
|
||||||
error_code = 400
|
error_code = 400
|
||||||
error_type = 'domain_has_subdomain'
|
error_type = 'zone_has_sub_zone'
|
||||||
|
|
||||||
|
|
||||||
class Forbidden(Base):
|
class Forbidden(Base):
|
||||||
@ -216,11 +216,11 @@ class Forbidden(Base):
|
|||||||
expected = True
|
expected = True
|
||||||
|
|
||||||
|
|
||||||
class IllegalChildDomain(Forbidden):
|
class IllegalChildZone(Forbidden):
|
||||||
error_type = 'illegal_child'
|
error_type = 'illegal_child'
|
||||||
|
|
||||||
|
|
||||||
class IllegalParentDomain(Forbidden):
|
class IllegalParentZone(Forbidden):
|
||||||
error_type = 'illegal_parent'
|
error_type = 'illegal_parent'
|
||||||
|
|
||||||
|
|
||||||
@ -246,8 +246,8 @@ class DuplicateTsigKey(Duplicate):
|
|||||||
error_type = 'duplicate_tsigkey'
|
error_type = 'duplicate_tsigkey'
|
||||||
|
|
||||||
|
|
||||||
class DuplicateDomain(Duplicate):
|
class DuplicateZone(Duplicate):
|
||||||
error_type = 'duplicate_domain'
|
error_type = 'duplicate_zone'
|
||||||
|
|
||||||
|
|
||||||
class DuplicateTld(Duplicate):
|
class DuplicateTld(Duplicate):
|
||||||
@ -278,8 +278,8 @@ class DuplicatePoolAttribute(Duplicate):
|
|||||||
error_type = 'duplicate_pool_attribute'
|
error_type = 'duplicate_pool_attribute'
|
||||||
|
|
||||||
|
|
||||||
class DuplicateDomainAttribute(Duplicate):
|
class DuplicateZoneAttribute(Duplicate):
|
||||||
error_type = 'duplicate_domain_attribute'
|
error_type = 'duplicate_zone_attribute'
|
||||||
|
|
||||||
|
|
||||||
class DuplicatePoolNsRecord(Duplicate):
|
class DuplicatePoolNsRecord(Duplicate):
|
||||||
@ -330,16 +330,16 @@ class BlacklistNotFound(NotFound):
|
|||||||
error_type = 'blacklist_not_found'
|
error_type = 'blacklist_not_found'
|
||||||
|
|
||||||
|
|
||||||
class DomainNotFound(NotFound):
|
class ZoneNotFound(NotFound):
|
||||||
error_type = 'domain_not_found'
|
error_type = 'zone_not_found'
|
||||||
|
|
||||||
|
|
||||||
class DomainMasterNotFound(NotFound):
|
class ZoneMasterNotFound(NotFound):
|
||||||
error_type = 'domain_master_not_found'
|
error_type = 'zone_master_not_found'
|
||||||
|
|
||||||
|
|
||||||
class DomainAttributeNotFound(NotFound):
|
class ZoneAttributeNotFound(NotFound):
|
||||||
error_type = 'domain_attribute_not_found'
|
error_type = 'zone_attribute_not_found'
|
||||||
|
|
||||||
|
|
||||||
class TldNotFound(NotFound):
|
class TldNotFound(NotFound):
|
||||||
|
@ -61,7 +61,7 @@ class AkamaiCommands(base.Commands):
|
|||||||
client = impl_akamai.EnhancedDNSClient(
|
client = impl_akamai.EnhancedDNSClient(
|
||||||
target.options.get("username"), target.options.get("password"))
|
target.options.get("username"), target.options.get("password"))
|
||||||
|
|
||||||
zone = self.central_api.find_domain(self.context, {"name": zone_name})
|
zone = self.central_api.find_zone(self.context, {"name": zone_name})
|
||||||
akamai_zone = client.getZone(zone_name)
|
akamai_zone = client.getZone(zone_name)
|
||||||
|
|
||||||
print("Designate zone\n%s" % pformat(zone.to_dict()))
|
print("Designate zone\n%s" % pformat(zone.to_dict()))
|
||||||
@ -70,7 +70,7 @@ class AkamaiCommands(base.Commands):
|
|||||||
@base.args('pool-id', help="Pool to Sync", type=str)
|
@base.args('pool-id', help="Pool to Sync", type=str)
|
||||||
@base.args('pool-target-id', help="Pool Target to Sync", type=str)
|
@base.args('pool-target-id', help="Pool Target to Sync", type=str)
|
||||||
@base.args('--batch-size', default=20, type=int)
|
@base.args('--batch-size', default=20, type=int)
|
||||||
def sync_domains(self, pool_id, pool_target_id, batch_size):
|
def sync_zones(self, pool_id, pool_target_id, batch_size):
|
||||||
pool, target = self._get_config(pool_id, pool_target_id)
|
pool, target = self._get_config(pool_id, pool_target_id)
|
||||||
|
|
||||||
client = impl_akamai.EnhancedDNSClient(
|
client = impl_akamai.EnhancedDNSClient(
|
||||||
@ -82,7 +82,7 @@ class AkamaiCommands(base.Commands):
|
|||||||
marker = None
|
marker = None
|
||||||
|
|
||||||
while (marker is not False):
|
while (marker is not False):
|
||||||
zones = self.central_api.find_domains(
|
zones = self.central_api.find_zones(
|
||||||
self.context, criterion, limit=batch_size, marker=marker)
|
self.context, criterion, limit=batch_size, marker=marker)
|
||||||
update = []
|
update = []
|
||||||
|
|
||||||
|
@ -116,8 +116,8 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
domain = self.storage.find_domain(context, criterion)
|
zone = self.storage.find_zone(context, criterion)
|
||||||
except exceptions.DomainNotFound:
|
except exceptions.ZoneNotFound:
|
||||||
response.set_rcode(dns.rcode.NOTAUTH)
|
response.set_rcode(dns.rcode.NOTAUTH)
|
||||||
yield response
|
yield response
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
@ -127,11 +127,11 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
# We check if the src_master which is the assumed master for the zone
|
# We check if the src_master which is the assumed master for the zone
|
||||||
# that is sending this NOTIFY OP is actually the master. If it's not
|
# that is sending this NOTIFY OP is actually the master. If it's not
|
||||||
# We'll reply but don't do anything with the NOTIFY.
|
# We'll reply but don't do anything with the NOTIFY.
|
||||||
master_addr = domain.get_master_by_ip(notify_addr)
|
master_addr = zone.get_master_by_ip(notify_addr)
|
||||||
if not master_addr:
|
if not master_addr:
|
||||||
msg = _LW("NOTIFY for %(name)s from non-master server "
|
msg = _LW("NOTIFY for %(name)s from non-master server "
|
||||||
"%(addr)s, ignoring.")
|
"%(addr)s, ignoring.")
|
||||||
LOG.warn(msg % {"name": domain.name, "addr": notify_addr})
|
LOG.warn(msg % {"name": zone.name, "addr": notify_addr})
|
||||||
response.set_rcode(dns.rcode.REFUSED)
|
response.set_rcode(dns.rcode.REFUSED)
|
||||||
yield response
|
yield response
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
@ -140,17 +140,17 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
# According to RFC we should query the server that sent the NOTIFY
|
# According to RFC we should query the server that sent the NOTIFY
|
||||||
resolver.nameservers = [notify_addr]
|
resolver.nameservers = [notify_addr]
|
||||||
|
|
||||||
soa_answer = resolver.query(domain.name, 'SOA')
|
soa_answer = resolver.query(zone.name, 'SOA')
|
||||||
soa_serial = soa_answer[0].serial
|
soa_serial = soa_answer[0].serial
|
||||||
if soa_serial == domain.serial:
|
if soa_serial == zone.serial:
|
||||||
msg = _LI("Serial %(serial)s is the same for master and us for "
|
msg = _LI("Serial %(serial)s is the same for master and us for "
|
||||||
"%(domain_id)s")
|
"%(zone_id)s")
|
||||||
LOG.info(msg % {"serial": soa_serial, "domain_id": domain.id})
|
LOG.info(msg % {"serial": soa_serial, "zone_id": zone.id})
|
||||||
else:
|
else:
|
||||||
msg = _LI("Scheduling AXFR for %(domain_id)s from %(master_addr)s")
|
msg = _LI("Scheduling AXFR for %(zone_id)s from %(master_addr)s")
|
||||||
info = {"domain_id": domain.id, "master_addr": master_addr}
|
info = {"zone_id": zone.id, "master_addr": master_addr}
|
||||||
LOG.info(msg % info)
|
LOG.info(msg % info)
|
||||||
self.tg.add_thread(self.domain_sync, context, domain,
|
self.tg.add_thread(self.zone_sync, context, zone,
|
||||||
[master_addr])
|
[master_addr])
|
||||||
|
|
||||||
response.flags |= dns.flags.AA
|
response.flags |= dns.flags.AA
|
||||||
@ -170,7 +170,7 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def _domain_criterion_from_request(self, request, criterion=None):
|
def _zone_criterion_from_request(self, request, criterion=None):
|
||||||
"""Builds a bare criterion dict based on the request attributes"""
|
"""Builds a bare criterion dict based on the request attributes"""
|
||||||
criterion = criterion or {}
|
criterion = criterion or {}
|
||||||
|
|
||||||
@ -197,12 +197,12 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
|
|
||||||
return criterion
|
return criterion
|
||||||
|
|
||||||
def _convert_to_rrset(self, domain, recordset):
|
def _convert_to_rrset(self, zone, recordset):
|
||||||
# Fetch the domain or the config ttl if the recordset ttl is null
|
# Fetch the zone or the config ttl if the recordset ttl is null
|
||||||
if recordset.ttl:
|
if recordset.ttl:
|
||||||
ttl = recordset.ttl
|
ttl = recordset.ttl
|
||||||
else:
|
else:
|
||||||
ttl = domain.ttl
|
ttl = zone.ttl
|
||||||
|
|
||||||
# construct rdata from all the records
|
# construct rdata from all the records
|
||||||
rdata = []
|
rdata = []
|
||||||
@ -233,12 +233,12 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
# TODO(vinod) once validation is separated from the api,
|
# TODO(vinod) once validation is separated from the api,
|
||||||
# validate the parameters
|
# validate the parameters
|
||||||
try:
|
try:
|
||||||
criterion = self._domain_criterion_from_request(
|
criterion = self._zone_criterion_from_request(
|
||||||
request, {'name': q_rrset.name.to_text()})
|
request, {'name': q_rrset.name.to_text()})
|
||||||
domain = self.storage.find_domain(context, criterion)
|
zone = self.storage.find_zone(context, criterion)
|
||||||
|
|
||||||
except exceptions.DomainNotFound:
|
except exceptions.ZoneNotFound:
|
||||||
LOG.warning(_LW("DomainNotFound while handling axfr request. "
|
LOG.warning(_LW("ZoneNotFound while handling axfr request. "
|
||||||
"Question was %(qr)s") % {'qr': q_rrset})
|
"Question was %(qr)s") % {'qr': q_rrset})
|
||||||
|
|
||||||
yield self._handle_query_error(request, dns.rcode.REFUSED)
|
yield self._handle_query_error(request, dns.rcode.REFUSED)
|
||||||
@ -252,11 +252,11 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
# The AXFR response needs to have a SOA at the beginning and end.
|
# The AXFR response needs to have a SOA at the beginning and end.
|
||||||
criterion = {'domain_id': domain.id, 'type': 'SOA'}
|
criterion = {'zone_id': zone.id, 'type': 'SOA'}
|
||||||
soa_records = self.storage.find_recordsets_axfr(context, criterion)
|
soa_records = self.storage.find_recordsets_axfr(context, criterion)
|
||||||
|
|
||||||
# Get all the records other than SOA
|
# Get all the records other than SOA
|
||||||
criterion = {'domain_id': domain.id, 'type': '!SOA'}
|
criterion = {'zone_id': zone.id, 'type': '!SOA'}
|
||||||
records = self.storage.find_recordsets_axfr(context, criterion)
|
records = self.storage.find_recordsets_axfr(context, criterion)
|
||||||
|
|
||||||
# Place the SOA RRSet at the front and end of the RRSet list
|
# Place the SOA RRSet at the front and end of the RRSet list
|
||||||
@ -296,7 +296,7 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
# Build a DNSPython RRSet from the RR
|
# Build a DNSPython RRSet from the RR
|
||||||
rrset = dns.rrset.from_text_list(
|
rrset = dns.rrset.from_text_list(
|
||||||
str(record[3]), # name
|
str(record[3]), # name
|
||||||
int(record[2]) if record[2] is not None else domain.ttl, # ttl
|
int(record[2]) if record[2] is not None else zone.ttl, # ttl
|
||||||
dns.rdataclass.IN, # class
|
dns.rdataclass.IN, # class
|
||||||
str(record[1]), # rrtype
|
str(record[1]), # rrtype
|
||||||
[str(record[4])], # rdata
|
[str(record[4])], # rdata
|
||||||
@ -309,10 +309,10 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
if renderer.counts[dns.renderer.ANSWER] == 0:
|
if renderer.counts[dns.renderer.ANSWER] == 0:
|
||||||
# We've received a TooBig from the first attempted RRSet in
|
# We've received a TooBig from the first attempted RRSet in
|
||||||
# this packet. Log a warning and abort the AXFR.
|
# this packet. Log a warning and abort the AXFR.
|
||||||
LOG.warning(_LW('Aborted AXFR of %(domain)s, a single RR '
|
LOG.warning(_LW('Aborted AXFR of %(zone)s, a single RR '
|
||||||
'(%(rrset_type)s %(rrset_name)s) '
|
'(%(rrset_type)s %(rrset_name)s) '
|
||||||
'exceeded the max message size.'),
|
'exceeded the max message size.'),
|
||||||
{'domain': domain.name,
|
{'zone': zone.name,
|
||||||
'rrset_type': record[1],
|
'rrset_type': record[1],
|
||||||
'rrset_name': record[3]})
|
'rrset_name': record[3]})
|
||||||
|
|
||||||
@ -356,17 +356,17 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
criterion = {
|
criterion = {
|
||||||
'name': q_rrset.name.to_text(),
|
'name': q_rrset.name.to_text(),
|
||||||
'type': dns.rdatatype.to_text(q_rrset.rdtype),
|
'type': dns.rdatatype.to_text(q_rrset.rdtype),
|
||||||
'domains_deleted': False
|
'zones_deleted': False
|
||||||
}
|
}
|
||||||
recordset = self.storage.find_recordset(context, criterion)
|
recordset = self.storage.find_recordset(context, criterion)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
criterion = self._domain_criterion_from_request(
|
criterion = self._zone_criterion_from_request(
|
||||||
request, {'id': recordset.domain_id})
|
request, {'id': recordset.zone_id})
|
||||||
domain = self.storage.find_domain(context, criterion)
|
zone = self.storage.find_zone(context, criterion)
|
||||||
|
|
||||||
except exceptions.DomainNotFound:
|
except exceptions.ZoneNotFound:
|
||||||
LOG.warning(_LW("DomainNotFound while handling query request"
|
LOG.warning(_LW("ZoneNotFound while handling query request"
|
||||||
". Question was %(qr)s") % {'qr': q_rrset})
|
". Question was %(qr)s") % {'qr': q_rrset})
|
||||||
|
|
||||||
yield self._handle_query_error(request, dns.rcode.REFUSED)
|
yield self._handle_query_error(request, dns.rcode.REFUSED)
|
||||||
@ -379,7 +379,7 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
yield self._handle_query_error(request, dns.rcode.REFUSED)
|
yield self._handle_query_error(request, dns.rcode.REFUSED)
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
r_rrset = self._convert_to_rrset(domain, recordset)
|
r_rrset = self._convert_to_rrset(zone, recordset)
|
||||||
response.set_rcode(dns.rcode.NOERROR)
|
response.set_rcode(dns.rcode.NOERROR)
|
||||||
response.answer = [r_rrset]
|
response.answer = [r_rrset]
|
||||||
# For all the data stored in designate mdns is Authoritative
|
# For all the data stored in designate mdns is Authoritative
|
||||||
@ -396,9 +396,9 @@ class RequestHandler(xfr.XFRMixin):
|
|||||||
# However, an authoritative nameserver shouldn't return NXDOMAIN
|
# However, an authoritative nameserver shouldn't return NXDOMAIN
|
||||||
# for a zone it isn't authoritative for. It would be more
|
# for a zone it isn't authoritative for. It would be more
|
||||||
# appropriate for it to return REFUSED. It should still return
|
# appropriate for it to return REFUSED. It should still return
|
||||||
# NXDOMAIN if it is authoritative for a domain but the FQDN doesn't
|
# NXDOMAIN if it is authoritative for a zone but the FQDN doesn't
|
||||||
# exist, like abcdef.rackspace.com. Of course, a wildcard within a
|
# exist, like abcdef.rackspace.com. Of course, a wildcard within a
|
||||||
# domain would mean that NXDOMAIN isn't ever returned for a domain.
|
# zone would mean that NXDOMAIN isn't ever returned for a zone.
|
||||||
#
|
#
|
||||||
# To simply things currently this returns a REFUSED in all cases.
|
# To simply things currently this returns a REFUSED in all cases.
|
||||||
# If zone transfers needs different errors, we could revisit this.
|
# If zone transfers needs different errors, we could revisit this.
|
||||||
|
@ -40,11 +40,11 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
RPC_API_VERSION = '2.0'
|
RPC_API_VERSION = '2.0'
|
||||||
RPC_API_NAMESPACE = 'notify'
|
RPC_API_NAMESPACE = 'notify'
|
||||||
|
|
||||||
def notify_zone_changed(self, context, domain, host, port, timeout,
|
def notify_zone_changed(self, context, zone, host, port, timeout,
|
||||||
retry_interval, max_retries, delay):
|
retry_interval, max_retries, delay):
|
||||||
"""
|
"""
|
||||||
:param context: The user context.
|
:param context: The user context.
|
||||||
:param domain: The designate domain object. This contains the domain
|
:param zone: The designate zone object. This contains the zone
|
||||||
name.
|
name.
|
||||||
:param host: A notify is sent to this host.
|
:param host: A notify is sent to this host.
|
||||||
:param port: A notify is sent to this port.
|
:param port: A notify is sent to this port.
|
||||||
@ -61,15 +61,15 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
"""
|
"""
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
return self._make_and_send_dns_message(
|
return self._make_and_send_dns_message(
|
||||||
domain, host, port, timeout, retry_interval, max_retries,
|
zone, host, port, timeout, retry_interval, max_retries,
|
||||||
notify=True)
|
notify=True)
|
||||||
|
|
||||||
def poll_for_serial_number(self, context, domain, nameserver, timeout,
|
def poll_for_serial_number(self, context, zone, nameserver, timeout,
|
||||||
retry_interval, max_retries, delay):
|
retry_interval, max_retries, delay):
|
||||||
"""
|
"""
|
||||||
:param context: The user context.
|
:param context: The user context.
|
||||||
:param domain: The designate domain object. This contains the domain
|
:param zone: The designate zone object. This contains the zone
|
||||||
name. domain.serial = expected_serial
|
name. zone.serial = expected_serial
|
||||||
:param nameserver: Destination for the poll
|
:param nameserver: Destination for the poll
|
||||||
:param timeout: The time (in seconds) to wait for a SOA response from
|
:param timeout: The time (in seconds) to wait for a SOA response from
|
||||||
nameserver.
|
nameserver.
|
||||||
@ -81,17 +81,17 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
:return: The pool manager is informed of the status with update_status.
|
:return: The pool manager is informed of the status with update_status.
|
||||||
"""
|
"""
|
||||||
(status, actual_serial, retries) = self.get_serial_number(
|
(status, actual_serial, retries) = self.get_serial_number(
|
||||||
context, domain, nameserver.host, nameserver.port, timeout,
|
context, zone, nameserver.host, nameserver.port, timeout,
|
||||||
retry_interval, max_retries, delay)
|
retry_interval, max_retries, delay)
|
||||||
self.pool_manager_api.update_status(
|
self.pool_manager_api.update_status(
|
||||||
context, domain, nameserver, status, actual_serial)
|
context, zone, nameserver, status, actual_serial)
|
||||||
|
|
||||||
def get_serial_number(self, context, domain, host, port, timeout,
|
def get_serial_number(self, context, zone, host, port, timeout,
|
||||||
retry_interval, max_retries, delay):
|
retry_interval, max_retries, delay):
|
||||||
"""
|
"""
|
||||||
:param context: The user context.
|
:param context: The user context.
|
||||||
:param domain: The designate domain object. This contains the domain
|
:param zone: The designate zone object. This contains the zone
|
||||||
name. domain.serial = expected_serial
|
name. zone.serial = expected_serial
|
||||||
:param host: A notify is sent to this host.
|
:param host: A notify is sent to this host.
|
||||||
:param port: A notify is sent to this port.
|
:param port: A notify is sent to this port.
|
||||||
:param timeout: The time (in seconds) to wait for a SOA response from
|
:param timeout: The time (in seconds) to wait for a SOA response from
|
||||||
@ -115,26 +115,26 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
while (True):
|
while (True):
|
||||||
(response, retry) = self._make_and_send_dns_message(
|
(response, retry) = self._make_and_send_dns_message(
|
||||||
domain, host, port, timeout, retry_interval, retries)
|
zone, host, port, timeout, retry_interval, retries)
|
||||||
if response and response.rcode() in (
|
if response and response.rcode() in (
|
||||||
dns.rcode.NXDOMAIN, dns.rcode.REFUSED, dns.rcode.SERVFAIL):
|
dns.rcode.NXDOMAIN, dns.rcode.REFUSED, dns.rcode.SERVFAIL):
|
||||||
status = 'NO_DOMAIN'
|
status = 'NO_DOMAIN'
|
||||||
elif response and len(response.answer) == 1 \
|
elif response and len(response.answer) == 1 \
|
||||||
and str(response.answer[0].name) == str(domain.name) \
|
and str(response.answer[0].name) == str(zone.name) \
|
||||||
and response.answer[0].rdclass == dns.rdataclass.IN \
|
and response.answer[0].rdclass == dns.rdataclass.IN \
|
||||||
and response.answer[0].rdtype == dns.rdatatype.SOA:
|
and response.answer[0].rdtype == dns.rdatatype.SOA:
|
||||||
# parse the SOA response and get the serial number
|
# parse the SOA response and get the serial number
|
||||||
rrset = response.answer[0]
|
rrset = response.answer[0]
|
||||||
actual_serial = rrset.to_rdataset().items[0].serial
|
actual_serial = rrset.to_rdataset().items[0].serial
|
||||||
|
|
||||||
if actual_serial is None or actual_serial < domain.serial:
|
if actual_serial is None or actual_serial < zone.serial:
|
||||||
# TODO(vinod): Account for serial number wrap around.
|
# TODO(vinod): Account for serial number wrap around.
|
||||||
retries = retries - retry
|
retries = retries - retry
|
||||||
LOG.warn(_LW("Got lower serial for '%(zone)s' to '%(host)s:"
|
LOG.warn(_LW("Got lower serial for '%(zone)s' to '%(host)s:"
|
||||||
"%(port)s'. Expected:'%(es)d'. Got:'%(as)s'."
|
"%(port)s'. Expected:'%(es)d'. Got:'%(as)s'."
|
||||||
"Retries left='%(retries)d'") %
|
"Retries left='%(retries)d'") %
|
||||||
{'zone': domain.name, 'host': host,
|
{'zone': zone.name, 'host': host,
|
||||||
'port': port, 'es': domain.serial,
|
'port': port, 'es': zone.serial,
|
||||||
'as': actual_serial, 'retries': retries})
|
'as': actual_serial, 'retries': retries})
|
||||||
if retries > 0:
|
if retries > 0:
|
||||||
# retry again
|
# retry again
|
||||||
@ -150,10 +150,10 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
# Return retries for testing purposes.
|
# Return retries for testing purposes.
|
||||||
return (status, actual_serial, retries)
|
return (status, actual_serial, retries)
|
||||||
|
|
||||||
def _make_and_send_dns_message(self, domain, host, port, timeout,
|
def _make_and_send_dns_message(self, zone, host, port, timeout,
|
||||||
retry_interval, max_retries, notify=False):
|
retry_interval, max_retries, notify=False):
|
||||||
"""
|
"""
|
||||||
:param domain: The designate domain object. This contains the domain
|
:param zone: The designate zone object. This contains the zone
|
||||||
name.
|
name.
|
||||||
:param host: The destination host for the dns message.
|
:param host: The destination host for the dns message.
|
||||||
:param port: The destination port for the dns message.
|
:param port: The destination port for the dns message.
|
||||||
@ -168,7 +168,7 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
response is the response on success or None on failure.
|
response is the response on success or None on failure.
|
||||||
current_retry is the current retry number
|
current_retry is the current retry number
|
||||||
"""
|
"""
|
||||||
dns_message = self._make_dns_message(domain.name, notify=notify)
|
dns_message = self._make_dns_message(zone.name, notify=notify)
|
||||||
|
|
||||||
retry = 0
|
retry = 0
|
||||||
response = None
|
response = None
|
||||||
@ -178,7 +178,7 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
LOG.info(_LI("Sending '%(msg)s' for '%(zone)s' to '%(server)s:"
|
LOG.info(_LI("Sending '%(msg)s' for '%(zone)s' to '%(server)s:"
|
||||||
"%(port)d'.") %
|
"%(port)d'.") %
|
||||||
{'msg': 'NOTIFY' if notify else 'SOA',
|
{'msg': 'NOTIFY' if notify else 'SOA',
|
||||||
'zone': domain.name, 'server': host,
|
'zone': zone.name, 'server': host,
|
||||||
'port': port})
|
'port': port})
|
||||||
response = self._send_dns_message(
|
response = self._send_dns_message(
|
||||||
dns_message, host, port, timeout)
|
dns_message, host, port, timeout)
|
||||||
@ -188,7 +188,7 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
"'%(zone)s' to '%(server)s:%(port)d'. Timeout="
|
"'%(zone)s' to '%(server)s:%(port)d'. Timeout="
|
||||||
"'%(timeout)d' seconds. Retry='%(retry)d'") %
|
"'%(timeout)d' seconds. Retry='%(retry)d'") %
|
||||||
{'msg': 'NOTIFY' if notify else 'SOA',
|
{'msg': 'NOTIFY' if notify else 'SOA',
|
||||||
'zone': domain.name, 'server': host,
|
'zone': zone.name, 'server': host,
|
||||||
'port': port, 'timeout': timeout,
|
'port': port, 'timeout': timeout,
|
||||||
'retry': retry})
|
'retry': retry})
|
||||||
response = None
|
response = None
|
||||||
@ -200,7 +200,7 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
"for '%(zone)s' to '%(server)s:%(port)d'. Timeout"
|
"for '%(zone)s' to '%(server)s:%(port)d'. Timeout"
|
||||||
"='%(timeout)d' seconds. Retry='%(retry)d'") %
|
"='%(timeout)d' seconds. Retry='%(retry)d'") %
|
||||||
{'msg': 'NOTIFY' if notify else 'SOA',
|
{'msg': 'NOTIFY' if notify else 'SOA',
|
||||||
'zone': domain.name, 'server': host,
|
'zone': zone.name, 'server': host,
|
||||||
'port': port, 'timeout': timeout,
|
'port': port, 'timeout': timeout,
|
||||||
'retry': retry})
|
'retry': retry})
|
||||||
response = None
|
response = None
|
||||||
@ -210,7 +210,7 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
elif response.rcode() in (dns.rcode.NXDOMAIN, dns.rcode.REFUSED,
|
elif response.rcode() in (dns.rcode.NXDOMAIN, dns.rcode.REFUSED,
|
||||||
dns.rcode.SERVFAIL):
|
dns.rcode.SERVFAIL):
|
||||||
LOG.info(_LI("%(zone)s not found on %(server)s:%(port)d") %
|
LOG.info(_LI("%(zone)s not found on %(server)s:%(port)d") %
|
||||||
{'zone': domain.name, 'server': host,
|
{'zone': zone.name, 'server': host,
|
||||||
'port': port})
|
'port': port})
|
||||||
break
|
break
|
||||||
elif not (response.flags & dns.flags.AA) or dns.rcode.from_flags(
|
elif not (response.flags & dns.flags.AA) or dns.rcode.from_flags(
|
||||||
@ -219,7 +219,7 @@ class NotifyEndpoint(base.BaseEndpoint):
|
|||||||
"send '%(msg)s' for '%(zone)s' to '%(server)s:"
|
"send '%(msg)s' for '%(zone)s' to '%(server)s:"
|
||||||
"%(port)d'.\nResponse message:\n%(resp)s\n") %
|
"%(port)d'.\nResponse message:\n%(resp)s\n") %
|
||||||
{'msg': 'NOTIFY' if notify else 'SOA',
|
{'msg': 'NOTIFY' if notify else 'SOA',
|
||||||
'zone': domain.name, 'server': host,
|
'zone': zone.name, 'server': host,
|
||||||
'port': port, 'resp': str(response)})
|
'port': port, 'resp': str(response)})
|
||||||
response = None
|
response = None
|
||||||
break
|
break
|
||||||
|
@ -69,51 +69,51 @@ class MdnsAPI(object):
|
|||||||
MDNS_API = cls()
|
MDNS_API = cls()
|
||||||
return MDNS_API
|
return MDNS_API
|
||||||
|
|
||||||
def notify_zone_changed(self, context, domain, host, port, timeout,
|
def notify_zone_changed(self, context, zone, host, port, timeout,
|
||||||
retry_interval, max_retries, delay):
|
retry_interval, max_retries, delay):
|
||||||
LOG.info(_LI("notify_zone_changed: Calling mdns for zone '%(zone)s', "
|
LOG.info(_LI("notify_zone_changed: Calling mdns for zone '%(zone)s', "
|
||||||
"serial '%(serial)s' to nameserver '%(host)s:%(port)s'") %
|
"serial '%(serial)s' to nameserver '%(host)s:%(port)s'") %
|
||||||
{'zone': domain.name, 'serial': domain.serial,
|
{'zone': zone.name, 'serial': zone.serial,
|
||||||
'host': host, 'port': port})
|
'host': host, 'port': port})
|
||||||
# The notify_zone_changed method is a cast rather than a call since the
|
# The notify_zone_changed method is a cast rather than a call since the
|
||||||
# caller need not wait for the notify to complete.
|
# caller need not wait for the notify to complete.
|
||||||
return self.notify_client.cast(
|
return self.notify_client.cast(
|
||||||
context, 'notify_zone_changed', domain=domain,
|
context, 'notify_zone_changed', zone=zone,
|
||||||
host=host, port=port, timeout=timeout,
|
host=host, port=port, timeout=timeout,
|
||||||
retry_interval=retry_interval, max_retries=max_retries,
|
retry_interval=retry_interval, max_retries=max_retries,
|
||||||
delay=delay)
|
delay=delay)
|
||||||
|
|
||||||
def poll_for_serial_number(self, context, domain, nameserver, timeout,
|
def poll_for_serial_number(self, context, zone, nameserver, timeout,
|
||||||
retry_interval, max_retries, delay):
|
retry_interval, max_retries, delay):
|
||||||
LOG.info(
|
LOG.info(
|
||||||
_LI("poll_for_serial_number: Calling mdns for zone '%(zone)s', "
|
_LI("poll_for_serial_number: Calling mdns for zone '%(zone)s', "
|
||||||
"serial '%(serial)s' on nameserver '%(host)s:%(port)s'") %
|
"serial '%(serial)s' on nameserver '%(host)s:%(port)s'") %
|
||||||
{'zone': domain.name, 'serial': domain.serial,
|
{'zone': zone.name, 'serial': zone.serial,
|
||||||
'host': nameserver.host, 'port': nameserver.port})
|
'host': nameserver.host, 'port': nameserver.port})
|
||||||
# The poll_for_serial_number method is a cast rather than a call since
|
# The poll_for_serial_number method is a cast rather than a call since
|
||||||
# the caller need not wait for the poll to complete. Mdns informs pool
|
# the caller need not wait for the poll to complete. Mdns informs pool
|
||||||
# manager of the return value using update_status
|
# manager of the return value using update_status
|
||||||
return self.notify_client.cast(
|
return self.notify_client.cast(
|
||||||
context, 'poll_for_serial_number', domain=domain,
|
context, 'poll_for_serial_number', zone=zone,
|
||||||
nameserver=nameserver, timeout=timeout,
|
nameserver=nameserver, timeout=timeout,
|
||||||
retry_interval=retry_interval, max_retries=max_retries,
|
retry_interval=retry_interval, max_retries=max_retries,
|
||||||
delay=delay)
|
delay=delay)
|
||||||
|
|
||||||
def get_serial_number(self, context, domain, host, port, timeout,
|
def get_serial_number(self, context, zone, host, port, timeout,
|
||||||
retry_interval, max_retries, delay):
|
retry_interval, max_retries, delay):
|
||||||
LOG.info(
|
LOG.info(
|
||||||
_LI("get_serial_number: Calling mdns for zone '%(zone)s', serial "
|
_LI("get_serial_number: Calling mdns for zone '%(zone)s', serial "
|
||||||
"%(serial)s' on nameserver '%(host)s:%(port)s'") %
|
"%(serial)s' on nameserver '%(host)s:%(port)s'") %
|
||||||
{'zone': domain.name, 'serial': domain.serial,
|
{'zone': zone.name, 'serial': zone.serial,
|
||||||
'host': host, 'port': port})
|
'host': host, 'port': port})
|
||||||
cctxt = self.notify_client.prepare()
|
cctxt = self.notify_client.prepare()
|
||||||
return cctxt.call(
|
return cctxt.call(
|
||||||
context, 'get_serial_number', domain=domain,
|
context, 'get_serial_number', zone=zone,
|
||||||
host=host, port=port, timeout=timeout,
|
host=host, port=port, timeout=timeout,
|
||||||
retry_interval=retry_interval, max_retries=max_retries,
|
retry_interval=retry_interval, max_retries=max_retries,
|
||||||
delay=delay)
|
delay=delay)
|
||||||
|
|
||||||
def perform_zone_xfr(self, context, domain):
|
def perform_zone_xfr(self, context, zone):
|
||||||
LOG.info(_LI("perform_zone_xfr: Calling mdns for zone %(zone)s") %
|
LOG.info(_LI("perform_zone_xfr: Calling mdns for zone %(zone)s") %
|
||||||
{"zone": domain.name})
|
{"zone": zone.name})
|
||||||
return self.xfr_client.cast(context, 'perform_zone_xfr', domain=domain)
|
return self.xfr_client.cast(context, 'perform_zone_xfr', zone=zone)
|
||||||
|
@ -29,29 +29,29 @@ class XFRMixin(object):
|
|||||||
"""
|
"""
|
||||||
Utility mixin that holds common methods for XFR functionality.
|
Utility mixin that holds common methods for XFR functionality.
|
||||||
"""
|
"""
|
||||||
def domain_sync(self, context, domain, servers=None):
|
def zone_sync(self, context, zone, servers=None):
|
||||||
servers = servers or domain.masters
|
servers = servers or zone.masters
|
||||||
servers = servers.to_list()
|
servers = servers.to_list()
|
||||||
|
|
||||||
timeout = cfg.CONF["service:mdns"].xfr_timeout
|
timeout = cfg.CONF["service:mdns"].xfr_timeout
|
||||||
try:
|
try:
|
||||||
dnspython_zone = dnsutils.do_axfr(domain.name, servers,
|
dnspython_zone = dnsutils.do_axfr(zone.name, servers,
|
||||||
timeout=timeout)
|
timeout=timeout)
|
||||||
except exceptions.XFRFailure as e:
|
except exceptions.XFRFailure as e:
|
||||||
LOG.warning(e.message)
|
LOG.warning(e.message)
|
||||||
return
|
return
|
||||||
|
|
||||||
zone = dnsutils.from_dnspython_zone(dnspython_zone)
|
zone = dnsutils.from_dnspython_zone(dnspython_zone)
|
||||||
domain.update(zone)
|
zone.update(zone)
|
||||||
|
|
||||||
domain.transferred_at = timeutils.utcnow()
|
zone.transferred_at = timeutils.utcnow()
|
||||||
|
|
||||||
self.central_api.update_domain(context, domain, increment_serial=False)
|
self.central_api.update_zone(context, zone, increment_serial=False)
|
||||||
|
|
||||||
|
|
||||||
class XfrEndpoint(base.BaseEndpoint, XFRMixin):
|
class XfrEndpoint(base.BaseEndpoint, XFRMixin):
|
||||||
RPC_API_VERSION = '1.0'
|
RPC_API_VERSION = '1.0'
|
||||||
RPC_API_NAMESPACE = 'xfr'
|
RPC_API_NAMESPACE = 'xfr'
|
||||||
|
|
||||||
def perform_zone_xfr(self, context, domain):
|
def perform_zone_xfr(self, context, zone):
|
||||||
self.domain_sync(context, domain)
|
self.zone_sync(context, zone)
|
||||||
|
@ -57,14 +57,14 @@ class NotificationHandler(ExtensionPlugin):
|
|||||||
def process_notification(self, context, event_type, payload):
|
def process_notification(self, context, event_type, payload):
|
||||||
"""Processes a given notification"""
|
"""Processes a given notification"""
|
||||||
|
|
||||||
def get_domain(self, domain_id):
|
def get_zone(self, zone_id):
|
||||||
"""
|
"""
|
||||||
Return the domain for this context
|
Return the zone for this context
|
||||||
"""
|
"""
|
||||||
context = DesignateContext.get_admin_context(all_tenants=True)
|
context = DesignateContext.get_admin_context(all_tenants=True)
|
||||||
return self.central_api.get_domain(context, domain_id)
|
return self.central_api.get_zone(context, zone_id)
|
||||||
|
|
||||||
def _find_or_create_recordset(self, context, domain_id, name, type,
|
def _find_or_create_recordset(self, context, zone_id, name, type,
|
||||||
ttl=None):
|
ttl=None):
|
||||||
name = name.encode('idna').decode('utf-8')
|
name = name.encode('idna').decode('utf-8')
|
||||||
|
|
||||||
@ -76,12 +76,12 @@ class NotificationHandler(ExtensionPlugin):
|
|||||||
'ttl': ttl,
|
'ttl': ttl,
|
||||||
}
|
}
|
||||||
recordset = self.central_api.create_recordset(
|
recordset = self.central_api.create_recordset(
|
||||||
context, domain_id, RecordSet(**values))
|
context, zone_id, RecordSet(**values))
|
||||||
|
|
||||||
except exceptions.DuplicateRecordSet:
|
except exceptions.DuplicateRecordSet:
|
||||||
# Fetch the existing recordset
|
# Fetch the existing recordset
|
||||||
recordset = self.central_api.find_recordset(context, {
|
recordset = self.central_api.find_recordset(context, {
|
||||||
'domain_id': domain_id,
|
'zone_id': zone_id,
|
||||||
'name': name,
|
'name': name,
|
||||||
'type': type,
|
'type': type,
|
||||||
})
|
})
|
||||||
@ -106,7 +106,7 @@ class BaseAddressHandler(NotificationHandler):
|
|||||||
data["octet%s" % i] = ip_data[i]
|
data["octet%s" % i] = ip_data[i]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _create(self, addresses, extra, domain_id, managed=True,
|
def _create(self, addresses, extra, zone_id, managed=True,
|
||||||
resource_type=None, resource_id=None):
|
resource_type=None, resource_id=None):
|
||||||
"""
|
"""
|
||||||
Create a a record from addresses
|
Create a a record from addresses
|
||||||
@ -123,13 +123,13 @@ class BaseAddressHandler(NotificationHandler):
|
|||||||
'Deprecation notice: Unmanaged designate-sink records are '
|
'Deprecation notice: Unmanaged designate-sink records are '
|
||||||
'being deprecated please update the call '
|
'being deprecated please update the call '
|
||||||
'to remove managed=False'))
|
'to remove managed=False'))
|
||||||
LOG.debug('Using DomainID: %s' % domain_id)
|
LOG.debug('Using Zone ID: %s' % zone_id)
|
||||||
domain = self.get_domain(domain_id)
|
zone = self.get_zone(zone_id)
|
||||||
LOG.debug('Domain: %r' % domain)
|
LOG.debug('Zone: %r' % zone)
|
||||||
|
|
||||||
data = extra.copy()
|
data = extra.copy()
|
||||||
LOG.debug('Event data: %s' % data)
|
LOG.debug('Event data: %s' % data)
|
||||||
data['domain'] = domain['name']
|
data['zone'] = zone['name']
|
||||||
|
|
||||||
context = DesignateContext().elevated()
|
context = DesignateContext().elevated()
|
||||||
context.all_tenants = True
|
context.all_tenants = True
|
||||||
@ -141,7 +141,7 @@ class BaseAddressHandler(NotificationHandler):
|
|||||||
|
|
||||||
for fmt in cfg.CONF[self.name].get('format'):
|
for fmt in cfg.CONF[self.name].get('format'):
|
||||||
recordset_values = {
|
recordset_values = {
|
||||||
'domain_id': domain['id'],
|
'zone_id': zone['id'],
|
||||||
'name': fmt % event_data,
|
'name': fmt % event_data,
|
||||||
'type': 'A' if addr['version'] == 4 else 'AAAA'}
|
'type': 'A' if addr['version'] == 4 else 'AAAA'}
|
||||||
|
|
||||||
@ -160,16 +160,16 @@ class BaseAddressHandler(NotificationHandler):
|
|||||||
'managed_resource_id': resource_id})
|
'managed_resource_id': resource_id})
|
||||||
|
|
||||||
LOG.debug('Creating record in %s / %s with values %r' %
|
LOG.debug('Creating record in %s / %s with values %r' %
|
||||||
(domain['id'], recordset['id'], record_values))
|
(zone['id'], recordset['id'], record_values))
|
||||||
self.central_api.create_record(context,
|
self.central_api.create_record(context,
|
||||||
domain['id'],
|
zone['id'],
|
||||||
recordset['id'],
|
recordset['id'],
|
||||||
Record(**record_values))
|
Record(**record_values))
|
||||||
|
|
||||||
def _delete(self, domain_id, managed=True, resource_id=None,
|
def _delete(self, zone_id, managed=True, resource_id=None,
|
||||||
resource_type='instance', criterion=None):
|
resource_type='instance', criterion=None):
|
||||||
"""
|
"""
|
||||||
Handle a generic delete of a fixed ip within a domain
|
Handle a generic delete of a fixed ip within a zone
|
||||||
|
|
||||||
:param criterion: Criterion to search and destroy records
|
:param criterion: Criterion to search and destroy records
|
||||||
"""
|
"""
|
||||||
@ -184,7 +184,7 @@ class BaseAddressHandler(NotificationHandler):
|
|||||||
context.all_tenants = True
|
context.all_tenants = True
|
||||||
context.edit_managed_records = True
|
context.edit_managed_records = True
|
||||||
|
|
||||||
criterion.update({'domain_id': domain_id})
|
criterion.update({'zone_id': zone_id})
|
||||||
|
|
||||||
if managed:
|
if managed:
|
||||||
criterion.update({
|
criterion.update({
|
||||||
@ -201,6 +201,6 @@ class BaseAddressHandler(NotificationHandler):
|
|||||||
LOG.debug('Deleting record %s' % record['id'])
|
LOG.debug('Deleting record %s' % record['id'])
|
||||||
|
|
||||||
self.central_api.delete_record(context,
|
self.central_api.delete_record(context,
|
||||||
domain_id,
|
zone_id,
|
||||||
record['recordset_id'],
|
record['recordset_id'],
|
||||||
record['id'])
|
record['id'])
|
||||||
|
@ -29,9 +29,9 @@ cfg.CONF.register_group(cfg.OptGroup(
|
|||||||
cfg.CONF.register_opts([
|
cfg.CONF.register_opts([
|
||||||
cfg.ListOpt('notification-topics', default=['notifications']),
|
cfg.ListOpt('notification-topics', default=['notifications']),
|
||||||
cfg.StrOpt('control-exchange', default='neutron'),
|
cfg.StrOpt('control-exchange', default='neutron'),
|
||||||
cfg.StrOpt('domain-id'),
|
cfg.StrOpt('zone-id'),
|
||||||
cfg.MultiStrOpt('format', default=[
|
cfg.MultiStrOpt('format', default=[
|
||||||
'%(octet0)s-%(octet1)s-%(octet2)s-%(octet3)s.%(domain)s'])
|
'%(octet0)s-%(octet1)s-%(octet2)s-%(octet3)s.%(zone)s'])
|
||||||
], group='handler:neutron_floatingip')
|
], group='handler:neutron_floatingip')
|
||||||
|
|
||||||
|
|
||||||
@ -56,9 +56,9 @@ class NeutronFloatingHandler(BaseAddressHandler):
|
|||||||
LOG.debug('%s received notification - %s' %
|
LOG.debug('%s received notification - %s' %
|
||||||
(self.get_canonical_name(), event_type))
|
(self.get_canonical_name(), event_type))
|
||||||
|
|
||||||
domain_id = cfg.CONF[self.name].domain_id
|
zone_id = cfg.CONF[self.name].zone_id
|
||||||
if event_type.startswith('floatingip.delete'):
|
if event_type.startswith('floatingip.delete'):
|
||||||
self._delete(domain_id=domain_id,
|
self._delete(zone_id=zone_id,
|
||||||
resource_id=payload['floatingip_id'],
|
resource_id=payload['floatingip_id'],
|
||||||
resource_type='floatingip')
|
resource_type='floatingip')
|
||||||
elif event_type.startswith('floatingip.update'):
|
elif event_type.startswith('floatingip.update'):
|
||||||
@ -69,10 +69,10 @@ class NeutronFloatingHandler(BaseAddressHandler):
|
|||||||
}
|
}
|
||||||
self._create(addresses=[address],
|
self._create(addresses=[address],
|
||||||
extra=payload['floatingip'],
|
extra=payload['floatingip'],
|
||||||
domain_id=domain_id,
|
zone_id=zone_id,
|
||||||
resource_id=payload['floatingip']['id'],
|
resource_id=payload['floatingip']['id'],
|
||||||
resource_type='floatingip')
|
resource_type='floatingip')
|
||||||
elif not payload['floatingip']['fixed_ip_address']:
|
elif not payload['floatingip']['fixed_ip_address']:
|
||||||
self._delete(domain_id=domain_id,
|
self._delete(zone_id=zone_id,
|
||||||
resource_id=payload['floatingip']['id'],
|
resource_id=payload['floatingip']['id'],
|
||||||
resource_type='floatingip')
|
resource_type='floatingip')
|
||||||
|
@ -29,9 +29,9 @@ cfg.CONF.register_group(cfg.OptGroup(
|
|||||||
cfg.CONF.register_opts([
|
cfg.CONF.register_opts([
|
||||||
cfg.ListOpt('notification-topics', default=['notifications']),
|
cfg.ListOpt('notification-topics', default=['notifications']),
|
||||||
cfg.StrOpt('control-exchange', default='nova'),
|
cfg.StrOpt('control-exchange', default='nova'),
|
||||||
cfg.StrOpt('domain-id'),
|
cfg.StrOpt('zone-id'),
|
||||||
cfg.MultiStrOpt('format', default=[
|
cfg.MultiStrOpt('format', default=[
|
||||||
'%(octet0)s-%(octet1)s-%(octet2)s-%(octet3)s.%(domain)s'])
|
'%(octet0)s-%(octet1)s-%(octet2)s-%(octet3)s.%(zone)s'])
|
||||||
], group='handler:nova_fixed')
|
], group='handler:nova_fixed')
|
||||||
|
|
||||||
|
|
||||||
@ -60,15 +60,15 @@ class NovaFixedHandler(BaseAddressHandler):
|
|||||||
def process_notification(self, context, event_type, payload):
|
def process_notification(self, context, event_type, payload):
|
||||||
LOG.debug('NovaFixedHandler received notification - %s' % event_type)
|
LOG.debug('NovaFixedHandler received notification - %s' % event_type)
|
||||||
|
|
||||||
domain_id = cfg.CONF[self.name].domain_id
|
zone_id = cfg.CONF[self.name].zone_id
|
||||||
if event_type == 'compute.instance.create.end':
|
if event_type == 'compute.instance.create.end':
|
||||||
self._create(addresses=payload['fixed_ips'],
|
self._create(addresses=payload['fixed_ips'],
|
||||||
extra=payload,
|
extra=payload,
|
||||||
domain_id=domain_id,
|
zone_id=zone_id,
|
||||||
resource_id=payload['instance_id'],
|
resource_id=payload['instance_id'],
|
||||||
resource_type='instance')
|
resource_type='instance')
|
||||||
|
|
||||||
elif event_type == 'compute.instance.delete.start':
|
elif event_type == 'compute.instance.delete.start':
|
||||||
self._delete(domain_id=domain_id,
|
self._delete(zone_id=zone_id,
|
||||||
resource_id=payload['instance_id'],
|
resource_id=payload['instance_id'],
|
||||||
resource_type='instance')
|
resource_type='instance')
|
||||||
|
@ -12,16 +12,14 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
from designate.objects.base import DesignateObject # noqa
|
from designate.objects.base import DesignateObject # noqa
|
||||||
from designate.objects.base import DictObjectMixin # noqa
|
from designate.objects.base import DictObjectMixin # noqa
|
||||||
from designate.objects.base import ListObjectMixin # noqa
|
from designate.objects.base import ListObjectMixin # noqa
|
||||||
from designate.objects.base import PagedListObjectMixin # noqa
|
from designate.objects.base import PagedListObjectMixin # noqa
|
||||||
from designate.objects.blacklist import Blacklist, BlacklistList # noqa
|
from designate.objects.blacklist import Blacklist, BlacklistList # noqa
|
||||||
from designate.objects.domain import Domain, DomainList # noqa
|
from designate.objects.zone import Zone, ZoneList # noqa
|
||||||
from designate.objects.domain_attribute import DomainAttribute, DomainAttributeList # noqa
|
from designate.objects.zone_attribute import ZoneAttribute, ZoneAttributeList # noqa
|
||||||
from designate.objects.domain_master import DomainMaster, DomainMasterList # noqa
|
from designate.objects.zone_master import ZoneMaster, ZoneMasterList # noqa
|
||||||
from designate.objects.floating_ip import FloatingIP, FloatingIPList # noqa
|
from designate.objects.floating_ip import FloatingIP, FloatingIPList # noqa
|
||||||
from designate.objects.pool_manager_status import PoolManagerStatus, PoolManagerStatusList # noqa
|
from designate.objects.pool_manager_status import PoolManagerStatus, PoolManagerStatusList # noqa
|
||||||
from designate.objects.pool import Pool, PoolList # noqa
|
from designate.objects.pool import Pool, PoolList # noqa
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
from designate.objects.adapters.base import DesignateAdapter # noqa
|
from designate.objects.adapters.base import DesignateAdapter # noqa
|
||||||
# API v2
|
# API v2
|
||||||
from designate.objects.adapters.api_v2.blacklist import BlacklistAPIv2Adapter, BlacklistListAPIv2Adapter # noqa
|
from designate.objects.adapters.api_v2.blacklist import BlacklistAPIv2Adapter, BlacklistListAPIv2Adapter # noqa
|
||||||
from designate.objects.adapters.api_v2.domain import DomainAPIv2Adapter, DomainListAPIv2Adapter # noqa
|
from designate.objects.adapters.api_v2.zone import ZoneAPIv2Adapter, ZoneListAPIv2Adapter # noqa
|
||||||
from designate.objects.adapters.api_v2.domain_master import DomainMasterAPIv2Adapter, DomainMasterListAPIv2Adapter # noqa
|
from designate.objects.adapters.api_v2.zone_master import ZoneMasterAPIv2Adapter, ZoneMasterListAPIv2Adapter # noqa
|
||||||
from designate.objects.adapters.api_v2.floating_ip import FloatingIPAPIv2Adapter, FloatingIPListAPIv2Adapter # noqa
|
from designate.objects.adapters.api_v2.floating_ip import FloatingIPAPIv2Adapter, FloatingIPListAPIv2Adapter # noqa
|
||||||
from designate.objects.adapters.api_v2.record import RecordAPIv2Adapter, RecordListAPIv2Adapter # noqa
|
from designate.objects.adapters.api_v2.record import RecordAPIv2Adapter, RecordListAPIv2Adapter # noqa
|
||||||
from designate.objects.adapters.api_v2.recordset import RecordSetAPIv2Adapter, RecordSetListAPIv2Adapter # noqa
|
from designate.objects.adapters.api_v2.recordset import RecordSetAPIv2Adapter, RecordSetListAPIv2Adapter # noqa
|
||||||
|
@ -27,7 +27,7 @@ class RecordSetAPIv2Adapter(base.APIv2Adapter):
|
|||||||
'fields': {
|
'fields': {
|
||||||
"id": {},
|
"id": {},
|
||||||
"zone_id": {
|
"zone_id": {
|
||||||
'rename': 'domain_id'
|
'rename': 'zone_id'
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
'immutable': True
|
'immutable': True
|
||||||
|
@ -19,9 +19,9 @@ from designate import objects
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DomainAPIv2Adapter(base.APIv2Adapter):
|
class ZoneAPIv2Adapter(base.APIv2Adapter):
|
||||||
|
|
||||||
ADAPTER_OBJECT = objects.Domain
|
ADAPTER_OBJECT = objects.Zone
|
||||||
|
|
||||||
MODIFICATIONS = {
|
MODIFICATIONS = {
|
||||||
'fields': {
|
'fields': {
|
||||||
@ -69,18 +69,18 @@ class DomainAPIv2Adapter(base.APIv2Adapter):
|
|||||||
object.masters = objects.adapters.DesignateAdapter.parse(
|
object.masters = objects.adapters.DesignateAdapter.parse(
|
||||||
cls.ADAPTER_FORMAT,
|
cls.ADAPTER_FORMAT,
|
||||||
values['masters'],
|
values['masters'],
|
||||||
objects.DomainMasterList(),
|
objects.ZoneMasterList(),
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
|
|
||||||
del values['masters']
|
del values['masters']
|
||||||
|
|
||||||
return super(DomainAPIv2Adapter, cls)._parse_object(
|
return super(ZoneAPIv2Adapter, cls)._parse_object(
|
||||||
values, object, *args, **kwargs)
|
values, object, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class DomainListAPIv2Adapter(base.APIv2Adapter):
|
class ZoneListAPIv2Adapter(base.APIv2Adapter):
|
||||||
|
|
||||||
ADAPTER_OBJECT = objects.DomainList
|
ADAPTER_OBJECT = objects.ZoneList
|
||||||
|
|
||||||
MODIFICATIONS = {
|
MODIFICATIONS = {
|
||||||
'options': {
|
'options': {
|
@ -31,7 +31,7 @@ class ZoneExportAPIv2Adapter(base.APIv2Adapter):
|
|||||||
"message": {},
|
"message": {},
|
||||||
"location": {},
|
"location": {},
|
||||||
"zone_id": {
|
"zone_id": {
|
||||||
'rename': 'domain_id',
|
'rename': 'zone_id',
|
||||||
},
|
},
|
||||||
"project_id": {
|
"project_id": {
|
||||||
'rename': 'tenant_id'
|
'rename': 'tenant_id'
|
||||||
|
@ -30,7 +30,7 @@ class ZoneImportAPIv2Adapter(base.APIv2Adapter):
|
|||||||
"status": {},
|
"status": {},
|
||||||
"message": {},
|
"message": {},
|
||||||
"zone_id": {
|
"zone_id": {
|
||||||
'rename': 'domain_id',
|
'rename': 'zone_id',
|
||||||
},
|
},
|
||||||
"project_id": {
|
"project_id": {
|
||||||
'rename': 'tenant_id'
|
'rename': 'tenant_id'
|
||||||
|
@ -19,9 +19,9 @@ from designate import utils
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DomainMasterAPIv2Adapter(base.APIv2Adapter):
|
class ZoneMasterAPIv2Adapter(base.APIv2Adapter):
|
||||||
|
|
||||||
ADAPTER_OBJECT = objects.DomainMaster
|
ADAPTER_OBJECT = objects.ZoneMaster
|
||||||
|
|
||||||
MODIFICATIONS = {
|
MODIFICATIONS = {
|
||||||
'fields': {
|
'fields': {
|
||||||
@ -49,9 +49,9 @@ class DomainMasterAPIv2Adapter(base.APIv2Adapter):
|
|||||||
return object
|
return object
|
||||||
|
|
||||||
|
|
||||||
class DomainMasterListAPIv2Adapter(base.APIv2Adapter):
|
class ZoneMasterListAPIv2Adapter(base.APIv2Adapter):
|
||||||
|
|
||||||
ADAPTER_OBJECT = objects.DomainMasterList
|
ADAPTER_OBJECT = objects.ZoneMasterList
|
||||||
|
|
||||||
MODIFICATIONS = {
|
MODIFICATIONS = {
|
||||||
'options': {
|
'options': {
|
@ -36,7 +36,7 @@ class ZoneTransferAcceptAPIv2Adapter(base.APIv2Adapter):
|
|||||||
},
|
},
|
||||||
"status": {},
|
"status": {},
|
||||||
"zone_id": {
|
"zone_id": {
|
||||||
'rename': 'domain_id',
|
'rename': 'zone_id',
|
||||||
},
|
},
|
||||||
"created_at": {},
|
"created_at": {},
|
||||||
"updated_at": {},
|
"updated_at": {},
|
||||||
|
@ -30,7 +30,6 @@ class ZoneTransferRequestAPIv2Adapter(base.APIv2Adapter):
|
|||||||
'protected': False
|
'protected': False
|
||||||
},
|
},
|
||||||
"zone_id": {
|
"zone_id": {
|
||||||
'rename': 'domain_id',
|
|
||||||
'immutable': True,
|
'immutable': True,
|
||||||
'protected': False
|
'protected': False
|
||||||
},
|
},
|
||||||
@ -50,7 +49,6 @@ class ZoneTransferRequestAPIv2Adapter(base.APIv2Adapter):
|
|||||||
'protected': False
|
'protected': False
|
||||||
},
|
},
|
||||||
"zone_name": {
|
"zone_name": {
|
||||||
'rename': 'domain_name',
|
|
||||||
'protected': False
|
'protected': False
|
||||||
},
|
},
|
||||||
"created_at": {},
|
"created_at": {},
|
||||||
|
@ -209,7 +209,7 @@ class DesignateAdapter(object):
|
|||||||
##############################################################
|
##############################################################
|
||||||
|
|
||||||
# Check if the field should be allowed change after it is
|
# Check if the field should be allowed change after it is
|
||||||
# initially set (eg domain name)
|
# initially set (eg zone name)
|
||||||
if cls.MODIFICATIONS['fields'][key].get('immutable', False):
|
if cls.MODIFICATIONS['fields'][key].get('immutable', False):
|
||||||
if getattr(output_object, obj_key, False) and \
|
if getattr(output_object, obj_key, False) and \
|
||||||
getattr(output_object, obj_key) != value:
|
getattr(output_object, obj_key) != value:
|
||||||
|
@ -26,7 +26,7 @@ class PoolManagerStatus(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
},
|
},
|
||||||
'required': True
|
'required': True
|
||||||
},
|
},
|
||||||
'domain_id': {
|
'zone_id': {
|
||||||
'schema': {
|
'schema': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
'format': 'uuid',
|
'format': 'uuid',
|
||||||
@ -54,7 +54,7 @@ class PoolManagerStatus(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
STRING_KEYS = [
|
STRING_KEYS = [
|
||||||
'id', 'action', 'status', 'server_id', 'domain_id'
|
'id', 'action', 'status', 'server_id', 'zone_id'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class Record(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'data': {},
|
'data': {},
|
||||||
'domain_id': {
|
'zone_id': {
|
||||||
'schema': {
|
'schema': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
'format': 'uuid',
|
'format': 'uuid',
|
||||||
|
@ -84,7 +84,7 @@ class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
},
|
},
|
||||||
'read_only': True
|
'read_only': True
|
||||||
},
|
},
|
||||||
'domain_id': {
|
'zone_id': {
|
||||||
'schema': {
|
'schema': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
'description': 'Zone identifier',
|
'description': 'Zone identifier',
|
||||||
@ -277,7 +277,7 @@ class RecordSet(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
self.records = old_records
|
self.records = old_records
|
||||||
|
|
||||||
STRING_KEYS = [
|
STRING_KEYS = [
|
||||||
'id', 'type', 'name', 'domain_id'
|
'id', 'type', 'name', 'zone_id'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@ from designate.objects import base
|
|||||||
class Tenant(base.DictObjectMixin, base.DesignateObject):
|
class Tenant(base.DictObjectMixin, base.DesignateObject):
|
||||||
FIELDS = {
|
FIELDS = {
|
||||||
'id': {},
|
'id': {},
|
||||||
'domain_count': {},
|
'zone_count': {},
|
||||||
'domains': {}
|
'zones': {}
|
||||||
}
|
}
|
||||||
|
|
||||||
STRING_KEYS = [
|
STRING_KEYS = [
|
||||||
|
@ -19,8 +19,8 @@ from designate.objects.validation_error import ValidationError
|
|||||||
from designate.objects.validation_error import ValidationErrorList
|
from designate.objects.validation_error import ValidationErrorList
|
||||||
|
|
||||||
|
|
||||||
class Domain(base.DictObjectMixin, base.SoftDeleteObjectMixin,
|
class Zone(base.DictObjectMixin, base.SoftDeleteObjectMixin,
|
||||||
base.PersistentObjectMixin, base.DesignateObject):
|
base.PersistentObjectMixin, base.DesignateObject):
|
||||||
FIELDS = {
|
FIELDS = {
|
||||||
'shard': {
|
'shard': {
|
||||||
'schema': {
|
'schema': {
|
||||||
@ -93,7 +93,7 @@ class Domain(base.DictObjectMixin, base.SoftDeleteObjectMixin,
|
|||||||
},
|
},
|
||||||
'read_only': True
|
'read_only': True
|
||||||
},
|
},
|
||||||
'parent_domain_id': {
|
'parent_zone_id': {
|
||||||
'schema': {
|
'schema': {
|
||||||
'type': ['string', 'null'],
|
'type': ['string', 'null'],
|
||||||
'format': 'uuid'
|
'format': 'uuid'
|
||||||
@ -141,11 +141,11 @@ class Domain(base.DictObjectMixin, base.SoftDeleteObjectMixin,
|
|||||||
},
|
},
|
||||||
'attributes': {
|
'attributes': {
|
||||||
'relation': True,
|
'relation': True,
|
||||||
'relation_cls': 'DomainAttributeList'
|
'relation_cls': 'ZoneAttributeList'
|
||||||
},
|
},
|
||||||
'masters': {
|
'masters': {
|
||||||
'relation': True,
|
'relation': True,
|
||||||
'relation_cls': 'DomainMasterList'
|
'relation_cls': 'ZoneMasterList'
|
||||||
},
|
},
|
||||||
'type': {
|
'type': {
|
||||||
'schema': {
|
'schema': {
|
||||||
@ -169,7 +169,7 @@ class Domain(base.DictObjectMixin, base.SoftDeleteObjectMixin,
|
|||||||
|
|
||||||
def get_master_by_ip(self, host):
|
def get_master_by_ip(self, host):
|
||||||
"""
|
"""
|
||||||
Utility to get the master by it's ip for this domain.
|
Utility to get the master by it's ip for this zone.
|
||||||
"""
|
"""
|
||||||
for srv in self.masters:
|
for srv in self.masters:
|
||||||
srv_host, _ = utils.split_host_port(srv.to_data())
|
srv_host, _ = utils.split_host_port(srv.to_data())
|
||||||
@ -224,7 +224,7 @@ class Domain(base.DictObjectMixin, base.SoftDeleteObjectMixin,
|
|||||||
errors.append(e)
|
errors.append(e)
|
||||||
self._raise(errors)
|
self._raise(errors)
|
||||||
|
|
||||||
super(Domain, self).validate()
|
super(Zone, self).validate()
|
||||||
except exceptions.RelationNotLoaded as ex:
|
except exceptions.RelationNotLoaded as ex:
|
||||||
errors = ValidationErrorList()
|
errors = ValidationErrorList()
|
||||||
e = ValidationError()
|
e = ValidationError()
|
||||||
@ -236,6 +236,6 @@ class Domain(base.DictObjectMixin, base.SoftDeleteObjectMixin,
|
|||||||
self._raise(errors)
|
self._raise(errors)
|
||||||
|
|
||||||
|
|
||||||
class DomainList(base.ListObjectMixin, base.DesignateObject,
|
class ZoneList(base.ListObjectMixin, base.DesignateObject,
|
||||||
base.PagedListObjectMixin):
|
base.PagedListObjectMixin):
|
||||||
LIST_ITEM_TYPE = Domain
|
LIST_ITEM_TYPE = Zone
|
@ -16,18 +16,18 @@
|
|||||||
from designate.objects import base
|
from designate.objects import base
|
||||||
|
|
||||||
|
|
||||||
class DomainAttribute(base.DictObjectMixin, base.PersistentObjectMixin,
|
class ZoneAttribute(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||||
base.DesignateObject):
|
base.DesignateObject):
|
||||||
FIELDS = {
|
FIELDS = {
|
||||||
'domain_id': {},
|
'zone_id': {},
|
||||||
'key': {},
|
'key': {},
|
||||||
'value': {}
|
'value': {}
|
||||||
}
|
}
|
||||||
|
|
||||||
STRING_KEYS = [
|
STRING_KEYS = [
|
||||||
'id', 'key', 'value', 'domain_id'
|
'id', 'key', 'value', 'zone_id'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class DomainAttributeList(base.ListObjectMixin, base.DesignateObject):
|
class ZoneAttributeList(base.ListObjectMixin, base.DesignateObject):
|
||||||
LIST_ITEM_TYPE = DomainAttribute
|
LIST_ITEM_TYPE = ZoneAttribute
|
@ -53,7 +53,7 @@ class ZoneExport(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
},
|
},
|
||||||
'read_only': True
|
'read_only': True
|
||||||
},
|
},
|
||||||
'domain_id': {
|
'zone_id': {
|
||||||
'schema': {
|
'schema': {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid"
|
"format": "uuid"
|
||||||
|
@ -46,7 +46,7 @@ class ZoneImport(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
},
|
},
|
||||||
'read_only': True
|
'read_only': True
|
||||||
},
|
},
|
||||||
'domain_id': {
|
'zone_id': {
|
||||||
'schema': {
|
'schema': {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid"
|
"format": "uuid"
|
||||||
|
@ -17,10 +17,10 @@ from designate.objects import base
|
|||||||
from designate import utils
|
from designate import utils
|
||||||
|
|
||||||
|
|
||||||
class DomainMaster(base.DictObjectMixin, base.PersistentObjectMixin,
|
class ZoneMaster(base.DictObjectMixin, base.PersistentObjectMixin,
|
||||||
base.DesignateObject):
|
base.DesignateObject):
|
||||||
FIELDS = {
|
FIELDS = {
|
||||||
'domain_id': {},
|
'zone_id': {},
|
||||||
'host': {
|
'host': {
|
||||||
'schema': {
|
'schema': {
|
||||||
'type': 'string',
|
'type': 'string',
|
||||||
@ -47,8 +47,8 @@ class DomainMaster(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
return cls.from_dict({"host": host, "port": port})
|
return cls.from_dict({"host": host, "port": port})
|
||||||
|
|
||||||
|
|
||||||
class DomainMasterList(base.ListObjectMixin, base.DesignateObject):
|
class ZoneMasterList(base.ListObjectMixin, base.DesignateObject):
|
||||||
LIST_ITEM_TYPE = DomainMaster
|
LIST_ITEM_TYPE = ZoneMaster
|
||||||
|
|
||||||
def to_data(self):
|
def to_data(self):
|
||||||
rlist = []
|
rlist = []
|
@ -46,7 +46,7 @@ class ZoneTransferAccept(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
},
|
},
|
||||||
'required': True
|
'required': True
|
||||||
},
|
},
|
||||||
'domain_id': {
|
'zone_id': {
|
||||||
'schema': {
|
'schema': {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid"
|
"format": "uuid"
|
||||||
@ -56,7 +56,7 @@ class ZoneTransferAccept(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
STRING_KEYS = [
|
STRING_KEYS = [
|
||||||
'id', 'domain_id', 'tenant_id', 'zone_transfer_request_id'
|
'id', 'zone_id', 'tenant_id', 'zone_transfer_request_id'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class ZoneTransferRequest(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
"maxLength": 160
|
"maxLength": 160
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'domain_id': {
|
'zone_id': {
|
||||||
'schema': {
|
'schema': {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Zone identifier",
|
"description": "Zone identifier",
|
||||||
@ -57,7 +57,7 @@ class ZoneTransferRequest(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
"enum": ["ACTIVE", "PENDING", "DELETED", "ERROR", "COMPLETE"],
|
"enum": ["ACTIVE", "PENDING", "DELETED", "ERROR", "COMPLETE"],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'domain_name': {
|
'zone_name': {
|
||||||
'schema': {
|
'schema': {
|
||||||
"type": ["string", "null"],
|
"type": ["string", "null"],
|
||||||
"maxLength": 255,
|
"maxLength": 255,
|
||||||
@ -67,7 +67,7 @@ class ZoneTransferRequest(base.DictObjectMixin, base.PersistentObjectMixin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
STRING_KEYS = [
|
STRING_KEYS = [
|
||||||
'id', 'domain_id', 'domain_name', 'target_tenant_id'
|
'id', 'zone_id', 'zone_name', 'target_tenant_id'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ OPTS = [
|
|||||||
'Pool Manager'),
|
'Pool Manager'),
|
||||||
cfg.IntOpt('threshold-percentage', default=100,
|
cfg.IntOpt('threshold-percentage', default=100,
|
||||||
help='The percentage of servers requiring a successful update '
|
help='The percentage of servers requiring a successful update '
|
||||||
'for a domain change to be considered active'),
|
'for a zone change to be considered active'),
|
||||||
cfg.IntOpt('poll-timeout', default=30,
|
cfg.IntOpt('poll-timeout', default=30,
|
||||||
help='The time to wait for a response from a server'),
|
help='The time to wait for a response from a server'),
|
||||||
cfg.IntOpt('poll-retry-interval', default=15,
|
cfg.IntOpt('poll-retry-interval', default=15,
|
||||||
|
4
designate/pool_manager/cache/base.py
vendored
4
designate/pool_manager/cache/base.py
vendored
@ -49,7 +49,7 @@ class PoolManagerCache(DriverPlugin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def retrieve(self, context, nameserver_id, domain_id, action):
|
def retrieve(self, context, nameserver_id, zone_id, action):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Retrieve the pool manager status object.
|
Retrieve the pool manager status object.
|
||||||
@ -57,7 +57,7 @@ class PoolManagerCache(DriverPlugin):
|
|||||||
:param context: Security context information
|
:param context: Security context information
|
||||||
:param nameserver_id: the nameserver ID of the pool manager status
|
:param nameserver_id: the nameserver ID of the pool manager status
|
||||||
object
|
object
|
||||||
:param domain_id: the domain ID of the pool manger status object
|
:param zone_id: the zone ID of the pool manger status object
|
||||||
:param action: the action of the pool manager status object
|
:param action: the action of the pool manager status object
|
||||||
:return: the pool manager status object
|
:return: the pool manager status object
|
||||||
"""
|
"""
|
||||||
|
@ -75,10 +75,10 @@ class MemcachePoolManagerCache(cache_base.PoolManagerCache):
|
|||||||
serial_number_key, pool_manager_status.serial_number,
|
serial_number_key, pool_manager_status.serial_number,
|
||||||
self.expiration)
|
self.expiration)
|
||||||
|
|
||||||
def retrieve(self, context, nameserver_id, domain_id, action):
|
def retrieve(self, context, nameserver_id, zone_id, action):
|
||||||
values = {
|
values = {
|
||||||
'nameserver_id': nameserver_id,
|
'nameserver_id': nameserver_id,
|
||||||
'domain_id': domain_id,
|
'zone_id': zone_id,
|
||||||
'action': action,
|
'action': action,
|
||||||
}
|
}
|
||||||
pool_manager_status = objects.PoolManagerStatus(**values)
|
pool_manager_status = objects.PoolManagerStatus(**values)
|
||||||
@ -103,9 +103,9 @@ class MemcachePoolManagerCache(cache_base.PoolManagerCache):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _status_key(pool_manager_status, tail):
|
def _status_key(pool_manager_status, tail):
|
||||||
key = '{nameserver}-{domain}-{action}-{tail}'.format(
|
key = '{nameserver}-{zone}-{action}-{tail}'.format(
|
||||||
nameserver=pool_manager_status.nameserver_id,
|
nameserver=pool_manager_status.nameserver_id,
|
||||||
domain=pool_manager_status.domain_id,
|
zone=pool_manager_status.zone_id,
|
||||||
action=pool_manager_status.action,
|
action=pool_manager_status.action,
|
||||||
tail=tail
|
tail=tail
|
||||||
)
|
)
|
||||||
|
@ -32,5 +32,5 @@ class NoopPoolManagerCache(cache_base.PoolManagerCache):
|
|||||||
def store(self, context, pool_manager_status):
|
def store(self, context, pool_manager_status):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def retrieve(self, context, nameserver_id, domain_id, action):
|
def retrieve(self, context, nameserver_id, zone_id, action):
|
||||||
raise exceptions.PoolManagerStatusNotFound
|
raise exceptions.PoolManagerStatusNotFound
|
||||||
|
@ -50,7 +50,7 @@ class SQLAlchemyPoolManagerCache(sqlalchemy_base.SQLAlchemy,
|
|||||||
if not pool_manager_status.id:
|
if not pool_manager_status.id:
|
||||||
pool_manager_status = self.retrieve(
|
pool_manager_status = self.retrieve(
|
||||||
context, pool_manager_status.nameserver_id,
|
context, pool_manager_status.nameserver_id,
|
||||||
pool_manager_status.domain_id, pool_manager_status.action)
|
pool_manager_status.zone_id, pool_manager_status.action)
|
||||||
self._delete(
|
self._delete(
|
||||||
context, tables.pool_manager_statuses, pool_manager_status,
|
context, tables.pool_manager_statuses, pool_manager_status,
|
||||||
exceptions.PoolManagerStatusNotFound)
|
exceptions.PoolManagerStatusNotFound)
|
||||||
@ -66,10 +66,10 @@ class SQLAlchemyPoolManagerCache(sqlalchemy_base.SQLAlchemy,
|
|||||||
tables.pool_manager_statuses, pool_manager_status,
|
tables.pool_manager_statuses, pool_manager_status,
|
||||||
exceptions.DuplicatePoolManagerStatus)
|
exceptions.DuplicatePoolManagerStatus)
|
||||||
|
|
||||||
def retrieve(self, context, nameserver_id, domain_id, action):
|
def retrieve(self, context, nameserver_id, zone_id, action):
|
||||||
criterion = {
|
criterion = {
|
||||||
'nameserver_id': nameserver_id,
|
'nameserver_id': nameserver_id,
|
||||||
'domain_id': domain_id,
|
'zone_id': zone_id,
|
||||||
'action': action
|
'action': action
|
||||||
}
|
}
|
||||||
return self._find(
|
return self._find(
|
||||||
|
34
designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/008_domain_to_zone_rename.py
vendored
Normal file
34
designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/008_domain_to_zone_rename.py
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# Author: Kiall Mac Innes <kiall@hp.com>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
# See https://blueprints.launchpad.net/nova/+spec/backportable-db-migrations
|
||||||
|
# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
|
||||||
|
from sqlalchemy.schema import Table, MetaData
|
||||||
|
|
||||||
|
|
||||||
|
meta = MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
status_table = Table('pool_manager_statuses', meta, autoload=True)
|
||||||
|
|
||||||
|
status_table.c.domain_id.alter(name='zone_id')
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migration_engine):
|
||||||
|
pass
|
@ -33,7 +33,7 @@ pool_manager_statuses = Table(
|
|||||||
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
||||||
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
||||||
Column('nameserver_id', UUID, nullable=False),
|
Column('nameserver_id', UUID, nullable=False),
|
||||||
Column('domain_id', UUID, nullable=False),
|
Column('zone_id', UUID, nullable=False),
|
||||||
Column('action', Enum(name='update_actions', *UPDATE_ACTIONS),
|
Column('action', Enum(name='update_actions', *UPDATE_ACTIONS),
|
||||||
nullable=False),
|
nullable=False),
|
||||||
Column('status', Enum(name='update_statuses', *UPDATE_STATUSES),
|
Column('status', Enum(name='update_statuses', *UPDATE_STATUSES),
|
||||||
@ -41,9 +41,9 @@ pool_manager_statuses = Table(
|
|||||||
Column('serial_number', Integer, nullable=False),
|
Column('serial_number', Integer, nullable=False),
|
||||||
|
|
||||||
|
|
||||||
UniqueConstraint('nameserver_id', 'domain_id', 'action',
|
UniqueConstraint('nameserver_id', 'zone_id', 'action',
|
||||||
name='unique_pool_manager_status'),
|
name='unique_pool_manager_status'),
|
||||||
ForeignKeyConstraint(['domain_id'], ['domains.id']),
|
ForeignKeyConstraint(['zone_id'], ['zones.id']),
|
||||||
|
|
||||||
mysql_engine='InnoDB',
|
mysql_engine='InnoDB',
|
||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
|
@ -35,15 +35,16 @@ class PoolManagerAPI(object):
|
|||||||
API version history:
|
API version history:
|
||||||
|
|
||||||
1.0 - Initial version
|
1.0 - Initial version
|
||||||
|
2.0 - Rename domains to zones
|
||||||
"""
|
"""
|
||||||
RPC_API_VERSION = '1.0'
|
RPC_API_VERSION = '2.0'
|
||||||
|
|
||||||
def __init__(self, topic=None):
|
def __init__(self, topic=None):
|
||||||
self.topic = topic if topic else cfg.CONF.pool_manager_topic
|
self.topic = topic if topic else cfg.CONF.pool_manager_topic
|
||||||
|
|
||||||
target = messaging.Target(topic=self.topic,
|
target = messaging.Target(topic=self.topic,
|
||||||
version=self.RPC_API_VERSION)
|
version=self.RPC_API_VERSION)
|
||||||
self.client = rpc.get_client(target, version_cap='1.0')
|
self.client = rpc.get_client(target, version_cap='2.0')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_instance(cls):
|
def get_instance(cls):
|
||||||
@ -59,51 +60,51 @@ class PoolManagerAPI(object):
|
|||||||
MNGR_API = cls()
|
MNGR_API = cls()
|
||||||
return MNGR_API
|
return MNGR_API
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
LOG.info(_LI("create_domain: Calling pool manager for %(domain)s, "
|
LOG.info(_LI("create_zone: Calling pool manager for %(zone)s, "
|
||||||
"serial:%(serial)s") %
|
"serial:%(serial)s") %
|
||||||
{'domain': domain.name, 'serial': domain.serial})
|
{'zone': zone.name, 'serial': zone.serial})
|
||||||
|
|
||||||
# Modifying the topic so it is pool manager instance specific.
|
# Modifying the topic so it is pool manager instance specific.
|
||||||
topic = '%s.%s' % (self.topic, domain.pool_id)
|
topic = '%s.%s' % (self.topic, zone.pool_id)
|
||||||
cctxt = self.client.prepare(topic=topic)
|
cctxt = self.client.prepare(topic=topic)
|
||||||
return cctxt.cast(
|
return cctxt.cast(
|
||||||
context, 'create_domain', domain=domain)
|
context, 'create_zone', zone=zone)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
LOG.info(_LI("delete_domain: Calling pool manager for %(domain)s, "
|
LOG.info(_LI("delete_zone: Calling pool manager for %(zone)s, "
|
||||||
"serial:%(serial)s") %
|
"serial:%(serial)s") %
|
||||||
{'domain': domain.name, 'serial': domain.serial})
|
{'zone': zone.name, 'serial': zone.serial})
|
||||||
|
|
||||||
# Modifying the topic so it is pool manager instance specific.
|
# Modifying the topic so it is pool manager instance specific.
|
||||||
topic = '%s.%s' % (self.topic, domain.pool_id)
|
topic = '%s.%s' % (self.topic, zone.pool_id)
|
||||||
cctxt = self.client.prepare(topic=topic)
|
cctxt = self.client.prepare(topic=topic)
|
||||||
return cctxt.cast(
|
return cctxt.cast(
|
||||||
context, 'delete_domain', domain=domain)
|
context, 'delete_zone', zone=zone)
|
||||||
|
|
||||||
def update_domain(self, context, domain):
|
def update_zone(self, context, zone):
|
||||||
LOG.info(_LI("update_domain: Calling pool manager for %(domain)s, "
|
LOG.info(_LI("update_zone: Calling pool manager for %(zone)s, "
|
||||||
"serial:%(serial)s") %
|
"serial:%(serial)s") %
|
||||||
{'domain': domain.name, 'serial': domain.serial})
|
{'zone': zone.name, 'serial': zone.serial})
|
||||||
|
|
||||||
# Modifying the topic so it is pool manager instance specific.
|
# Modifying the topic so it is pool manager instance specific.
|
||||||
topic = '%s.%s' % (self.topic, domain.pool_id)
|
topic = '%s.%s' % (self.topic, zone.pool_id)
|
||||||
cctxt = self.client.prepare(topic=topic)
|
cctxt = self.client.prepare(topic=topic)
|
||||||
return cctxt.cast(
|
return cctxt.cast(
|
||||||
context, 'update_domain', domain=domain)
|
context, 'update_zone', zone=zone)
|
||||||
|
|
||||||
def update_status(self, context, domain, nameserver, status,
|
def update_status(self, context, zone, nameserver, status,
|
||||||
actual_serial):
|
actual_serial):
|
||||||
LOG.info(_LI("update_status: Calling pool manager for %(domain)s : "
|
LOG.info(_LI("update_status: Calling pool manager for %(zone)s : "
|
||||||
"%(action)s : %(status)s : %(serial)s on nameserver "
|
"%(action)s : %(status)s : %(serial)s on nameserver "
|
||||||
"'%(host)s:%(port)s'") %
|
"'%(host)s:%(port)s'") %
|
||||||
{'domain': domain.name, 'action': domain.action,
|
{'zone': zone.name, 'action': zone.action,
|
||||||
'status': status, 'serial': actual_serial,
|
'status': status, 'serial': actual_serial,
|
||||||
'host': nameserver.host, 'port': nameserver.port})
|
'host': nameserver.host, 'port': nameserver.port})
|
||||||
|
|
||||||
# Modifying the topic so it is pool manager instance specific.
|
# Modifying the topic so it is pool manager instance specific.
|
||||||
topic = '%s.%s' % (self.topic, domain.pool_id)
|
topic = '%s.%s' % (self.topic, zone.pool_id)
|
||||||
cctxt = self.client.prepare(topic=topic)
|
cctxt = self.client.prepare(topic=topic)
|
||||||
return cctxt.cast(
|
return cctxt.cast(
|
||||||
context, 'update_status', domain=domain, nameserver=nameserver,
|
context, 'update_status', zone=zone, nameserver=nameserver,
|
||||||
status=status, actual_serial=actual_serial)
|
status=status, actual_serial=actual_serial)
|
||||||
|
@ -71,7 +71,7 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
|
|
||||||
1.0 - Initial version
|
1.0 - Initial version
|
||||||
"""
|
"""
|
||||||
RPC_API_VERSION = '1.0'
|
RPC_API_VERSION = '2.0'
|
||||||
|
|
||||||
target = messaging.Target(version=RPC_API_VERSION)
|
target = messaging.Target(version=RPC_API_VERSION)
|
||||||
|
|
||||||
@ -180,22 +180,22 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Handle Deletion Failures
|
# Handle Deletion Failures
|
||||||
domains = self._get_failed_domains(context, DELETE_ACTION)
|
zones = self._get_failed_zones(context, DELETE_ACTION)
|
||||||
|
|
||||||
for domain in domains:
|
for zone in zones:
|
||||||
self.delete_domain(context, domain)
|
self.delete_zone(context, zone)
|
||||||
|
|
||||||
# Handle Creation Failures
|
# Handle Creation Failures
|
||||||
domains = self._get_failed_domains(context, CREATE_ACTION)
|
zones = self._get_failed_zones(context, CREATE_ACTION)
|
||||||
|
|
||||||
for domain in domains:
|
for zone in zones:
|
||||||
self.create_domain(context, domain)
|
self.create_zone(context, zone)
|
||||||
|
|
||||||
# Handle Update Failures
|
# Handle Update Failures
|
||||||
domains = self._get_failed_domains(context, UPDATE_ACTION)
|
zones = self._get_failed_zones(context, UPDATE_ACTION)
|
||||||
|
|
||||||
for domain in domains:
|
for zone in zones:
|
||||||
self.update_domain(context, domain)
|
self.update_zone(context, zone)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(_LE('An unhandled exception in periodic '
|
LOG.exception(_LE('An unhandled exception in periodic '
|
||||||
@ -224,14 +224,14 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
current = utils.increment_serial()
|
current = utils.increment_serial()
|
||||||
criterion['serial'] = ">%s" % (current - periodic_sync_seconds)
|
criterion['serial'] = ">%s" % (current - periodic_sync_seconds)
|
||||||
|
|
||||||
domains = self.central_api.find_domains(context, criterion)
|
zones = self.central_api.find_zones(context, criterion)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for domain in domains:
|
for zone in zones:
|
||||||
# TODO(kiall): If the domain was created within the last
|
# TODO(kiall): If the zone was created within the last
|
||||||
# periodic_sync_seconds, attempt to recreate
|
# periodic_sync_seconds, attempt to recreate
|
||||||
# to fill in targets which may have failed.
|
# to fill in targets which may have failed.
|
||||||
self.update_domain(context, domain)
|
self.update_zone(context, zone)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(_LE('An unhandled exception in periodic '
|
LOG.exception(_LE('An unhandled exception in periodic '
|
||||||
@ -239,73 +239,73 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
|
|
||||||
# Standard Create/Update/Delete Methods
|
# Standard Create/Update/Delete Methods
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param domain: Domain to be created
|
:param zone: Zone to be created
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
LOG.info(_LI("Creating new domain %s"), domain.name)
|
LOG.info(_LI("Creating new zone %s"), zone.name)
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
# Create the domain on each of the Pool Targets
|
# Create the zone on each of the Pool Targets
|
||||||
for target in self.pool.targets:
|
for target in self.pool.targets:
|
||||||
results.append(
|
results.append(
|
||||||
self._create_domain_on_target(context, target, domain)
|
self._create_zone_on_target(context, target, zone)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self._exceed_or_meet_threshold(results.count(True)):
|
if self._exceed_or_meet_threshold(results.count(True)):
|
||||||
LOG.debug('Consensus reached for creating domain %(domain)s '
|
LOG.debug('Consensus reached for creating zone %(zone)s '
|
||||||
'on pool targets' % {'domain': domain.name})
|
'on pool targets' % {'zone': zone.name})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
LOG.warn(_LW('Consensus not reached for creating domain %(domain)s'
|
LOG.warn(_LW('Consensus not reached for creating zone %(zone)s'
|
||||||
' on pool targets') % {'domain': domain.name})
|
' on pool targets') % {'zone': zone.name})
|
||||||
|
|
||||||
self.central_api.update_status(
|
self.central_api.update_status(
|
||||||
context, domain.id, ERROR_STATUS, domain.serial)
|
context, zone.id, ERROR_STATUS, zone.serial)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Send a NOTIFY to each also-notifies
|
# Send a NOTIFY to each also-notifies
|
||||||
for also_notify in self.pool.also_notifies:
|
for also_notify in self.pool.also_notifies:
|
||||||
self._update_domain_on_also_notify(context, also_notify, domain)
|
self._update_zone_on_also_notify(context, also_notify, zone)
|
||||||
|
|
||||||
# Send a NOTIFY to each nameserver
|
# Send a NOTIFY to each nameserver
|
||||||
for nameserver in self.pool.nameservers:
|
for nameserver in self.pool.nameservers:
|
||||||
create_status = self._build_status_object(
|
create_status = self._build_status_object(
|
||||||
nameserver, domain, CREATE_ACTION)
|
nameserver, zone, CREATE_ACTION)
|
||||||
self.cache.store(context, create_status)
|
self.cache.store(context, create_status)
|
||||||
|
|
||||||
self.mdns_api.poll_for_serial_number(
|
self.mdns_api.poll_for_serial_number(
|
||||||
context, domain, nameserver, self.timeout,
|
context, zone, nameserver, self.timeout,
|
||||||
self.retry_interval, self.max_retries, self.delay)
|
self.retry_interval, self.max_retries, self.delay)
|
||||||
|
|
||||||
def _create_domain_on_target(self, context, target, domain):
|
def _create_zone_on_target(self, context, target, zone):
|
||||||
"""
|
"""
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param target: Target to create Domain on
|
:param target: Target to create Zone on
|
||||||
:param domain: Domain to be created
|
:param zone: Zone to be created
|
||||||
:return: True/False
|
:return: True/False
|
||||||
"""
|
"""
|
||||||
LOG.debug("Creating domain %s on target %s", domain.name, target.id)
|
LOG.debug("Creating zone %s on target %s", zone.name, target.id)
|
||||||
|
|
||||||
backend = self.target_backends[target.id]
|
backend = self.target_backends[target.id]
|
||||||
retries = 0
|
retries = 0
|
||||||
|
|
||||||
while retries < self.max_retries:
|
while retries < self.max_retries:
|
||||||
try:
|
try:
|
||||||
backend.create_domain(context, domain)
|
backend.create_zone(context, zone)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
retries += 1
|
retries += 1
|
||||||
LOG.exception(_LE("Failed to create domain %(domain)s on "
|
LOG.exception(_LE("Failed to create zone %(zone)s on "
|
||||||
"target %(target)s on attempt %(attempt)d"),
|
"target %(target)s on attempt %(attempt)d"),
|
||||||
{
|
{
|
||||||
'domain': domain.name,
|
'zone': zone.name,
|
||||||
'target': target.id,
|
'target': target.id,
|
||||||
'attempt': retries
|
'attempt': retries
|
||||||
})
|
})
|
||||||
@ -313,140 +313,140 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def update_domain(self, context, domain):
|
def update_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param domain: Domain to be updated
|
:param zone: Zone to be updated
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
LOG.info(_LI("Updating domain %s"), domain.name)
|
LOG.info(_LI("Updating zone %s"), zone.name)
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
# Update the domain on each of the Pool Targets
|
# Update the zone on each of the Pool Targets
|
||||||
for target in self.pool.targets:
|
for target in self.pool.targets:
|
||||||
results.append(
|
results.append(
|
||||||
self._update_domain_on_target(context, target, domain))
|
self._update_zone_on_target(context, target, zone))
|
||||||
|
|
||||||
if self._exceed_or_meet_threshold(results.count(True)):
|
if self._exceed_or_meet_threshold(results.count(True)):
|
||||||
LOG.debug('Consensus reached for updating domain %(domain)s '
|
LOG.debug('Consensus reached for updating zone %(zone)s '
|
||||||
'on pool targets' % {'domain': domain.name})
|
'on pool targets' % {'zone': zone.name})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
LOG.warn(_LW('Consensus not reached for updating domain %(domain)s'
|
LOG.warn(_LW('Consensus not reached for updating zone %(zone)s'
|
||||||
' on pool targets') % {'domain': domain.name})
|
' on pool targets') % {'zone': zone.name})
|
||||||
|
|
||||||
self.central_api.update_status(
|
self.central_api.update_status(
|
||||||
context, domain.id, ERROR_STATUS, domain.serial)
|
context, zone.id, ERROR_STATUS, zone.serial)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Send a NOTIFY to each also-notifies
|
# Send a NOTIFY to each also-notifies
|
||||||
for also_notify in self.pool.also_notifies:
|
for also_notify in self.pool.also_notifies:
|
||||||
self._update_domain_on_also_notify(context, also_notify, domain)
|
self._update_zone_on_also_notify(context, also_notify, zone)
|
||||||
|
|
||||||
# Ensure the change has propogated to each nameserver
|
# Ensure the change has propogated to each nameserver
|
||||||
for nameserver in self.pool.nameservers:
|
for nameserver in self.pool.nameservers:
|
||||||
# See if there is already another update in progress
|
# See if there is already another update in progress
|
||||||
try:
|
try:
|
||||||
update_status = self.cache.retrieve(
|
update_status = self.cache.retrieve(
|
||||||
context, nameserver.id, domain.id, UPDATE_ACTION)
|
context, nameserver.id, zone.id, UPDATE_ACTION)
|
||||||
except exceptions.PoolManagerStatusNotFound:
|
except exceptions.PoolManagerStatusNotFound:
|
||||||
update_status = self._build_status_object(
|
update_status = self._build_status_object(
|
||||||
nameserver, domain, UPDATE_ACTION)
|
nameserver, zone, UPDATE_ACTION)
|
||||||
self.cache.store(context, update_status)
|
self.cache.store(context, update_status)
|
||||||
|
|
||||||
self.mdns_api.poll_for_serial_number(
|
self.mdns_api.poll_for_serial_number(
|
||||||
context, domain, nameserver, self.timeout,
|
context, zone, nameserver, self.timeout,
|
||||||
self.retry_interval, self.max_retries, self.delay)
|
self.retry_interval, self.max_retries, self.delay)
|
||||||
|
|
||||||
def _update_domain_on_target(self, context, target, domain):
|
def _update_zone_on_target(self, context, target, zone):
|
||||||
"""
|
"""
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param target: Target to update Domain on
|
:param target: Target to update Zone on
|
||||||
:param domain: Domain to be updated
|
:param zone: Zone to be updated
|
||||||
:return: True/False
|
:return: True/False
|
||||||
"""
|
"""
|
||||||
LOG.debug("Updating domain %s on target %s", domain.name, target.id)
|
LOG.debug("Updating zone %s on target %s", zone.name, target.id)
|
||||||
|
|
||||||
backend = self.target_backends[target.id]
|
backend = self.target_backends[target.id]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
backend.update_domain(context, domain)
|
backend.update_zone(context, zone)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(_LE("Failed to update domain %(domain)s on target "
|
LOG.exception(_LE("Failed to update zone %(zone)s on target "
|
||||||
"%(target)s"),
|
"%(target)s"),
|
||||||
{'domain': domain.name, 'target': target.id})
|
{'zone': zone.name, 'target': target.id})
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _update_domain_on_also_notify(self, context, also_notify, domain):
|
def _update_zone_on_also_notify(self, context, also_notify, zone):
|
||||||
LOG.info(_LI('Updating domain %(domain)s on also_notify %(server)s.') %
|
LOG.info(_LI('Updating zone %(zone)s on also_notify %(server)s.') %
|
||||||
{'domain': domain.name,
|
{'zone': zone.name,
|
||||||
'server': self._get_destination(also_notify)})
|
'server': self._get_destination(also_notify)})
|
||||||
|
|
||||||
self.mdns_api.notify_zone_changed(
|
self.mdns_api.notify_zone_changed(
|
||||||
context, domain, also_notify.host, also_notify.port, self.timeout,
|
context, zone, also_notify.host, also_notify.port, self.timeout,
|
||||||
self.retry_interval, self.max_retries, 0)
|
self.retry_interval, self.max_retries, 0)
|
||||||
|
|
||||||
def delete_domain(self, context, domain):
|
def delete_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param domain: Domain to be deleted
|
:param zone: Zone to be deleted
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
LOG.info(_LI("Deleting domain %s"), domain.name)
|
LOG.info(_LI("Deleting zone %s"), zone.name)
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
# Delete the domain on each of the Pool Targets
|
# Delete the zone on each of the Pool Targets
|
||||||
for target in self.pool.targets:
|
for target in self.pool.targets:
|
||||||
results.append(
|
results.append(
|
||||||
self._delete_domain_on_target(context, target, domain))
|
self._delete_zone_on_target(context, target, zone))
|
||||||
|
|
||||||
# TODO(kiall): We should monitor that the Domain is actually deleted
|
# TODO(kiall): We should monitor that the Zone is actually deleted
|
||||||
# correctly on each of the nameservers, rather than
|
# correctly on each of the nameservers, rather than
|
||||||
# assuming a successful delete-on-target is OK as we have
|
# assuming a successful delete-on-target is OK as we have
|
||||||
# in the past.
|
# in the past.
|
||||||
if self._exceed_or_meet_threshold(
|
if self._exceed_or_meet_threshold(
|
||||||
results.count(True), MAXIMUM_THRESHOLD):
|
results.count(True), MAXIMUM_THRESHOLD):
|
||||||
LOG.debug('Consensus reached for deleting domain %(domain)s '
|
LOG.debug('Consensus reached for deleting zone %(zone)s '
|
||||||
'on pool targets' % {'domain': domain.name})
|
'on pool targets' % {'zone': zone.name})
|
||||||
|
|
||||||
self.central_api.update_status(
|
self.central_api.update_status(
|
||||||
context, domain.id, SUCCESS_STATUS, domain.serial)
|
context, zone.id, SUCCESS_STATUS, zone.serial)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
LOG.warn(_LW('Consensus not reached for deleting domain %(domain)s'
|
LOG.warn(_LW('Consensus not reached for deleting zone %(zone)s'
|
||||||
' on pool targets') % {'domain': domain.name})
|
' on pool targets') % {'zone': zone.name})
|
||||||
|
|
||||||
self.central_api.update_status(
|
self.central_api.update_status(
|
||||||
context, domain.id, ERROR_STATUS, domain.serial)
|
context, zone.id, ERROR_STATUS, zone.serial)
|
||||||
|
|
||||||
def _delete_domain_on_target(self, context, target, domain):
|
def _delete_zone_on_target(self, context, target, zone):
|
||||||
"""
|
"""
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param target: Target to delete Domain from
|
:param target: Target to delete Zone from
|
||||||
:param domain: Domain to be deleted
|
:param zone: Zone to be deleted
|
||||||
:return: True/False
|
:return: True/False
|
||||||
"""
|
"""
|
||||||
LOG.debug("Deleting domain %s on target %s", domain.name, target.id)
|
LOG.debug("Deleting zone %s on target %s", zone.name, target.id)
|
||||||
|
|
||||||
backend = self.target_backends[target.id]
|
backend = self.target_backends[target.id]
|
||||||
retries = 0
|
retries = 0
|
||||||
|
|
||||||
while retries < self.max_retries:
|
while retries < self.max_retries:
|
||||||
try:
|
try:
|
||||||
backend.delete_domain(context, domain)
|
backend.delete_zone(context, zone)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
retries += 1
|
retries += 1
|
||||||
LOG.exception(_LE("Failed to delete domain %(domain)s on "
|
LOG.exception(_LE("Failed to delete zone %(zone)s on "
|
||||||
"target %(target)s on attempt %(attempt)d"),
|
"target %(target)s on attempt %(attempt)d"),
|
||||||
{
|
{
|
||||||
'domain': domain.name,
|
'zone': zone.name,
|
||||||
'target': target.id,
|
'target': target.id,
|
||||||
'attempt': retries
|
'attempt': retries
|
||||||
})
|
})
|
||||||
@ -454,38 +454,38 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def update_status(self, context, domain, nameserver, status,
|
def update_status(self, context, zone, nameserver, status,
|
||||||
actual_serial):
|
actual_serial):
|
||||||
"""
|
"""
|
||||||
update_status is called by mdns for creates and updates.
|
update_status is called by mdns for creates and updates.
|
||||||
deletes are handled by the backend entirely and status is determined
|
deletes are handled by the backend entirely and status is determined
|
||||||
at the time of delete itself.
|
at the time of delete itself.
|
||||||
:param context: Security context information.
|
:param context: Security context information.
|
||||||
:param domain: The designate domain object.
|
:param zone: The designate zone object.
|
||||||
:param nameserver: The nameserver for which a status update is being
|
:param nameserver: The nameserver for which a status update is being
|
||||||
sent.
|
sent.
|
||||||
:param status: The status, 'SUCCESS' or 'ERROR'.
|
:param status: The status, 'SUCCESS' or 'ERROR'.
|
||||||
:param actual_serial: The actual serial number received from the name
|
:param actual_serial: The actual serial number received from the name
|
||||||
server for the domain.
|
server for the zone.
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
LOG.debug("Calling update_status for %s : %s : %s : %s" %
|
LOG.debug("Calling update_status for %s : %s : %s : %s" %
|
||||||
(domain.name, domain.action, status, actual_serial))
|
(zone.name, zone.action, status, actual_serial))
|
||||||
action = UPDATE_ACTION if domain.action == 'NONE' else domain.action
|
action = UPDATE_ACTION if zone.action == 'NONE' else zone.action
|
||||||
|
|
||||||
with lockutils.lock('update-status-%s' % domain.id):
|
with lockutils.lock('update-status-%s' % zone.id):
|
||||||
try:
|
try:
|
||||||
current_status = self.cache.retrieve(
|
current_status = self.cache.retrieve(
|
||||||
context, nameserver.id, domain.id, action)
|
context, nameserver.id, zone.id, action)
|
||||||
except exceptions.PoolManagerStatusNotFound:
|
except exceptions.PoolManagerStatusNotFound:
|
||||||
current_status = self._build_status_object(
|
current_status = self._build_status_object(
|
||||||
nameserver, domain, action)
|
nameserver, zone, action)
|
||||||
self.cache.store(context, current_status)
|
self.cache.store(context, current_status)
|
||||||
cache_serial = current_status.serial_number
|
cache_serial = current_status.serial_number
|
||||||
|
|
||||||
LOG.debug('For domain %s : %s on nameserver %s the cache serial '
|
LOG.debug('For zone %s : %s on nameserver %s the cache serial '
|
||||||
'is %s and the actual serial is %s.' %
|
'is %s and the actual serial is %s.' %
|
||||||
(domain.name, action,
|
(zone.name, action,
|
||||||
self._get_destination(nameserver),
|
self._get_destination(nameserver),
|
||||||
cache_serial, actual_serial))
|
cache_serial, actual_serial))
|
||||||
if actual_serial and cache_serial <= actual_serial:
|
if actual_serial and cache_serial <= actual_serial:
|
||||||
@ -493,51 +493,51 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
current_status.serial_number = actual_serial
|
current_status.serial_number = actual_serial
|
||||||
self.cache.store(context, current_status)
|
self.cache.store(context, current_status)
|
||||||
|
|
||||||
consensus_serial = self._get_consensus_serial(context, domain)
|
consensus_serial = self._get_consensus_serial(context, zone)
|
||||||
|
|
||||||
# If there is a valid consensus serial we can still send a success
|
# If there is a valid consensus serial we can still send a success
|
||||||
# for that serial.
|
# for that serial.
|
||||||
# If there is a higher error serial we can also send an error for
|
# If there is a higher error serial we can also send an error for
|
||||||
# the error serial.
|
# the error serial.
|
||||||
if consensus_serial != 0 and cache_serial <= consensus_serial \
|
if consensus_serial != 0 and cache_serial <= consensus_serial \
|
||||||
and domain.status != 'ACTIVE':
|
and zone.status != 'ACTIVE':
|
||||||
LOG.info(_LI('For domain %(domain)s '
|
LOG.info(_LI('For zone %(zone)s '
|
||||||
'the consensus serial is %(consensus_serial)s.') %
|
'the consensus serial is %(consensus_serial)s.') %
|
||||||
{'domain': domain.name,
|
{'zone': zone.name,
|
||||||
'consensus_serial': consensus_serial})
|
'consensus_serial': consensus_serial})
|
||||||
self.central_api.update_status(
|
self.central_api.update_status(
|
||||||
context, domain.id, SUCCESS_STATUS, consensus_serial)
|
context, zone.id, SUCCESS_STATUS, consensus_serial)
|
||||||
|
|
||||||
if status == ERROR_STATUS:
|
if status == ERROR_STATUS:
|
||||||
error_serial = self._get_error_serial(
|
error_serial = self._get_error_serial(
|
||||||
context, domain, consensus_serial)
|
context, zone, consensus_serial)
|
||||||
if error_serial > consensus_serial or error_serial == 0:
|
if error_serial > consensus_serial or error_serial == 0:
|
||||||
LOG.warn(_LW('For domain %(domain)s '
|
LOG.warn(_LW('For zone %(zone)s '
|
||||||
'the error serial is %(error_serial)s.') %
|
'the error serial is %(error_serial)s.') %
|
||||||
{'domain': domain.name,
|
{'zone': zone.name,
|
||||||
'error_serial': error_serial})
|
'error_serial': error_serial})
|
||||||
self.central_api.update_status(
|
self.central_api.update_status(
|
||||||
context, domain.id, ERROR_STATUS, error_serial)
|
context, zone.id, ERROR_STATUS, error_serial)
|
||||||
|
|
||||||
if status == NO_DOMAIN_STATUS and action != DELETE_ACTION:
|
if status == NO_DOMAIN_STATUS and action != DELETE_ACTION:
|
||||||
LOG.warn(_LW('Domain %(domain)s is not present in some '
|
LOG.warn(_LW('Zone %(zone)s is not present in some '
|
||||||
'targets') % {'domain': domain.name})
|
'targets') % {'zone': zone.name})
|
||||||
self.central_api.update_status(
|
self.central_api.update_status(
|
||||||
context, domain.id, NO_DOMAIN_STATUS, 0)
|
context, zone.id, NO_DOMAIN_STATUS, 0)
|
||||||
|
|
||||||
if consensus_serial == domain.serial and self._is_consensus(
|
if consensus_serial == zone.serial and self._is_consensus(
|
||||||
context, domain, action, SUCCESS_STATUS,
|
context, zone, action, SUCCESS_STATUS,
|
||||||
MAXIMUM_THRESHOLD):
|
MAXIMUM_THRESHOLD):
|
||||||
self._clear_cache(context, domain, action)
|
self._clear_cache(context, zone, action)
|
||||||
|
|
||||||
# Utility Methods
|
# Utility Methods
|
||||||
def _get_failed_domains(self, context, action):
|
def _get_failed_zones(self, context, action):
|
||||||
criterion = {
|
criterion = {
|
||||||
'pool_id': CONF['service:pool_manager'].pool_id,
|
'pool_id': CONF['service:pool_manager'].pool_id,
|
||||||
'action': action,
|
'action': action,
|
||||||
'status': 'ERROR'
|
'status': 'ERROR'
|
||||||
}
|
}
|
||||||
return self.central_api.find_domains(context, criterion)
|
return self.central_api.find_zones(context, criterion)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_destination(nameserver):
|
def _get_destination(nameserver):
|
||||||
@ -567,10 +567,10 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
def _get_serials_descending(self, pool_manager_statuses):
|
def _get_serials_descending(self, pool_manager_statuses):
|
||||||
return self._get_sorted_serials(pool_manager_statuses, descending=True)
|
return self._get_sorted_serials(pool_manager_statuses, descending=True)
|
||||||
|
|
||||||
def _is_consensus(self, context, domain, action, status, threshold=None):
|
def _is_consensus(self, context, zone, action, status, threshold=None):
|
||||||
status_count = 0
|
status_count = 0
|
||||||
pool_manager_statuses = self._retrieve_statuses(
|
pool_manager_statuses = self._retrieve_statuses(
|
||||||
context, domain, action)
|
context, zone, action)
|
||||||
for pool_manager_status in pool_manager_statuses:
|
for pool_manager_status in pool_manager_statuses:
|
||||||
if pool_manager_status.status == status:
|
if pool_manager_status.status == status:
|
||||||
status_count += 1
|
status_count += 1
|
||||||
@ -578,11 +578,11 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
threshold = self.threshold
|
threshold = self.threshold
|
||||||
return self._exceed_or_meet_threshold(status_count, threshold)
|
return self._exceed_or_meet_threshold(status_count, threshold)
|
||||||
|
|
||||||
def _get_consensus_serial(self, context, domain):
|
def _get_consensus_serial(self, context, zone):
|
||||||
consensus_serial = 0
|
consensus_serial = 0
|
||||||
action = UPDATE_ACTION if domain.action == 'NONE' else domain.action
|
action = UPDATE_ACTION if zone.action == 'NONE' else zone.action
|
||||||
|
|
||||||
pm_statuses = self._retrieve_statuses(context, domain, action)
|
pm_statuses = self._retrieve_statuses(context, zone, action)
|
||||||
for serial in self._get_serials_descending(pm_statuses):
|
for serial in self._get_serials_descending(pm_statuses):
|
||||||
serial_count = 0
|
serial_count = 0
|
||||||
for pm_status in pm_statuses:
|
for pm_status in pm_statuses:
|
||||||
@ -593,12 +593,12 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
break
|
break
|
||||||
return consensus_serial
|
return consensus_serial
|
||||||
|
|
||||||
def _get_error_serial(self, context, domain, consensus_serial):
|
def _get_error_serial(self, context, zone, consensus_serial):
|
||||||
error_serial = 0
|
error_serial = 0
|
||||||
action = UPDATE_ACTION if domain.action == 'NONE' else domain.action
|
action = UPDATE_ACTION if zone.action == 'NONE' else zone.action
|
||||||
|
|
||||||
if self._is_consensus(context, domain, action, ERROR_STATUS):
|
if self._is_consensus(context, zone, action, ERROR_STATUS):
|
||||||
pm_statuses = self._retrieve_statuses(context, domain, action)
|
pm_statuses = self._retrieve_statuses(context, zone, action)
|
||||||
for serial in self._get_serials_ascending(pm_statuses):
|
for serial in self._get_serials_ascending(pm_statuses):
|
||||||
if serial > consensus_serial:
|
if serial > consensus_serial:
|
||||||
error_serial = serial
|
error_serial = serial
|
||||||
@ -608,10 +608,10 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
# When we hear back from the nameserver, the serial_number is set to the
|
# When we hear back from the nameserver, the serial_number is set to the
|
||||||
# value the nameserver
|
# value the nameserver
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _build_status_object(nameserver, domain, action):
|
def _build_status_object(nameserver, zone, action):
|
||||||
values = {
|
values = {
|
||||||
'nameserver_id': nameserver.id,
|
'nameserver_id': nameserver.id,
|
||||||
'domain_id': domain.id,
|
'zone_id': zone.id,
|
||||||
'status': None,
|
'status': None,
|
||||||
'serial_number': 0,
|
'serial_number': 0,
|
||||||
'action': action
|
'action': action
|
||||||
@ -619,9 +619,9 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
return objects.PoolManagerStatus(**values)
|
return objects.PoolManagerStatus(**values)
|
||||||
|
|
||||||
# Methods for manipulating the cache.
|
# Methods for manipulating the cache.
|
||||||
def _clear_cache(self, context, domain, action=None):
|
def _clear_cache(self, context, zone, action=None):
|
||||||
LOG.debug('Clearing cache for domain %s with action %s.' %
|
LOG.debug('Clearing cache for zone %s with action %s.' %
|
||||||
(domain.name, action))
|
(zone.name, action))
|
||||||
|
|
||||||
pool_manager_statuses = []
|
pool_manager_statuses = []
|
||||||
if action:
|
if action:
|
||||||
@ -632,7 +632,7 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
for nameserver in self.pool.nameservers:
|
for nameserver in self.pool.nameservers:
|
||||||
for action in actions:
|
for action in actions:
|
||||||
pool_manager_status = self._build_status_object(
|
pool_manager_status = self._build_status_object(
|
||||||
nameserver, domain, action)
|
nameserver, zone, action)
|
||||||
pool_manager_statuses.append(pool_manager_status)
|
pool_manager_statuses.append(pool_manager_status)
|
||||||
|
|
||||||
for pool_manager_status in pool_manager_statuses:
|
for pool_manager_status in pool_manager_statuses:
|
||||||
@ -642,22 +642,22 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
except exceptions.PoolManagerStatusNotFound:
|
except exceptions.PoolManagerStatusNotFound:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _retrieve_from_mdns(self, context, nameserver, domain, action):
|
def _retrieve_from_mdns(self, context, nameserver, zone, action):
|
||||||
try:
|
try:
|
||||||
(status, actual_serial, retries) = \
|
(status, actual_serial, retries) = \
|
||||||
self.mdns_api.get_serial_number(
|
self.mdns_api.get_serial_number(
|
||||||
context, domain, nameserver.host, nameserver.port,
|
context, zone, nameserver.host, nameserver.port,
|
||||||
self.timeout, self.retry_interval, self.max_retries,
|
self.timeout, self.retry_interval, self.max_retries,
|
||||||
self.delay)
|
self.delay)
|
||||||
except messaging.MessagingException as msg_ex:
|
except messaging.MessagingException as msg_ex:
|
||||||
LOG.debug('Could not retrieve status and serial for domain %s on '
|
LOG.debug('Could not retrieve status and serial for zone %s on '
|
||||||
'nameserver %s with action %s (%s: %s)' %
|
'nameserver %s with action %s (%s: %s)' %
|
||||||
(domain.name, self._get_destination(nameserver), action,
|
(zone.name, self._get_destination(nameserver), action,
|
||||||
type(msg_ex), str(msg_ex)))
|
type(msg_ex), str(msg_ex)))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
pool_manager_status = self._build_status_object(
|
pool_manager_status = self._build_status_object(
|
||||||
nameserver, domain, action)
|
nameserver, zone, action)
|
||||||
|
|
||||||
if status == NO_DOMAIN_STATUS:
|
if status == NO_DOMAIN_STATUS:
|
||||||
if action == CREATE_ACTION:
|
if action == CREATE_ACTION:
|
||||||
@ -671,37 +671,37 @@ class Service(service.RPCService, coordination.CoordinationMixin,
|
|||||||
pool_manager_status.status = status
|
pool_manager_status.status = status
|
||||||
pool_manager_status.serial_number = actual_serial \
|
pool_manager_status.serial_number = actual_serial \
|
||||||
if actual_serial is not None else 0
|
if actual_serial is not None else 0
|
||||||
LOG.debug('Retrieved status %s and serial %s for domain %s '
|
LOG.debug('Retrieved status %s and serial %s for zone %s '
|
||||||
'on nameserver %s with action %s from mdns.' %
|
'on nameserver %s with action %s from mdns.' %
|
||||||
(pool_manager_status.status,
|
(pool_manager_status.status,
|
||||||
pool_manager_status.serial_number,
|
pool_manager_status.serial_number,
|
||||||
domain.name, self._get_destination(nameserver), action))
|
zone.name, self._get_destination(nameserver), action))
|
||||||
self.cache.store(context, pool_manager_status)
|
self.cache.store(context, pool_manager_status)
|
||||||
|
|
||||||
return pool_manager_status
|
return pool_manager_status
|
||||||
|
|
||||||
def _retrieve_statuses(self, context, domain, action):
|
def _retrieve_statuses(self, context, zone, action):
|
||||||
pool_manager_statuses = []
|
pool_manager_statuses = []
|
||||||
for nameserver in self.pool.nameservers:
|
for nameserver in self.pool.nameservers:
|
||||||
try:
|
try:
|
||||||
pool_manager_status = self.cache.retrieve(
|
pool_manager_status = self.cache.retrieve(
|
||||||
context, nameserver.id, domain.id, action)
|
context, nameserver.id, zone.id, action)
|
||||||
LOG.debug('Cache hit! Retrieved status %s and serial %s '
|
LOG.debug('Cache hit! Retrieved status %s and serial %s '
|
||||||
'for domain %s on nameserver %s with action %s from '
|
'for zone %s on nameserver %s with action %s from '
|
||||||
'the cache.' %
|
'the cache.' %
|
||||||
(pool_manager_status.status,
|
(pool_manager_status.status,
|
||||||
pool_manager_status.serial_number,
|
pool_manager_status.serial_number,
|
||||||
domain.name,
|
zone.name,
|
||||||
self._get_destination(nameserver), action))
|
self._get_destination(nameserver), action))
|
||||||
except exceptions.PoolManagerStatusNotFound:
|
except exceptions.PoolManagerStatusNotFound:
|
||||||
LOG.debug('Cache miss! Did not retrieve status and serial '
|
LOG.debug('Cache miss! Did not retrieve status and serial '
|
||||||
'for domain %s on nameserver %s with action %s from '
|
'for zone %s on nameserver %s with action %s from '
|
||||||
'the cache. Getting it from the server.' %
|
'the cache. Getting it from the server.' %
|
||||||
(domain.name,
|
(zone.name,
|
||||||
self._get_destination(nameserver),
|
self._get_destination(nameserver),
|
||||||
action))
|
action))
|
||||||
pool_manager_status = self._retrieve_from_mdns(
|
pool_manager_status = self._retrieve_from_mdns(
|
||||||
context, nameserver, domain, action)
|
context, nameserver, zone, action)
|
||||||
|
|
||||||
if pool_manager_status is not None:
|
if pool_manager_status is not None:
|
||||||
pool_manager_statuses.append(pool_manager_status)
|
pool_manager_statuses.append(pool_manager_status)
|
||||||
|
@ -24,12 +24,12 @@ LOG = logging.getLogger(__name__)
|
|||||||
cfg.CONF.register_opts([
|
cfg.CONF.register_opts([
|
||||||
cfg.StrOpt('quota-driver', default='storage', help='Quota driver to use'),
|
cfg.StrOpt('quota-driver', default='storage', help='Quota driver to use'),
|
||||||
|
|
||||||
cfg.IntOpt('quota-domains', default=10,
|
cfg.IntOpt('quota-zones', default=10,
|
||||||
help='Number of domains allowed per tenant'),
|
help='Number of zones allowed per tenant'),
|
||||||
cfg.IntOpt('quota-domain-recordsets', default=500,
|
cfg.IntOpt('quota-zone-recordsets', default=500,
|
||||||
help='Number of recordsets allowed per domain'),
|
help='Number of recordsets allowed per zone'),
|
||||||
cfg.IntOpt('quota-domain-records', default=500,
|
cfg.IntOpt('quota-zone-records', default=500,
|
||||||
help='Number of records allowed per domain'),
|
help='Number of records allowed per zone'),
|
||||||
cfg.IntOpt('quota-recordset-records', default=20,
|
cfg.IntOpt('quota-recordset-records', default=20,
|
||||||
help='Number of records allowed per recordset'),
|
help='Number of records allowed per recordset'),
|
||||||
cfg.IntOpt('quota-api-export-size', default=1000,
|
cfg.IntOpt('quota-api-export-size', default=1000,
|
||||||
|
@ -36,7 +36,8 @@ class Quota(DriverPlugin):
|
|||||||
if value >= quotas[resource]:
|
if value >= quotas[resource]:
|
||||||
raise exceptions.OverQuota()
|
raise exceptions.OverQuota()
|
||||||
else:
|
else:
|
||||||
raise exceptions.QuotaResourceUnknown()
|
raise exceptions.QuotaResourceUnknown("%s is not a valid quota"
|
||||||
|
" resource", resource)
|
||||||
|
|
||||||
def get_quotas(self, context, tenant_id):
|
def get_quotas(self, context, tenant_id):
|
||||||
quotas = self.get_default_quotas(context)
|
quotas = self.get_default_quotas(context)
|
||||||
@ -51,9 +52,9 @@ class Quota(DriverPlugin):
|
|||||||
|
|
||||||
def get_default_quotas(self, context):
|
def get_default_quotas(self, context):
|
||||||
return {
|
return {
|
||||||
'domains': cfg.CONF.quota_domains,
|
'zones': cfg.CONF.quota_zones,
|
||||||
'domain_recordsets': cfg.CONF.quota_domain_recordsets,
|
'zone_recordsets': cfg.CONF.quota_zone_recordsets,
|
||||||
'domain_records': cfg.CONF.quota_domain_records,
|
'zone_records': cfg.CONF.quota_zone_records,
|
||||||
'recordset_records': cfg.CONF.quota_recordset_records,
|
'recordset_records': cfg.CONF.quota_recordset_records,
|
||||||
'api_export_size': cfg.CONF.quota_api_export_size,
|
'api_export_size': cfg.CONF.quota_api_export_size,
|
||||||
}
|
}
|
||||||
@ -62,7 +63,8 @@ class Quota(DriverPlugin):
|
|||||||
quotas = self._get_quotas(context, tenant_id)
|
quotas = self._get_quotas(context, tenant_id)
|
||||||
|
|
||||||
if resource not in quotas:
|
if resource not in quotas:
|
||||||
raise exceptions.QuotaResourceUnknown()
|
raise exceptions.QuotaResourceUnknown("%s is not a valid quota "
|
||||||
|
"resource", resource)
|
||||||
|
|
||||||
return quotas[resource]
|
return quotas[resource]
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
$ORIGIN {{ domain.name }}
|
$ORIGIN {{ zone.name }}
|
||||||
$TTL {{ domain.ttl }}
|
$TTL {{ zone.ttl }}
|
||||||
|
|
||||||
{% for recordset in recordsets -%}
|
{% for recordset in recordsets -%}
|
||||||
{{recordset[0]}} {{recordset[1] or ''}} IN {{recordset[2]}} {{recordset[3]}}
|
{{recordset[0]}} {{recordset[1] or ''}} IN {{recordset[2]}} {{recordset[3]}}
|
||||||
|
@ -27,7 +27,7 @@ LOG = logging.getLogger(__name__)
|
|||||||
# "\Z", rather than simply "$" to ensure a string with a
|
# "\Z", rather than simply "$" to ensure a string with a
|
||||||
# trailing newline is NOT matched. See bug #1471158.
|
# trailing newline is NOT matched. See bug #1471158.
|
||||||
|
|
||||||
RE_DOMAINNAME = r'^(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+\Z'
|
RE_ZONENAME = r'^(?!.{255,})(?:(?!\-)[A-Za-z0-9_\-]{1,63}(?<!\-)\.)+\Z'
|
||||||
RE_HOSTNAME = r'^(?!.{255,})(?:(?:^\*|(?!\-)[A-Za-z0-9_\-]{1,63})(?<!\-)\.)+\Z'
|
RE_HOSTNAME = r'^(?!.{255,})(?:(?:^\*|(?!\-)[A-Za-z0-9_\-]{1,63})(?<!\-)\.)+\Z'
|
||||||
|
|
||||||
RE_SRV_HOST_NAME = r'^(?:(?!\-)(?:\_[A-Za-z0-9_\-]{1,63}\.){2})(?!.{255,})' \
|
RE_SRV_HOST_NAME = r'^(?:(?!\-)(?:\_[A-Za-z0-9_\-]{1,63}\.){2})(?!.{255,})' \
|
||||||
@ -108,7 +108,7 @@ def is_ip_or_host(instance):
|
|||||||
if not isinstance(instance, compat.str_types):
|
if not isinstance(instance, compat.str_types):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if not re.match(RE_DOMAINNAME, instance)\
|
if not re.match(RE_ZONENAME, instance)\
|
||||||
and not is_ipv4(instance)\
|
and not is_ipv4(instance)\
|
||||||
and not is_ipv6(instance):
|
and not is_ipv6(instance):
|
||||||
return False
|
return False
|
||||||
@ -118,11 +118,13 @@ def is_ip_or_host(instance):
|
|||||||
|
|
||||||
@draft3_format_checker.checks("domain-name")
|
@draft3_format_checker.checks("domain-name")
|
||||||
@draft4_format_checker.checks("domainname")
|
@draft4_format_checker.checks("domainname")
|
||||||
def is_domainname(instance):
|
@draft3_format_checker.checks("zone-name")
|
||||||
|
@draft4_format_checker.checks("zonename")
|
||||||
|
def is_zonename(instance):
|
||||||
if not isinstance(instance, compat.str_types):
|
if not isinstance(instance, compat.str_types):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if not re.match(RE_DOMAINNAME, instance):
|
if not re.match(RE_ZONENAME, instance):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@ -163,7 +165,7 @@ def is_email(instance):
|
|||||||
|
|
||||||
rname = instance.replace('@', '.', 1)
|
rname = instance.replace('@', '.', 1)
|
||||||
|
|
||||||
if not re.match(RE_DOMAINNAME, "%s." % rname):
|
if not re.match(RE_ZONENAME, "%s." % rname):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -322,7 +322,7 @@ class SQLAlchemy(object):
|
|||||||
table.c.created_at, # 2 - RS Created
|
table.c.created_at, # 2 - RS Created
|
||||||
table.c.updated_at, # 3 - RS Updated
|
table.c.updated_at, # 3 - RS Updated
|
||||||
table.c.tenant_id, # 4 - RS Tenant
|
table.c.tenant_id, # 4 - RS Tenant
|
||||||
table.c.domain_id, # 5 - RS Domain
|
table.c.zone_id, # 5 - RS Zone
|
||||||
table.c.name, # 6 - RS Name
|
table.c.name, # 6 - RS Name
|
||||||
table.c.type, # 7 - RS Type
|
table.c.type, # 7 - RS Type
|
||||||
table.c.ttl, # 8 - RS TTL
|
table.c.ttl, # 8 - RS TTL
|
||||||
@ -333,7 +333,7 @@ class SQLAlchemy(object):
|
|||||||
relation_table.c.created_at, # 12 - R Created
|
relation_table.c.created_at, # 12 - R Created
|
||||||
relation_table.c.updated_at, # 13 - R Updated
|
relation_table.c.updated_at, # 13 - R Updated
|
||||||
relation_table.c.tenant_id, # 14 - R Tenant
|
relation_table.c.tenant_id, # 14 - R Tenant
|
||||||
relation_table.c.domain_id, # 15 - R Domain
|
relation_table.c.zone_id, # 15 - R Zone
|
||||||
relation_table.c.recordset_id, # 16 - R RSet
|
relation_table.c.recordset_id, # 16 - R RSet
|
||||||
relation_table.c.data, # 17 - R Data
|
relation_table.c.data, # 17 - R Data
|
||||||
relation_table.c.description, # 18 - R Desc
|
relation_table.c.description, # 18 - R Desc
|
||||||
@ -364,7 +364,7 @@ class SQLAlchemy(object):
|
|||||||
"created_at": 2,
|
"created_at": 2,
|
||||||
"updated_at": 3,
|
"updated_at": 3,
|
||||||
"tenant_id": 4,
|
"tenant_id": 4,
|
||||||
"domain_id": 5,
|
"zone_id": 5,
|
||||||
"name": 6,
|
"name": 6,
|
||||||
"type": 7,
|
"type": 7,
|
||||||
"ttl": 8,
|
"ttl": 8,
|
||||||
@ -377,7 +377,7 @@ class SQLAlchemy(object):
|
|||||||
"created_at": 12,
|
"created_at": 12,
|
||||||
"updated_at": 13,
|
"updated_at": 13,
|
||||||
"tenant_id": 14,
|
"tenant_id": 14,
|
||||||
"domain_id": 15,
|
"zone_id": 15,
|
||||||
"recordset_id": 16,
|
"recordset_id": 16,
|
||||||
"data": 17,
|
"data": 17,
|
||||||
"description": 18,
|
"description": 18,
|
||||||
|
@ -227,28 +227,28 @@ class Storage(DriverPlugin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
Create a new Domain.
|
Create a new Zone.
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param domain: Domain object with the values to be created.
|
:param zone: Zone object with the values to be created.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_domain(self, context, domain_id):
|
def get_zone(self, context, zone_id):
|
||||||
"""
|
"""
|
||||||
Get a Domain via its ID.
|
Get a Zone via its ID.
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param domain_id: ID of the Domain.
|
:param zone_id: ID of the Zone.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def find_domains(self, context, criterion=None, marker=None,
|
def find_zones(self, context, criterion=None, marker=None,
|
||||||
limit=None, sort_key=None, sort_dir=None):
|
limit=None, sort_key=None, sort_dir=None):
|
||||||
"""
|
"""
|
||||||
Find Domains
|
Find zones
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param criterion: Criteria to filter by.
|
:param criterion: Criteria to filter by.
|
||||||
@ -261,57 +261,57 @@ class Storage(DriverPlugin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def find_domain(self, context, criterion):
|
def find_zone(self, context, criterion):
|
||||||
"""
|
"""
|
||||||
Find a single Domain.
|
Find a single Zone.
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param criterion: Criteria to filter by.
|
:param criterion: Criteria to filter by.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def update_domain(self, context, domain):
|
def update_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
Update a Domain
|
Update a Zone
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param domain: Domain object.
|
:param zone: Zone object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def delete_domain(self, context, domain_id):
|
def delete_zone(self, context, zone_id):
|
||||||
"""
|
"""
|
||||||
Delete a Domain
|
Delete a Zone
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param domain_id: Domain ID to delete.
|
:param zone_id: Zone ID to delete.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def purge_domain(self, context, zone):
|
def purge_zone(self, context, zone):
|
||||||
"""
|
"""
|
||||||
Purge a Domain
|
Purge a Zone
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param domain: Zone to delete.
|
:param zone: Zone to delete.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def count_domains(self, context, criterion=None):
|
def count_zones(self, context, criterion=None):
|
||||||
"""
|
"""
|
||||||
Count domains
|
Count zones
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param criterion: Criteria to filter by.
|
:param criterion: Criteria to filter by.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def create_recordset(self, context, domain_id, recordset):
|
def create_recordset(self, context, zone_id, recordset):
|
||||||
"""
|
"""
|
||||||
Create a recordset on a given Domain ID
|
Create a recordset on a given Zone ID
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param domain_id: Domain ID to create the recordset in.
|
:param zone_id: Zone ID to create the recordset in.
|
||||||
:param recordset: RecordSet object with the values to be created.
|
:param recordset: RecordSet object with the values to be created.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -386,12 +386,12 @@ class Storage(DriverPlugin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def create_record(self, context, domain_id, recordset_id, record):
|
def create_record(self, context, zone_id, recordset_id, record):
|
||||||
"""
|
"""
|
||||||
Create a record on a given Domain ID
|
Create a record on a given Zone ID
|
||||||
|
|
||||||
:param context: RPC Context.
|
:param context: RPC Context.
|
||||||
:param domain_id: Domain ID to create the record in.
|
:param zone_id: Zone ID to create the record in.
|
||||||
:param recordset_id: RecordSet ID to create the record in.
|
:param recordset_id: RecordSet ID to create the record in.
|
||||||
:param record: Record object with the values to be created.
|
:param record: Record object with the values to be created.
|
||||||
"""
|
"""
|
||||||
|
@ -32,7 +32,7 @@ from designate.storage.impl_sqlalchemy import tables
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
MAXIMUM_SUBDOMAIN_DEPTH = 128
|
MAXIMUM_SUBZONE_DEPTH = 128
|
||||||
|
|
||||||
cfg.CONF.register_group(cfg.OptGroup(
|
cfg.CONF.register_group(cfg.OptGroup(
|
||||||
name='storage:sqlalchemy', title="Configuration for SQLAlchemy Storage"
|
name='storage:sqlalchemy', title="Configuration for SQLAlchemy Storage"
|
||||||
@ -51,7 +51,7 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
def get_name(self):
|
def get_name(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
# CRUD for our resources (quota, server, tsigkey, tenant, domain & record)
|
# CRUD for our resources (quota, server, tsigkey, tenant, zone & record)
|
||||||
# R - get_*, find_*s
|
# R - get_*, find_*s
|
||||||
#
|
#
|
||||||
# Standard Arguments
|
# Standard Arguments
|
||||||
@ -172,18 +172,18 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
# Tenant Methods
|
# Tenant Methods
|
||||||
##
|
##
|
||||||
def find_tenants(self, context):
|
def find_tenants(self, context):
|
||||||
# returns an array of tenant_id & count of their domains
|
# returns an array of tenant_id & count of their zones
|
||||||
query = select([tables.domains.c.tenant_id,
|
query = select([tables.zones.c.tenant_id,
|
||||||
func.count(tables.domains.c.id)])
|
func.count(tables.zones.c.id)])
|
||||||
query = self._apply_tenant_criteria(context, tables.domains, query)
|
query = self._apply_tenant_criteria(context, tables.zones, query)
|
||||||
query = self._apply_deleted_criteria(context, tables.domains, query)
|
query = self._apply_deleted_criteria(context, tables.zones, query)
|
||||||
query = query.group_by(tables.domains.c.tenant_id)
|
query = query.group_by(tables.zones.c.tenant_id)
|
||||||
|
|
||||||
resultproxy = self.session.execute(query)
|
resultproxy = self.session.execute(query)
|
||||||
results = resultproxy.fetchall()
|
results = resultproxy.fetchall()
|
||||||
|
|
||||||
tenant_list = objects.TenantList(
|
tenant_list = objects.TenantList(
|
||||||
objects=[objects.Tenant(id=t[0], domain_count=t[1]) for t in
|
objects=[objects.Tenant(id=t[0], zone_count=t[1]) for t in
|
||||||
results])
|
results])
|
||||||
|
|
||||||
tenant_list.obj_reset_changes()
|
tenant_list.obj_reset_changes()
|
||||||
@ -191,26 +191,26 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
return tenant_list
|
return tenant_list
|
||||||
|
|
||||||
def get_tenant(self, context, tenant_id):
|
def get_tenant(self, context, tenant_id):
|
||||||
# get list list & count of all domains owned by given tenant_id
|
# get list list & count of all zones owned by given tenant_id
|
||||||
query = select([tables.domains.c.name])
|
query = select([tables.zones.c.name])
|
||||||
query = self._apply_tenant_criteria(context, tables.domains, query)
|
query = self._apply_tenant_criteria(context, tables.zones, query)
|
||||||
query = self._apply_deleted_criteria(context, tables.domains, query)
|
query = self._apply_deleted_criteria(context, tables.zones, query)
|
||||||
query = query.where(tables.domains.c.tenant_id == tenant_id)
|
query = query.where(tables.zones.c.tenant_id == tenant_id)
|
||||||
|
|
||||||
resultproxy = self.session.execute(query)
|
resultproxy = self.session.execute(query)
|
||||||
results = resultproxy.fetchall()
|
results = resultproxy.fetchall()
|
||||||
|
|
||||||
return objects.Tenant(
|
return objects.Tenant(
|
||||||
id=tenant_id,
|
id=tenant_id,
|
||||||
domain_count=len(results),
|
zone_count=len(results),
|
||||||
domains=[r[0] for r in results])
|
zones=[r[0] for r in results])
|
||||||
|
|
||||||
def count_tenants(self, context):
|
def count_tenants(self, context):
|
||||||
# tenants are the owner of domains, count the number of unique tenants
|
# tenants are the owner of zones, count the number of unique tenants
|
||||||
# select count(distinct tenant_id) from domains
|
# select count(distinct tenant_id) from zones
|
||||||
query = select([func.count(distinct(tables.domains.c.tenant_id))])
|
query = select([func.count(distinct(tables.zones.c.tenant_id))])
|
||||||
query = self._apply_tenant_criteria(context, tables.domains, query)
|
query = self._apply_tenant_criteria(context, tables.zones, query)
|
||||||
query = self._apply_deleted_criteria(context, tables.domains, query)
|
query = self._apply_deleted_criteria(context, tables.zones, query)
|
||||||
|
|
||||||
resultproxy = self.session.execute(query)
|
resultproxy = self.session.execute(query)
|
||||||
result = resultproxy.fetchone()
|
result = resultproxy.fetchone()
|
||||||
@ -221,95 +221,95 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
return result[0]
|
return result[0]
|
||||||
|
|
||||||
##
|
##
|
||||||
# Domain Methods
|
# Zone Methods
|
||||||
##
|
##
|
||||||
def _find_domains(self, context, criterion, one=False, marker=None,
|
def _find_zones(self, context, criterion, one=False, marker=None,
|
||||||
limit=None, sort_key=None, sort_dir=None):
|
limit=None, sort_key=None, sort_dir=None):
|
||||||
# Check to see if the criterion can use the reverse_name column
|
# Check to see if the criterion can use the reverse_name column
|
||||||
criterion = self._rname_check(criterion)
|
criterion = self._rname_check(criterion)
|
||||||
|
|
||||||
domains = self._find(
|
zones = self._find(
|
||||||
context, tables.domains, objects.Domain, objects.DomainList,
|
context, tables.zones, objects.Zone, objects.ZoneList,
|
||||||
exceptions.DomainNotFound, criterion, one, marker, limit,
|
exceptions.ZoneNotFound, criterion, one, marker, limit,
|
||||||
sort_key, sort_dir)
|
sort_key, sort_dir)
|
||||||
|
|
||||||
def _load_relations(domain):
|
def _load_relations(zone):
|
||||||
if domain.type == 'SECONDARY':
|
if zone.type == 'SECONDARY':
|
||||||
domain.masters = self._find_domain_masters(
|
zone.masters = self._find_zone_masters(
|
||||||
context, {'domain_id': domain.id})
|
context, {'zone_id': zone.id})
|
||||||
else:
|
else:
|
||||||
# This avoids an extra DB call per primary zone. This will
|
# This avoids an extra DB call per primary zone. This will
|
||||||
# always have 0 results for a PRIMARY zone.
|
# always have 0 results for a PRIMARY zone.
|
||||||
domain.masters = objects.DomainMasterList()
|
zone.masters = objects.ZoneMasterList()
|
||||||
|
|
||||||
domain.attributes = self._find_domain_attributes(
|
zone.attributes = self._find_zone_attributes(
|
||||||
context, {'domain_id': domain.id, "key": "!master"})
|
context, {'zone_id': zone.id, "key": "!master"})
|
||||||
|
|
||||||
domain.obj_reset_changes(['masters', 'attributes'])
|
zone.obj_reset_changes(['masters', 'attributes'])
|
||||||
|
|
||||||
if one:
|
if one:
|
||||||
_load_relations(domains)
|
_load_relations(zones)
|
||||||
else:
|
else:
|
||||||
domains.total_count = self.count_domains(context, criterion)
|
zones.total_count = self.count_zones(context, criterion)
|
||||||
for d in domains:
|
for d in zones:
|
||||||
_load_relations(d)
|
_load_relations(d)
|
||||||
|
|
||||||
return domains
|
return zones
|
||||||
|
|
||||||
def create_domain(self, context, domain):
|
def create_zone(self, context, zone):
|
||||||
# Patch in the reverse_name column
|
# Patch in the reverse_name column
|
||||||
extra_values = {"reverse_name": domain.name[::-1]}
|
extra_values = {"reverse_name": zone.name[::-1]}
|
||||||
|
|
||||||
# Don't handle recordsets for now
|
# Don't handle recordsets for now
|
||||||
domain = self._create(
|
zone = self._create(
|
||||||
tables.domains, domain, exceptions.DuplicateDomain,
|
tables.zones, zone, exceptions.DuplicateZone,
|
||||||
['attributes', 'recordsets', 'masters'],
|
['attributes', 'recordsets', 'masters'],
|
||||||
extra_values=extra_values)
|
extra_values=extra_values)
|
||||||
|
|
||||||
if domain.obj_attr_is_set('attributes'):
|
if zone.obj_attr_is_set('attributes'):
|
||||||
for attrib in domain.attributes:
|
for attrib in zone.attributes:
|
||||||
self.create_domain_attribute(context, domain.id, attrib)
|
self.create_zone_attribute(context, zone.id, attrib)
|
||||||
else:
|
else:
|
||||||
domain.attributes = objects.DomainAttributeList()
|
zone.attributes = objects.ZoneAttributeList()
|
||||||
if domain.obj_attr_is_set('masters'):
|
if zone.obj_attr_is_set('masters'):
|
||||||
for master in domain.masters:
|
for master in zone.masters:
|
||||||
self.create_domain_master(context, domain.id, master)
|
self.create_zone_master(context, zone.id, master)
|
||||||
else:
|
else:
|
||||||
domain.masters = objects.DomainMasterList()
|
zone.masters = objects.ZoneMasterList()
|
||||||
domain.obj_reset_changes(['masters', 'attributes'])
|
zone.obj_reset_changes(['masters', 'attributes'])
|
||||||
|
|
||||||
return domain
|
return zone
|
||||||
|
|
||||||
def get_domain(self, context, domain_id):
|
def get_zone(self, context, zone_id):
|
||||||
domain = self._find_domains(context, {'id': domain_id}, one=True)
|
zone = self._find_zones(context, {'id': zone_id}, one=True)
|
||||||
return domain
|
return zone
|
||||||
|
|
||||||
def find_domains(self, context, criterion=None, marker=None, limit=None,
|
def find_zones(self, context, criterion=None, marker=None, limit=None,
|
||||||
sort_key=None, sort_dir=None):
|
sort_key=None, sort_dir=None):
|
||||||
domains = self._find_domains(context, criterion, marker=marker,
|
zones = self._find_zones(context, criterion, marker=marker,
|
||||||
limit=limit, sort_key=sort_key,
|
limit=limit, sort_key=sort_key,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir)
|
||||||
return domains
|
return zones
|
||||||
|
|
||||||
def find_domain(self, context, criterion):
|
def find_zone(self, context, criterion):
|
||||||
domain = self._find_domains(context, criterion, one=True)
|
zone = self._find_zones(context, criterion, one=True)
|
||||||
return domain
|
return zone
|
||||||
|
|
||||||
def update_domain(self, context, domain):
|
def update_zone(self, context, zone):
|
||||||
tenant_id_changed = False
|
tenant_id_changed = False
|
||||||
if 'tenant_id' in domain.obj_what_changed():
|
if 'tenant_id' in zone.obj_what_changed():
|
||||||
tenant_id_changed = True
|
tenant_id_changed = True
|
||||||
|
|
||||||
# Don't handle recordsets for now
|
# Don't handle recordsets for now
|
||||||
updated_domain = self._update(
|
updated_zone = self._update(
|
||||||
context, tables.domains, domain, exceptions.DuplicateDomain,
|
context, tables.zones, zone, exceptions.DuplicateZone,
|
||||||
exceptions.DomainNotFound,
|
exceptions.ZoneNotFound,
|
||||||
['attributes', 'recordsets', 'masters'])
|
['attributes', 'recordsets', 'masters'])
|
||||||
|
|
||||||
if domain.obj_attr_is_set('attributes'):
|
if zone.obj_attr_is_set('attributes'):
|
||||||
# Gather the Attribute ID's we have
|
# Gather the Attribute ID's we have
|
||||||
have = set([r.id for r in self._find_domain_attributes(
|
have = set([r.id for r in self._find_zone_attributes(
|
||||||
context, {'domain_id': domain.id})])
|
context, {'zone_id': zone.id})])
|
||||||
|
|
||||||
# Prep some lists of changes
|
# Prep some lists of changes
|
||||||
keep = set([])
|
keep = set([])
|
||||||
@ -317,7 +317,7 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
update = []
|
update = []
|
||||||
|
|
||||||
# Determine what to change
|
# Determine what to change
|
||||||
for i in domain.attributes:
|
for i in zone.attributes:
|
||||||
keep.add(i.id)
|
keep.add(i.id)
|
||||||
try:
|
try:
|
||||||
i.obj_get_original_value('id')
|
i.obj_get_original_value('id')
|
||||||
@ -329,27 +329,27 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
# NOTE: Since we're dealing with mutable objects, the return value
|
# NOTE: Since we're dealing with mutable objects, the return value
|
||||||
# of create/update/delete attribute is not needed.
|
# of create/update/delete attribute is not needed.
|
||||||
# The original item will be mutated in place on the input
|
# The original item will be mutated in place on the input
|
||||||
# "domain.attributes" list.
|
# "zone.attributes" list.
|
||||||
|
|
||||||
# Delete Attributes
|
# Delete Attributes
|
||||||
for i_id in have - keep:
|
for i_id in have - keep:
|
||||||
attr = self._find_domain_attributes(
|
attr = self._find_zone_attributes(
|
||||||
context, {'id': i_id}, one=True)
|
context, {'id': i_id}, one=True)
|
||||||
self.delete_domain_attribute(context, attr.id)
|
self.delete_zone_attribute(context, attr.id)
|
||||||
|
|
||||||
# Update Attributes
|
# Update Attributes
|
||||||
for i in update:
|
for i in update:
|
||||||
self.update_domain_attribute(context, i)
|
self.update_zone_attribute(context, i)
|
||||||
|
|
||||||
# Create Attributes
|
# Create Attributes
|
||||||
for attr in create:
|
for attr in create:
|
||||||
attr.domain_id = domain.id
|
attr.zone_id = zone.id
|
||||||
self.create_domain_attribute(context, domain.id, attr)
|
self.create_zone_attribute(context, zone.id, attr)
|
||||||
|
|
||||||
if domain.obj_attr_is_set('masters'):
|
if zone.obj_attr_is_set('masters'):
|
||||||
# Gather the Attribute ID's we have
|
# Gather the Attribute ID's we have
|
||||||
have = set([r.id for r in self._find_domain_masters(
|
have = set([r.id for r in self._find_zone_masters(
|
||||||
context, {'domain_id': domain.id})])
|
context, {'zone_id': zone.id})])
|
||||||
|
|
||||||
# Prep some lists of changes
|
# Prep some lists of changes
|
||||||
keep = set([])
|
keep = set([])
|
||||||
@ -357,7 +357,7 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
update = []
|
update = []
|
||||||
|
|
||||||
# Determine what to change
|
# Determine what to change
|
||||||
for i in domain.masters:
|
for i in zone.masters:
|
||||||
keep.add(i.id)
|
keep.add(i.id)
|
||||||
try:
|
try:
|
||||||
i.obj_get_original_value('id')
|
i.obj_get_original_value('id')
|
||||||
@ -369,32 +369,32 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
# NOTE: Since we're dealing with mutable objects, the return value
|
# NOTE: Since we're dealing with mutable objects, the return value
|
||||||
# of create/update/delete attribute is not needed.
|
# of create/update/delete attribute is not needed.
|
||||||
# The original item will be mutated in place on the input
|
# The original item will be mutated in place on the input
|
||||||
# "domain.attributes" list.
|
# "zone.attributes" list.
|
||||||
|
|
||||||
# Delete Attributes
|
# Delete Attributes
|
||||||
for i_id in have - keep:
|
for i_id in have - keep:
|
||||||
attr = self._find_domain_masters(
|
attr = self._find_zone_masters(
|
||||||
context, {'id': i_id}, one=True)
|
context, {'id': i_id}, one=True)
|
||||||
self.delete_domain_master(context, attr.id)
|
self.delete_zone_master(context, attr.id)
|
||||||
|
|
||||||
# Update Attributes
|
# Update Attributes
|
||||||
for i in update:
|
for i in update:
|
||||||
self.update_domain_master(context, i)
|
self.update_zone_master(context, i)
|
||||||
|
|
||||||
# Create Attributes
|
# Create Attributes
|
||||||
for attr in create:
|
for attr in create:
|
||||||
attr.domain_id = domain.id
|
attr.zone_id = zone.id
|
||||||
self.create_domain_master(context, domain.id, attr)
|
self.create_zone_master(context, zone.id, attr)
|
||||||
|
|
||||||
if domain.obj_attr_is_set('recordsets'):
|
if zone.obj_attr_is_set('recordsets'):
|
||||||
existing = self.find_recordsets(context, {'domain_id': domain.id})
|
existing = self.find_recordsets(context, {'zone_id': zone.id})
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
for rrset in existing:
|
for rrset in existing:
|
||||||
data[rrset.name, rrset.type] = rrset
|
data[rrset.name, rrset.type] = rrset
|
||||||
|
|
||||||
keep = set()
|
keep = set()
|
||||||
for rrset in domain.recordsets:
|
for rrset in zone.recordsets:
|
||||||
current = data.get((rrset.name, rrset.type))
|
current = data.get((rrset.name, rrset.type))
|
||||||
|
|
||||||
if current:
|
if current:
|
||||||
@ -403,67 +403,67 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
self.update_recordset(context, current)
|
self.update_recordset(context, current)
|
||||||
keep.add(current.id)
|
keep.add(current.id)
|
||||||
else:
|
else:
|
||||||
self.create_recordset(context, domain.id, rrset)
|
self.create_recordset(context, zone.id, rrset)
|
||||||
keep.add(rrset.id)
|
keep.add(rrset.id)
|
||||||
|
|
||||||
if domain.type == 'SECONDARY':
|
if zone.type == 'SECONDARY':
|
||||||
# Purge anything that shouldn't be there :P
|
# Purge anything that shouldn't be there :P
|
||||||
for i in set([i.id for i in data.values()]) - keep:
|
for i in set([i.id for i in data.values()]) - keep:
|
||||||
self.delete_recordset(context, i)
|
self.delete_recordset(context, i)
|
||||||
|
|
||||||
if tenant_id_changed:
|
if tenant_id_changed:
|
||||||
recordsets_query = tables.recordsets.update().\
|
recordsets_query = tables.recordsets.update().\
|
||||||
where(tables.recordsets.c.domain_id == domain.id)\
|
where(tables.recordsets.c.zone_id == zone.id)\
|
||||||
.values({'tenant_id': domain.tenant_id})
|
.values({'tenant_id': zone.tenant_id})
|
||||||
|
|
||||||
records_query = tables.records.update().\
|
records_query = tables.records.update().\
|
||||||
where(tables.records.c.domain_id == domain.id).\
|
where(tables.records.c.zone_id == zone.id).\
|
||||||
values({'tenant_id': domain.tenant_id})
|
values({'tenant_id': zone.tenant_id})
|
||||||
|
|
||||||
self.session.execute(records_query)
|
self.session.execute(records_query)
|
||||||
self.session.execute(recordsets_query)
|
self.session.execute(recordsets_query)
|
||||||
|
|
||||||
return updated_domain
|
return updated_zone
|
||||||
|
|
||||||
def delete_domain(self, context, domain_id):
|
def delete_zone(self, context, zone_id):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
# Fetch the existing domain, we'll need to return it.
|
# Fetch the existing zone, we'll need to return it.
|
||||||
domain = self._find_domains(context, {'id': domain_id}, one=True)
|
zone = self._find_zones(context, {'id': zone_id}, one=True)
|
||||||
return self._delete(context, tables.domains, domain,
|
return self._delete(context, tables.zones, zone,
|
||||||
exceptions.DomainNotFound)
|
exceptions.ZoneNotFound)
|
||||||
|
|
||||||
def purge_domain(self, context, zone):
|
def purge_zone(self, context, zone):
|
||||||
"""Effectively remove a zone database record.
|
"""Effectively remove a zone database record.
|
||||||
"""
|
"""
|
||||||
return self._delete(context, tables.domains, zone,
|
return self._delete(context, tables.zones, zone,
|
||||||
exceptions.DomainNotFound, hard_delete=True)
|
exceptions.ZoneNotFound, hard_delete=True)
|
||||||
|
|
||||||
def _walk_up_domains(self, current, zones_by_id):
|
def _walk_up_zones(self, current, zones_by_id):
|
||||||
"""Walk upwards in a zone hierarchy until we find a parent zone
|
"""Walk upwards in a zone hierarchy until we find a parent zone
|
||||||
that does not belong to "zones_by_id"
|
that does not belong to "zones_by_id"
|
||||||
:returns: parent zone ID or None
|
:returns: parent zone ID or None
|
||||||
"""
|
"""
|
||||||
max_steps = MAXIMUM_SUBDOMAIN_DEPTH
|
max_steps = MAXIMUM_SUBZONE_DEPTH
|
||||||
while current.parent_domain_id in zones_by_id:
|
while current.parent_zone_id in zones_by_id:
|
||||||
current = zones_by_id[current.parent_domain_id]
|
current = zones_by_id[current.parent_zone_id]
|
||||||
max_steps -= 1
|
max_steps -= 1
|
||||||
if max_steps == 0:
|
if max_steps == 0:
|
||||||
raise exceptions.IllegalParentDomain("Loop detected in the"
|
raise exceptions.IllegalParentZone("Loop detected in the"
|
||||||
" domain hierarchy")
|
" zone hierarchy")
|
||||||
|
|
||||||
return current.parent_domain_id
|
return current.parent_zone_id
|
||||||
|
|
||||||
def purge_domains(self, context, criterion, limit):
|
def purge_zones(self, context, criterion, limit):
|
||||||
"""Purge deleted zones.
|
"""Purge deleted zones.
|
||||||
Reparent orphan childrens, if any.
|
Reparent orphan childrens, if any.
|
||||||
Transactions/locks are not needed.
|
Transactions/locks are not needed.
|
||||||
:returns: number of purged domains
|
:returns: number of purged zones
|
||||||
"""
|
"""
|
||||||
if 'deleted' in criterion:
|
if 'deleted' in criterion:
|
||||||
context.show_deleted = True
|
context.show_deleted = True
|
||||||
|
|
||||||
zones = self.find_domains(
|
zones = self.find_zones(
|
||||||
context=context,
|
context=context,
|
||||||
criterion=criterion,
|
criterion=criterion,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
@ -479,24 +479,24 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
for zone in zones:
|
for zone in zones:
|
||||||
|
|
||||||
# Reparent child zones, if any.
|
# Reparent child zones, if any.
|
||||||
surviving_parent_id = self._walk_up_domains(zone, zones_by_id)
|
surviving_parent_id = self._walk_up_zones(zone, zones_by_id)
|
||||||
query = tables.domains.update().\
|
query = tables.zones.update().\
|
||||||
where(tables.domains.c.parent_domain_id == zone.id).\
|
where(tables.zones.c.parent_zone_id == zone.id).\
|
||||||
values(parent_domain_id=surviving_parent_id)
|
values(parent_zone_id=surviving_parent_id)
|
||||||
|
|
||||||
resultproxy = self.session.execute(query)
|
resultproxy = self.session.execute(query)
|
||||||
LOG.debug(_LI("%d child zones updated"), resultproxy.rowcount)
|
LOG.debug(_LI("%d child zones updated"), resultproxy.rowcount)
|
||||||
|
|
||||||
self.purge_domain(context, zone)
|
self.purge_zone(context, zone)
|
||||||
|
|
||||||
LOG.info(_LI("Purged %d zones"), len(zones))
|
LOG.info(_LI("Purged %d zones"), len(zones))
|
||||||
return len(zones)
|
return len(zones)
|
||||||
|
|
||||||
def count_domains(self, context, criterion=None):
|
def count_zones(self, context, criterion=None):
|
||||||
query = select([func.count(tables.domains.c.id)])
|
query = select([func.count(tables.zones.c.id)])
|
||||||
query = self._apply_criterion(tables.domains, query, criterion)
|
query = self._apply_criterion(tables.zones, query, criterion)
|
||||||
query = self._apply_tenant_criteria(context, tables.domains, query)
|
query = self._apply_tenant_criteria(context, tables.zones, query)
|
||||||
query = self._apply_deleted_criteria(context, tables.domains, query)
|
query = self._apply_deleted_criteria(context, tables.zones, query)
|
||||||
|
|
||||||
resultproxy = self.session.execute(query)
|
resultproxy = self.session.execute(query)
|
||||||
result = resultproxy.fetchone()
|
result = resultproxy.fetchone()
|
||||||
@ -506,112 +506,112 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
|
|
||||||
return result[0]
|
return result[0]
|
||||||
|
|
||||||
# Domain attribute methods
|
# Zone attribute methods
|
||||||
def _find_domain_attributes(self, context, criterion, one=False,
|
def _find_zone_attributes(self, context, criterion, one=False,
|
||||||
marker=None, limit=None, sort_key=None,
|
marker=None, limit=None, sort_key=None,
|
||||||
sort_dir=None):
|
sort_dir=None):
|
||||||
return self._find(context, tables.domain_attributes,
|
return self._find(context, tables.zone_attributes,
|
||||||
objects.DomainAttribute, objects.DomainAttributeList,
|
objects.ZoneAttribute, objects.ZoneAttributeList,
|
||||||
exceptions.DomainAttributeNotFound, criterion, one,
|
exceptions.ZoneAttributeNotFound, criterion, one,
|
||||||
marker, limit, sort_key, sort_dir)
|
marker, limit, sort_key, sort_dir)
|
||||||
|
|
||||||
def create_domain_attribute(self, context, domain_id, domain_attribute):
|
def create_zone_attribute(self, context, zone_id, zone_attribute):
|
||||||
domain_attribute.domain_id = domain_id
|
zone_attribute.zone_id = zone_id
|
||||||
return self._create(tables.domain_attributes, domain_attribute,
|
return self._create(tables.zone_attributes, zone_attribute,
|
||||||
exceptions.DuplicateDomainAttribute)
|
exceptions.DuplicateZoneAttribute)
|
||||||
|
|
||||||
def get_domain_attributes(self, context, domain_attribute_id):
|
def get_zone_attributes(self, context, zone_attribute_id):
|
||||||
return self._find_domain_attributes(
|
return self._find_zone_attributes(
|
||||||
context, {'id': domain_attribute_id}, one=True)
|
context, {'id': zone_attribute_id}, one=True)
|
||||||
|
|
||||||
def find_domain_attributes(self, context, criterion=None, marker=None,
|
def find_zone_attributes(self, context, criterion=None, marker=None,
|
||||||
limit=None, sort_key=None, sort_dir=None):
|
limit=None, sort_key=None, sort_dir=None):
|
||||||
return self._find_domain_attributes(context, criterion, marker=marker,
|
return self._find_zone_attributes(context, criterion, marker=marker,
|
||||||
limit=limit, sort_key=sort_key,
|
limit=limit, sort_key=sort_key,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir)
|
||||||
|
|
||||||
def find_domain_attribute(self, context, criterion):
|
def find_zone_attribute(self, context, criterion):
|
||||||
return self._find_domain_attributes(context, criterion, one=True)
|
return self._find_zone_attributes(context, criterion, one=True)
|
||||||
|
|
||||||
def update_domain_attribute(self, context, domain_attribute):
|
def update_zone_attribute(self, context, zone_attribute):
|
||||||
return self._update(context, tables.domain_attributes,
|
return self._update(context, tables.zone_attributes,
|
||||||
domain_attribute,
|
zone_attribute,
|
||||||
exceptions.DuplicateDomainAttribute,
|
exceptions.DuplicateZoneAttribute,
|
||||||
exceptions.DomainAttributeNotFound)
|
exceptions.ZoneAttributeNotFound)
|
||||||
|
|
||||||
def delete_domain_attribute(self, context, domain_attribute_id):
|
def delete_zone_attribute(self, context, zone_attribute_id):
|
||||||
domain_attribute = self._find_domain_attributes(
|
zone_attribute = self._find_zone_attributes(
|
||||||
context, {'id': domain_attribute_id}, one=True)
|
context, {'id': zone_attribute_id}, one=True)
|
||||||
deleted_domain_attribute = self._delete(
|
deleted_zone_attribute = self._delete(
|
||||||
context, tables.domain_attributes, domain_attribute,
|
context, tables.zone_attributes, zone_attribute,
|
||||||
exceptions.DomainAttributeNotFound)
|
exceptions.ZoneAttributeNotFound)
|
||||||
|
|
||||||
return deleted_domain_attribute
|
return deleted_zone_attribute
|
||||||
|
|
||||||
# Domain master methods
|
# Zone master methods
|
||||||
def _find_domain_masters(self, context, criterion, one=False,
|
def _find_zone_masters(self, context, criterion, one=False,
|
||||||
marker=None, limit=None, sort_key=None,
|
marker=None, limit=None, sort_key=None,
|
||||||
sort_dir=None):
|
sort_dir=None):
|
||||||
|
|
||||||
criterion['key'] = 'master'
|
criterion['key'] = 'master'
|
||||||
|
|
||||||
attribs = self._find(context, tables.domain_attributes,
|
attribs = self._find(context, tables.zone_attributes,
|
||||||
objects.DomainAttribute,
|
objects.ZoneAttribute,
|
||||||
objects.DomainAttributeList,
|
objects.ZoneAttributeList,
|
||||||
exceptions.DomainMasterNotFound,
|
exceptions.ZoneMasterNotFound,
|
||||||
criterion, one,
|
criterion, one,
|
||||||
marker, limit, sort_key, sort_dir)
|
marker, limit, sort_key, sort_dir)
|
||||||
|
|
||||||
masters = objects.DomainMasterList()
|
masters = objects.ZoneMasterList()
|
||||||
|
|
||||||
for attrib in attribs:
|
for attrib in attribs:
|
||||||
masters.append(objects.DomainMaster().from_data(attrib.value))
|
masters.append(objects.ZoneMaster().from_data(attrib.value))
|
||||||
|
|
||||||
return masters
|
return masters
|
||||||
|
|
||||||
def create_domain_master(self, context, domain_id, domain_master):
|
def create_zone_master(self, context, zone_id, zone_master):
|
||||||
|
|
||||||
domain_attribute = objects.DomainAttribute()
|
zone_attribute = objects.ZoneAttribute()
|
||||||
domain_attribute.domain_id = domain_id
|
zone_attribute.zone_id = zone_id
|
||||||
domain_attribute.key = 'master'
|
zone_attribute.key = 'master'
|
||||||
domain_attribute.value = domain_master.to_data()
|
zone_attribute.value = zone_master.to_data()
|
||||||
|
|
||||||
return self._create(tables.domain_attributes, domain_attribute,
|
return self._create(tables.zone_attributes, zone_attribute,
|
||||||
exceptions.DuplicateDomainAttribute)
|
exceptions.DuplicateZoneAttribute)
|
||||||
|
|
||||||
def get_domain_masters(self, context, domain_attribute_id):
|
def get_zone_masters(self, context, zone_attribute_id):
|
||||||
return self._find_domain_masters(
|
return self._find_zone_masters(
|
||||||
context, {'id': domain_attribute_id}, one=True)
|
context, {'id': zone_attribute_id}, one=True)
|
||||||
|
|
||||||
def find_domain_masters(self, context, criterion=None, marker=None,
|
def find_zone_masters(self, context, criterion=None, marker=None,
|
||||||
limit=None, sort_key=None, sort_dir=None):
|
limit=None, sort_key=None, sort_dir=None):
|
||||||
return self._find_domain_masters(context, criterion, marker=marker,
|
return self._find_zone_masters(context, criterion, marker=marker,
|
||||||
limit=limit, sort_key=sort_key,
|
limit=limit, sort_key=sort_key,
|
||||||
sort_dir=sort_dir)
|
sort_dir=sort_dir)
|
||||||
|
|
||||||
def find_domain_master(self, context, criterion):
|
def find_zone_master(self, context, criterion):
|
||||||
return self._find_domain_master(context, criterion, one=True)
|
return self._find_zone_master(context, criterion, one=True)
|
||||||
|
|
||||||
def update_domain_master(self, context, domain_master):
|
def update_zone_master(self, context, zone_master):
|
||||||
|
|
||||||
domain_attribute = objects.DomainAttribute()
|
zone_attribute = objects.ZoneAttribute()
|
||||||
domain_attribute.domain_id = domain_master.domain_id
|
zone_attribute.zone_id = zone_master.zone_id
|
||||||
domain_attribute.key = 'master'
|
zone_attribute.key = 'master'
|
||||||
domain_attribute.value = domain_master.to_data()
|
zone_attribute.value = zone_master.to_data()
|
||||||
|
|
||||||
return self._update(context, tables.domain_attributes,
|
return self._update(context, tables.zone_attributes,
|
||||||
domain_attribute,
|
zone_attribute,
|
||||||
exceptions.DuplicateDomainAttribute,
|
exceptions.DuplicateZoneAttribute,
|
||||||
exceptions.DomainAttributeNotFound)
|
exceptions.ZoneAttributeNotFound)
|
||||||
|
|
||||||
def delete_domain_master(self, context, domain_master_id):
|
def delete_zone_master(self, context, zone_master_id):
|
||||||
domain_attribute = self._find_domain_attributes(
|
zone_attribute = self._find_zone_attributes(
|
||||||
context, {'id': domain_master_id}, one=True)
|
context, {'id': zone_master_id}, one=True)
|
||||||
deleted_domain_attribute = self._delete(
|
deleted_zone_attribute = self._delete(
|
||||||
context, tables.domain_attributes, domain_attribute,
|
context, tables.zone_attributes, zone_attribute,
|
||||||
exceptions.DomainAttributeNotFound)
|
exceptions.ZoneAttributeNotFound)
|
||||||
|
|
||||||
return deleted_domain_attribute
|
return deleted_zone_attribute
|
||||||
|
|
||||||
# RecordSet Methods
|
# RecordSet Methods
|
||||||
def _find_recordsets(self, context, criterion, one=False, marker=None,
|
def _find_recordsets(self, context, criterion, one=False, marker=None,
|
||||||
@ -621,17 +621,17 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
criterion = self._rname_check(criterion)
|
criterion = self._rname_check(criterion)
|
||||||
|
|
||||||
if criterion is not None \
|
if criterion is not None \
|
||||||
and not criterion.get('domains_deleted', True):
|
and not criterion.get('zones_deleted', True):
|
||||||
# remove 'domains_deleted' from the criterion, as _apply_criterion
|
# remove 'zones_deleted' from the criterion, as _apply_criterion
|
||||||
# assumes each key in criterion to be a column name.
|
# assumes each key in criterion to be a column name.
|
||||||
del criterion['domains_deleted']
|
del criterion['zones_deleted']
|
||||||
|
|
||||||
if one:
|
if one:
|
||||||
rjoin = tables.recordsets.join(
|
rjoin = tables.recordsets.join(
|
||||||
tables.domains,
|
tables.zones,
|
||||||
tables.recordsets.c.domain_id == tables.domains.c.id)
|
tables.recordsets.c.zone_id == tables.zones.c.id)
|
||||||
query = select([tables.recordsets]).select_from(rjoin).\
|
query = select([tables.recordsets]).select_from(rjoin).\
|
||||||
where(tables.domains.c.deleted == '0')
|
where(tables.zones.c.deleted == '0')
|
||||||
|
|
||||||
recordsets = self._find(
|
recordsets = self._find(
|
||||||
context, tables.recordsets, objects.RecordSet,
|
context, tables.recordsets, objects.RecordSet,
|
||||||
@ -678,12 +678,12 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
|
|
||||||
return raw_rows
|
return raw_rows
|
||||||
|
|
||||||
def create_recordset(self, context, domain_id, recordset):
|
def create_recordset(self, context, zone_id, recordset):
|
||||||
# Fetch the domain as we need the tenant_id
|
# Fetch the zone as we need the tenant_id
|
||||||
domain = self._find_domains(context, {'id': domain_id}, one=True)
|
zone = self._find_zones(context, {'id': zone_id}, one=True)
|
||||||
|
|
||||||
recordset.tenant_id = domain.tenant_id
|
recordset.tenant_id = zone.tenant_id
|
||||||
recordset.domain_id = domain_id
|
recordset.zone_id = zone_id
|
||||||
|
|
||||||
# Patch in the reverse_name column
|
# Patch in the reverse_name column
|
||||||
extra_values = {"reverse_name": recordset.name[::-1]}
|
extra_values = {"reverse_name": recordset.name[::-1]}
|
||||||
@ -697,7 +697,7 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
# NOTE: Since we're dealing with a mutable object, the return
|
# NOTE: Since we're dealing with a mutable object, the return
|
||||||
# value is not needed. The original item will be mutated
|
# value is not needed. The original item will be mutated
|
||||||
# in place on the input "recordset.records" list.
|
# in place on the input "recordset.records" list.
|
||||||
self.create_record(context, domain_id, recordset.id, record)
|
self.create_record(context, zone_id, recordset.id, record)
|
||||||
else:
|
else:
|
||||||
recordset.records = objects.RecordList()
|
recordset.records = objects.RecordList()
|
||||||
|
|
||||||
@ -777,7 +777,7 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
# Create Records
|
# Create Records
|
||||||
for record in create_records:
|
for record in create_records:
|
||||||
self.create_record(
|
self.create_record(
|
||||||
context, recordset.domain_id, recordset.id, record)
|
context, recordset.zone_id, recordset.id, record)
|
||||||
|
|
||||||
return recordset
|
return recordset
|
||||||
|
|
||||||
@ -792,12 +792,12 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
def count_recordsets(self, context, criterion=None):
|
def count_recordsets(self, context, criterion=None):
|
||||||
# Ensure that we return only active recordsets
|
# Ensure that we return only active recordsets
|
||||||
rjoin = tables.recordsets.join(
|
rjoin = tables.recordsets.join(
|
||||||
tables.domains,
|
tables.zones,
|
||||||
tables.recordsets.c.domain_id == tables.domains.c.id)
|
tables.recordsets.c.zone_id == tables.zones.c.id)
|
||||||
|
|
||||||
query = select([func.count(tables.recordsets.c.id)]).\
|
query = select([func.count(tables.recordsets.c.id)]).\
|
||||||
select_from(rjoin).\
|
select_from(rjoin).\
|
||||||
where(tables.domains.c.deleted == '0')
|
where(tables.zones.c.deleted == '0')
|
||||||
|
|
||||||
query = self._apply_criterion(tables.recordsets, query, criterion)
|
query = self._apply_criterion(tables.recordsets, query, criterion)
|
||||||
query = self._apply_tenant_criteria(context, tables.recordsets, query)
|
query = self._apply_tenant_criteria(context, tables.recordsets, query)
|
||||||
@ -829,12 +829,12 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
|
|
||||||
return md5.hexdigest()
|
return md5.hexdigest()
|
||||||
|
|
||||||
def create_record(self, context, domain_id, recordset_id, record):
|
def create_record(self, context, zone_id, recordset_id, record):
|
||||||
# Fetch the domain as we need the tenant_id
|
# Fetch the zone as we need the tenant_id
|
||||||
domain = self._find_domains(context, {'id': domain_id}, one=True)
|
zone = self._find_zones(context, {'id': zone_id}, one=True)
|
||||||
|
|
||||||
record.tenant_id = domain.tenant_id
|
record.tenant_id = zone.tenant_id
|
||||||
record.domain_id = domain_id
|
record.zone_id = zone_id
|
||||||
record.recordset_id = recordset_id
|
record.recordset_id = recordset_id
|
||||||
record.hash = self._recalculate_record_hash(record)
|
record.hash = self._recalculate_record_hash(record)
|
||||||
|
|
||||||
@ -870,12 +870,12 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
def count_records(self, context, criterion=None):
|
def count_records(self, context, criterion=None):
|
||||||
# Ensure that we return only active records
|
# Ensure that we return only active records
|
||||||
rjoin = tables.records.join(
|
rjoin = tables.records.join(
|
||||||
tables.domains,
|
tables.zones,
|
||||||
tables.records.c.domain_id == tables.domains.c.id)
|
tables.records.c.zone_id == tables.zones.c.id)
|
||||||
|
|
||||||
query = select([func.count(tables.records.c.id)]).\
|
query = select([func.count(tables.records.c.id)]).\
|
||||||
select_from(rjoin).\
|
select_from(rjoin).\
|
||||||
where(tables.domains.c.deleted == '0')
|
where(tables.zones.c.deleted == '0')
|
||||||
|
|
||||||
query = self._apply_criterion(tables.records, query, criterion)
|
query = self._apply_criterion(tables.records, query, criterion)
|
||||||
query = self._apply_tenant_criteria(context, tables.records, query)
|
query = self._apply_tenant_criteria(context, tables.records, query)
|
||||||
@ -1180,11 +1180,11 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
table = tables.zone_transfer_requests
|
table = tables.zone_transfer_requests
|
||||||
|
|
||||||
ljoin = tables.zone_transfer_requests.join(
|
ljoin = tables.zone_transfer_requests.join(
|
||||||
tables.domains,
|
tables.zones,
|
||||||
tables.zone_transfer_requests.c.domain_id == tables.domains.c.id)
|
tables.zone_transfer_requests.c.zone_id == tables.zones.c.id)
|
||||||
|
|
||||||
query = select(
|
query = select(
|
||||||
[table, tables.domains.c.name.label("domain_name")]
|
[table, tables.zones.c.name.label("zone_name")]
|
||||||
).select_from(ljoin)
|
).select_from(ljoin)
|
||||||
|
|
||||||
if not context.all_tenants:
|
if not context.all_tenants:
|
||||||
@ -1204,7 +1204,7 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
def create_zone_transfer_request(self, context, zone_transfer_request):
|
def create_zone_transfer_request(self, context, zone_transfer_request):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
criterion = {"domain_id": zone_transfer_request.domain_id,
|
criterion = {"zone_id": zone_transfer_request.zone_id,
|
||||||
"status": "ACTIVE"}
|
"status": "ACTIVE"}
|
||||||
self.find_zone_transfer_request(
|
self.find_zone_transfer_request(
|
||||||
context, criterion)
|
context, criterion)
|
||||||
@ -1239,7 +1239,7 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
|
|
||||||
def update_zone_transfer_request(self, context, zone_transfer_request):
|
def update_zone_transfer_request(self, context, zone_transfer_request):
|
||||||
|
|
||||||
zone_transfer_request.obj_reset_changes(('domain_name'))
|
zone_transfer_request.obj_reset_changes(('zone_name'))
|
||||||
|
|
||||||
updated_zt_request = self._update(
|
updated_zt_request = self._update(
|
||||||
context,
|
context,
|
||||||
@ -1247,7 +1247,7 @@ class SQLAlchemyStorage(sqlalchemy_base.SQLAlchemy, storage_base.Storage):
|
|||||||
zone_transfer_request,
|
zone_transfer_request,
|
||||||
exceptions.DuplicateZoneTransferRequest,
|
exceptions.DuplicateZoneTransferRequest,
|
||||||
exceptions.ZoneTransferRequestNotFound,
|
exceptions.ZoneTransferRequestNotFound,
|
||||||
skip_values=['domain_name'])
|
skip_values=['zone_name'])
|
||||||
|
|
||||||
return updated_zt_request
|
return updated_zt_request
|
||||||
|
|
||||||
|
@ -0,0 +1,139 @@
|
|||||||
|
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# Author: Graham Hayes <graham.hayes@hpe.com>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
# See https://blueprints.launchpad.net/nova/+spec/backportable-db-migrations
|
||||||
|
# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
|
||||||
|
from sqlalchemy.schema import MetaData, Table, Index
|
||||||
|
from migrate.changeset.constraint import UniqueConstraint, \
|
||||||
|
ForeignKeyConstraint, PathNotFoundError
|
||||||
|
|
||||||
|
|
||||||
|
# This migration removes all references to domain from our Database.
|
||||||
|
# We rename the domains and domain_attribute tables, and rename any columns
|
||||||
|
# that had "domain" in the name.as
|
||||||
|
# There is a follow on patch to recreate the FKs for the newly renamed
|
||||||
|
# tables as the lib we use doesn't seem to like creating FKs on renamed
|
||||||
|
# tables until after the migration is complete.
|
||||||
|
|
||||||
|
meta = MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
def index_exists(index):
|
||||||
|
table = index[1]._get_table()
|
||||||
|
cols = sorted([str(x).split('.')[1] for x in index[1:]])
|
||||||
|
|
||||||
|
for idx in table.indexes:
|
||||||
|
if sorted(idx.columns.keys()) == cols:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def drop_index(index):
|
||||||
|
if index_exists(index):
|
||||||
|
index = Index(*index)
|
||||||
|
index.drop()
|
||||||
|
|
||||||
|
|
||||||
|
def drop_foreign_key(fk_def):
|
||||||
|
|
||||||
|
table = fk_def[0]._get_table()
|
||||||
|
|
||||||
|
col = fk_def[0]
|
||||||
|
ref_col = fk_def[1]
|
||||||
|
|
||||||
|
# Use .copy() to avoid the set changing during the for operation
|
||||||
|
for fk in table.foreign_keys.copy():
|
||||||
|
# Check if the fk is the one we want
|
||||||
|
if fk.column == col and fk.parent == ref_col:
|
||||||
|
|
||||||
|
fkc = ForeignKeyConstraint([fk.column], [fk.parent],
|
||||||
|
name=fk.constraint.name)
|
||||||
|
fkc.drop()
|
||||||
|
# Check if the fk is the one we want (sometimes it seems the parent
|
||||||
|
# / col is switched
|
||||||
|
if fk.parent == col and fk.column == ref_col:
|
||||||
|
|
||||||
|
fkc = ForeignKeyConstraint([fk.parent], [fk.column],
|
||||||
|
name=fk.constraint.name)
|
||||||
|
fkc.drop()
|
||||||
|
|
||||||
|
|
||||||
|
def drop_unique_constraint(uc_def):
|
||||||
|
uc = UniqueConstraint(*uc_def[2], table=uc_def[0], name=uc_def[1])
|
||||||
|
try:
|
||||||
|
uc.drop()
|
||||||
|
except PathNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
# Get all the tables
|
||||||
|
domains_table = Table('domains', meta, autoload=True)
|
||||||
|
domain_attrib_table = Table('domain_attributes', meta, autoload=True)
|
||||||
|
recordsets_table = Table('recordsets', meta, autoload=True)
|
||||||
|
records_table = Table('records', meta, autoload=True)
|
||||||
|
ztr_table = Table('zone_transfer_requests', meta, autoload=True)
|
||||||
|
zta_table = Table('zone_transfer_accepts', meta, autoload=True)
|
||||||
|
zt_table = Table('zone_tasks', meta, autoload=True)
|
||||||
|
|
||||||
|
# Remove the affected FKs
|
||||||
|
# Define FKs
|
||||||
|
fks = [
|
||||||
|
[domains_table.c.id, domains_table.c.parent_domain_id],
|
||||||
|
[domain_attrib_table.c.domain_id,
|
||||||
|
domains_table.c.id],
|
||||||
|
[recordsets_table.c.domain_id, domains_table.c.id],
|
||||||
|
[records_table.c.domain_id, domains_table.c.id],
|
||||||
|
[ztr_table.c.domain_id, domains_table.c.id],
|
||||||
|
[zta_table.c.domain_id, domains_table.c.id]
|
||||||
|
]
|
||||||
|
|
||||||
|
# Drop FKs
|
||||||
|
for fk in fks:
|
||||||
|
drop_foreign_key(fk)
|
||||||
|
|
||||||
|
# Change the table structures
|
||||||
|
|
||||||
|
# Domains Table changes
|
||||||
|
domains_table.c.parent_domain_id.alter(name='parent_zone_id')
|
||||||
|
domains_table.rename('zones')
|
||||||
|
|
||||||
|
# Domain Attributes
|
||||||
|
domain_attrib_table.c.domain_id.alter(name='zone_id')
|
||||||
|
domain_attrib_table.rename('zone_attributes')
|
||||||
|
|
||||||
|
# Recordsets
|
||||||
|
recordsets_table.c.domain_id.alter(name='zone_id')
|
||||||
|
recordsets_table.c.domain_shard.alter(name='zone_shard')
|
||||||
|
|
||||||
|
# Records
|
||||||
|
records_table.c.domain_id.alter(name="zone_id")
|
||||||
|
records_table.c.domain_shard.alter(name="zone_shard")
|
||||||
|
|
||||||
|
# Zone Transfer Requests
|
||||||
|
ztr_table.c.domain_id.alter(name='zone_id')
|
||||||
|
|
||||||
|
# Zone Transfer Requests
|
||||||
|
zta_table.c.domain_id.alter(name='zone_id')
|
||||||
|
|
||||||
|
# Zone Tasks
|
||||||
|
zt_table.c.domain_id.alter(name='zone_id')
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migration_engine):
|
||||||
|
pass
|
@ -0,0 +1,66 @@
|
|||||||
|
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# Author: Graham Hayes <graham.hayes@hpe.com>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
# See https://blueprints.launchpad.net/nova/+spec/backportable-db-migrations
|
||||||
|
# http://lists.openstack.org/pipermail/openstack-dev/2013-March/006827.html
|
||||||
|
|
||||||
|
from migrate.changeset.constraint import ForeignKeyConstraint
|
||||||
|
from sqlalchemy.schema import MetaData, Table
|
||||||
|
|
||||||
|
# This migration adds back the FKs removed in migration 80, as sqlalchemy
|
||||||
|
# migrate seems to need to wait to add FKs to renamed tables.
|
||||||
|
|
||||||
|
meta = MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
# Get all the tables
|
||||||
|
zones_table = Table('zones', meta, autoload=True)
|
||||||
|
zone_attrib_table = Table('zone_attributes', meta, autoload=True)
|
||||||
|
recordsets_table = Table('recordsets', meta, autoload=True)
|
||||||
|
records_table = Table('records', meta, autoload=True)
|
||||||
|
ztr_table = Table('zone_transfer_requests', meta, autoload=True)
|
||||||
|
zta_table = Table('zone_transfer_accepts', meta, autoload=True)
|
||||||
|
zt_table = Table('zone_tasks', meta, autoload=True)
|
||||||
|
|
||||||
|
# Create new FKs
|
||||||
|
|
||||||
|
fks = []
|
||||||
|
|
||||||
|
fks.append(ForeignKeyConstraint([zones_table.c.parent_zone_id],
|
||||||
|
[zones_table.c.id], ondelete='SET NULL'))
|
||||||
|
fks.append(ForeignKeyConstraint([zone_attrib_table.c.zone_id],
|
||||||
|
[zones_table.c.id], ondelete='CASCADE'))
|
||||||
|
fks.append(ForeignKeyConstraint([recordsets_table.c.zone_id],
|
||||||
|
[zones_table.c.id], ondelete='CASCADE'))
|
||||||
|
fks.append(ForeignKeyConstraint([records_table.c.zone_id],
|
||||||
|
[zones_table.c.id], ondelete='CASCADE'))
|
||||||
|
fks.append(ForeignKeyConstraint([ztr_table.c.zone_id],
|
||||||
|
[zones_table.c.id], ondelete='CASCADE'))
|
||||||
|
fks.append(ForeignKeyConstraint([zta_table.c.zone_id],
|
||||||
|
[zones_table.c.id], ondelete='CASCADE'))
|
||||||
|
fks.append(ForeignKeyConstraint([zt_table.c.zone_id],
|
||||||
|
[zones_table.c.id], ondelete='CASCADE'))
|
||||||
|
|
||||||
|
for fk in fks:
|
||||||
|
fk.create()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migration_engine):
|
||||||
|
pass
|
@ -76,7 +76,7 @@ tlds = Table('tlds', metadata,
|
|||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
)
|
)
|
||||||
|
|
||||||
domains = Table('domains', metadata,
|
zones = Table('zones', metadata,
|
||||||
Column('id', UUID, default=utils.generate_uuid, primary_key=True),
|
Column('id', UUID, default=utils.generate_uuid, primary_key=True),
|
||||||
Column('version', Integer(), default=1, nullable=False),
|
Column('version', Integer(), default=1, nullable=False),
|
||||||
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
||||||
@ -104,22 +104,22 @@ domains = Table('domains', metadata,
|
|||||||
nullable=False),
|
nullable=False),
|
||||||
Column('status', Enum(name='resource_statuses', *RESOURCE_STATUSES),
|
Column('status', Enum(name='resource_statuses', *RESOURCE_STATUSES),
|
||||||
nullable=False, server_default='PENDING', default='PENDING'),
|
nullable=False, server_default='PENDING', default='PENDING'),
|
||||||
Column('parent_domain_id', UUID, default=None, nullable=True),
|
Column('parent_zone_id', UUID, default=None, nullable=True),
|
||||||
Column('action', Enum(name='actions', *ACTIONS),
|
Column('action', Enum(name='actions', *ACTIONS),
|
||||||
default='CREATE', server_default='CREATE', nullable=False),
|
default='CREATE', server_default='CREATE', nullable=False),
|
||||||
Column('pool_id', UUID, default=None, nullable=True),
|
Column('pool_id', UUID, default=None, nullable=True),
|
||||||
Column('reverse_name', String(255), nullable=False),
|
Column('reverse_name', String(255), nullable=False),
|
||||||
|
|
||||||
UniqueConstraint('name', 'deleted', 'pool_id', name='unique_domain_name'),
|
UniqueConstraint('name', 'deleted', 'pool_id', name='unique_zone_name'),
|
||||||
ForeignKeyConstraint(['parent_domain_id'],
|
ForeignKeyConstraint(['parent_zone_id'],
|
||||||
['domains.id'],
|
['zones.id'],
|
||||||
ondelete='SET NULL'),
|
ondelete='SET NULL'),
|
||||||
|
|
||||||
mysql_engine='InnoDB',
|
mysql_engine='InnoDB',
|
||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
)
|
)
|
||||||
|
|
||||||
domain_attributes = Table('domain_attributes', metadata,
|
zone_attributes = Table('zone_attributes', metadata,
|
||||||
Column('id', UUID(), default=utils.generate_uuid, primary_key=True),
|
Column('id', UUID(), default=utils.generate_uuid, primary_key=True),
|
||||||
Column('version', Integer(), default=1, nullable=False),
|
Column('version', Integer(), default=1, nullable=False),
|
||||||
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
||||||
@ -127,10 +127,10 @@ domain_attributes = Table('domain_attributes', metadata,
|
|||||||
|
|
||||||
Column('key', Enum(name='key', *ZONE_ATTRIBUTE_KEYS)),
|
Column('key', Enum(name='key', *ZONE_ATTRIBUTE_KEYS)),
|
||||||
Column('value', String(255), nullable=False),
|
Column('value', String(255), nullable=False),
|
||||||
Column('domain_id', UUID(), nullable=False),
|
Column('zone_id', UUID(), nullable=False),
|
||||||
|
|
||||||
UniqueConstraint('key', 'value', 'domain_id', name='unique_attributes'),
|
UniqueConstraint('key', 'value', 'zone_id', name='unique_attributes'),
|
||||||
ForeignKeyConstraint(['domain_id'], ['domains.id'], ondelete='CASCADE'),
|
ForeignKeyConstraint(['zone_id'], ['zones.id'], ondelete='CASCADE'),
|
||||||
|
|
||||||
mysql_engine='INNODB',
|
mysql_engine='INNODB',
|
||||||
mysql_charset='utf8'
|
mysql_charset='utf8'
|
||||||
@ -141,19 +141,19 @@ recordsets = Table('recordsets', metadata,
|
|||||||
Column('version', Integer(), default=1, nullable=False),
|
Column('version', Integer(), default=1, nullable=False),
|
||||||
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
||||||
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
||||||
Column('domain_shard', SmallInteger(), nullable=False,
|
Column('zone_shard', SmallInteger(), nullable=False,
|
||||||
default=lambda ctxt: default_shard(ctxt, 'domain_id')),
|
default=lambda ctxt: default_shard(ctxt, 'zone_id')),
|
||||||
|
|
||||||
Column('tenant_id', String(36), default=None, nullable=True),
|
Column('tenant_id', String(36), default=None, nullable=True),
|
||||||
Column('domain_id', UUID, nullable=False),
|
Column('zone_id', UUID, nullable=False),
|
||||||
Column('name', String(255), nullable=False),
|
Column('name', String(255), nullable=False),
|
||||||
Column('type', Enum(name='record_types', *RECORD_TYPES), nullable=False),
|
Column('type', Enum(name='record_types', *RECORD_TYPES), nullable=False),
|
||||||
Column('ttl', Integer, default=None, nullable=True),
|
Column('ttl', Integer, default=None, nullable=True),
|
||||||
Column('description', Unicode(160), nullable=True),
|
Column('description', Unicode(160), nullable=True),
|
||||||
Column('reverse_name', String(255), nullable=False, default=''),
|
Column('reverse_name', String(255), nullable=False, default=''),
|
||||||
|
|
||||||
UniqueConstraint('domain_id', 'name', 'type', name='unique_recordset'),
|
UniqueConstraint('zone_id', 'name', 'type', name='unique_recordset'),
|
||||||
ForeignKeyConstraint(['domain_id'], ['domains.id'], ondelete='CASCADE'),
|
ForeignKeyConstraint(['zone_id'], ['zones.id'], ondelete='CASCADE'),
|
||||||
|
|
||||||
mysql_engine='InnoDB',
|
mysql_engine='InnoDB',
|
||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
@ -164,11 +164,11 @@ records = Table('records', metadata,
|
|||||||
Column('version', Integer(), default=1, nullable=False),
|
Column('version', Integer(), default=1, nullable=False),
|
||||||
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
||||||
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
||||||
Column('domain_shard', SmallInteger(), nullable=False,
|
Column('zone_shard', SmallInteger(), nullable=False,
|
||||||
default=lambda ctxt: default_shard(ctxt, 'domain_id')),
|
default=lambda ctxt: default_shard(ctxt, 'zone_id')),
|
||||||
|
|
||||||
Column('tenant_id', String(36), default=None, nullable=True),
|
Column('tenant_id', String(36), default=None, nullable=True),
|
||||||
Column('domain_id', UUID, nullable=False),
|
Column('zone_id', UUID, nullable=False),
|
||||||
Column('recordset_id', UUID, nullable=False),
|
Column('recordset_id', UUID, nullable=False),
|
||||||
Column('data', Text, nullable=False),
|
Column('data', Text, nullable=False),
|
||||||
Column('description', Unicode(160), nullable=True),
|
Column('description', Unicode(160), nullable=True),
|
||||||
@ -189,7 +189,7 @@ records = Table('records', metadata,
|
|||||||
Column('serial', Integer(), server_default='1', nullable=False),
|
Column('serial', Integer(), server_default='1', nullable=False),
|
||||||
|
|
||||||
UniqueConstraint('hash', name='unique_record'),
|
UniqueConstraint('hash', name='unique_record'),
|
||||||
ForeignKeyConstraint(['domain_id'], ['domains.id'], ondelete='CASCADE'),
|
ForeignKeyConstraint(['zone_id'], ['zones.id'], ondelete='CASCADE'),
|
||||||
ForeignKeyConstraint(['recordset_id'], ['recordsets.id'],
|
ForeignKeyConstraint(['recordset_id'], ['recordsets.id'],
|
||||||
ondelete='CASCADE'),
|
ondelete='CASCADE'),
|
||||||
|
|
||||||
@ -282,7 +282,7 @@ zone_transfer_requests = Table('zone_transfer_requests', metadata,
|
|||||||
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
||||||
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
||||||
|
|
||||||
Column('domain_id', UUID, nullable=False),
|
Column('zone_id', UUID, nullable=False),
|
||||||
Column("key", String(255), nullable=False),
|
Column("key", String(255), nullable=False),
|
||||||
Column("description", String(255), nullable=False),
|
Column("description", String(255), nullable=False),
|
||||||
Column("tenant_id", String(36), default=None, nullable=False),
|
Column("tenant_id", String(36), default=None, nullable=False),
|
||||||
@ -291,7 +291,7 @@ zone_transfer_requests = Table('zone_transfer_requests', metadata,
|
|||||||
nullable=False, server_default='ACTIVE',
|
nullable=False, server_default='ACTIVE',
|
||||||
default='ACTIVE'),
|
default='ACTIVE'),
|
||||||
|
|
||||||
ForeignKeyConstraint(['domain_id'], ['domains.id'], ondelete='CASCADE'),
|
ForeignKeyConstraint(['zone_id'], ['zones.id'], ondelete='CASCADE'),
|
||||||
|
|
||||||
mysql_engine='InnoDB',
|
mysql_engine='InnoDB',
|
||||||
mysql_charset='utf8',
|
mysql_charset='utf8',
|
||||||
@ -303,14 +303,14 @@ zone_transfer_accepts = Table('zone_transfer_accepts', metadata,
|
|||||||
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
Column('created_at', DateTime, default=lambda: timeutils.utcnow()),
|
||||||
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
Column('updated_at', DateTime, onupdate=lambda: timeutils.utcnow()),
|
||||||
|
|
||||||
Column('domain_id', UUID, nullable=False),
|
Column('zone_id', UUID, nullable=False),
|
||||||
Column('zone_transfer_request_id', UUID, nullable=False),
|
Column('zone_transfer_request_id', UUID, nullable=False),
|
||||||
Column("tenant_id", String(36), default=None, nullable=False),
|
Column("tenant_id", String(36), default=None, nullable=False),
|
||||||
Column("status", Enum(name='resource_statuses', *TASK_STATUSES),
|
Column("status", Enum(name='resource_statuses', *TASK_STATUSES),
|
||||||
nullable=False, server_default='ACTIVE',
|
nullable=False, server_default='ACTIVE',
|
||||||
default='ACTIVE'),
|
default='ACTIVE'),
|
||||||
|
|
||||||
ForeignKeyConstraint(['domain_id'], ['domains.id'], ondelete='CASCADE'),
|
ForeignKeyConstraint(['zone_id'], ['zones.id'], ondelete='CASCADE'),
|
||||||
ForeignKeyConstraint(
|
ForeignKeyConstraint(
|
||||||
['zone_transfer_request_id'],
|
['zone_transfer_request_id'],
|
||||||
['zone_transfer_requests.id'],
|
['zone_transfer_requests.id'],
|
||||||
@ -327,7 +327,7 @@ zone_tasks = Table('zone_tasks', metadata,
|
|||||||
Column('version', Integer(), default=1, nullable=False),
|
Column('version', Integer(), default=1, nullable=False),
|
||||||
Column('tenant_id', String(36), default=None, nullable=True),
|
Column('tenant_id', String(36), default=None, nullable=True),
|
||||||
|
|
||||||
Column('domain_id', UUID(), nullable=True),
|
Column('zone_id', UUID(), nullable=True),
|
||||||
Column('task_type', Enum(name='task_types', *ZONE_TASK_TYPES),
|
Column('task_type', Enum(name='task_types', *ZONE_TASK_TYPES),
|
||||||
nullable=True),
|
nullable=True),
|
||||||
Column('message', String(160), nullable=True),
|
Column('message', String(160), nullable=True),
|
||||||
|
@ -62,7 +62,7 @@ class TestTimeoutError(Exception):
|
|||||||
|
|
||||||
class TestCase(base.BaseTestCase):
|
class TestCase(base.BaseTestCase):
|
||||||
quota_fixtures = [{
|
quota_fixtures = [{
|
||||||
'resource': 'domains',
|
'resource': 'zones',
|
||||||
'hard_limit': 5,
|
'hard_limit': 5,
|
||||||
}, {
|
}, {
|
||||||
'resource': 'records',
|
'resource': 'records',
|
||||||
@ -108,8 +108,8 @@ class TestCase(base.BaseTestCase):
|
|||||||
'resource_id': '7fbb6304-5e74-4691-bd80-cef3cff5fe2f',
|
'resource_id': '7fbb6304-5e74-4691-bd80-cef3cff5fe2f',
|
||||||
}]
|
}]
|
||||||
|
|
||||||
# The last domain is invalid
|
# The last zone is invalid
|
||||||
domain_fixtures = {
|
zone_fixtures = {
|
||||||
'PRIMARY': [
|
'PRIMARY': [
|
||||||
{
|
{
|
||||||
'name': 'example.com.',
|
'name': 'example.com.',
|
||||||
@ -179,8 +179,8 @@ class TestCase(base.BaseTestCase):
|
|||||||
{'data': '10 1 5060 server2.example.org.'},
|
{'data': '10 1 5060 server2.example.org.'},
|
||||||
],
|
],
|
||||||
'CNAME': [
|
'CNAME': [
|
||||||
{'data': 'www.somedomain.org.'},
|
{'data': 'www.somezone.org.'},
|
||||||
{'data': 'www.someotherdomain.com.'},
|
{'data': 'www.someotherzone.com.'},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,17 +247,17 @@ class TestCase(base.BaseTestCase):
|
|||||||
|
|
||||||
zone_import_fixtures = [{
|
zone_import_fixtures = [{
|
||||||
'status': 'PENDING',
|
'status': 'PENDING',
|
||||||
'domain_id': None,
|
'zone_id': None,
|
||||||
'message': None,
|
'message': None,
|
||||||
'task_type': 'IMPORT'
|
'task_type': 'IMPORT'
|
||||||
}, {
|
}, {
|
||||||
'status': 'ERROR',
|
'status': 'ERROR',
|
||||||
'domain_id': None,
|
'zone_id': None,
|
||||||
'message': None,
|
'message': None,
|
||||||
'task_type': 'IMPORT'
|
'task_type': 'IMPORT'
|
||||||
}, {
|
}, {
|
||||||
'status': 'COMPLETE',
|
'status': 'COMPLETE',
|
||||||
'domain_id': '6ca6baef-3305-4ad0-a52b-a82df5752b62',
|
'zone_id': '6ca6baef-3305-4ad0-a52b-a82df5752b62',
|
||||||
'message': None,
|
'message': None,
|
||||||
'task_type': 'IMPORT'
|
'task_type': 'IMPORT'
|
||||||
}]
|
}]
|
||||||
@ -431,16 +431,16 @@ class TestCase(base.BaseTestCase):
|
|||||||
_values.update(values)
|
_values.update(values)
|
||||||
return _values
|
return _values
|
||||||
|
|
||||||
def get_domain_fixture(self, domain_type=None, fixture=0, values=None):
|
def get_zone_fixture(self, zone_type=None, fixture=0, values=None):
|
||||||
domain_type = domain_type or 'PRIMARY'
|
zone_type = zone_type or 'PRIMARY'
|
||||||
|
|
||||||
_values = copy.copy(self.domain_fixtures[domain_type][fixture])
|
_values = copy.copy(self.zone_fixtures[zone_type][fixture])
|
||||||
if values:
|
if values:
|
||||||
_values.update(values)
|
_values.update(values)
|
||||||
|
|
||||||
return _values
|
return _values
|
||||||
|
|
||||||
def get_recordset_fixture(self, domain_name, type='A', fixture=0,
|
def get_recordset_fixture(self, zone_name, type='A', fixture=0,
|
||||||
values=None):
|
values=None):
|
||||||
values = values or {}
|
values = values or {}
|
||||||
|
|
||||||
@ -448,7 +448,7 @@ class TestCase(base.BaseTestCase):
|
|||||||
_values.update(values)
|
_values.update(values)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_values['name'] = _values['name'] % domain_name
|
_values['name'] = _values['name'] % zone_name
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -569,34 +569,34 @@ class TestCase(base.BaseTestCase):
|
|||||||
return self.central_service.create_tsigkey(
|
return self.central_service.create_tsigkey(
|
||||||
context, objects.TsigKey.from_dict(values))
|
context, objects.TsigKey.from_dict(values))
|
||||||
|
|
||||||
def create_domain(self, **kwargs):
|
def create_zone(self, **kwargs):
|
||||||
context = kwargs.pop('context', self.admin_context)
|
context = kwargs.pop('context', self.admin_context)
|
||||||
fixture = kwargs.pop('fixture', 0)
|
fixture = kwargs.pop('fixture', 0)
|
||||||
domain_type = kwargs.pop('type', None)
|
zone_type = kwargs.pop('type', None)
|
||||||
|
|
||||||
values = self.get_domain_fixture(domain_type=domain_type,
|
values = self.get_zone_fixture(zone_type=zone_type,
|
||||||
fixture=fixture, values=kwargs)
|
fixture=fixture, values=kwargs)
|
||||||
|
|
||||||
if 'tenant_id' not in values:
|
if 'tenant_id' not in values:
|
||||||
values['tenant_id'] = context.tenant
|
values['tenant_id'] = context.tenant
|
||||||
|
|
||||||
return self.central_service.create_domain(
|
return self.central_service.create_zone(
|
||||||
context, objects.Domain.from_dict(values))
|
context, objects.Zone.from_dict(values))
|
||||||
|
|
||||||
def create_recordset(self, domain, type='A', increment_serial=True,
|
def create_recordset(self, zone, type='A', increment_serial=True,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
context = kwargs.pop('context', self.admin_context)
|
context = kwargs.pop('context', self.admin_context)
|
||||||
fixture = kwargs.pop('fixture', 0)
|
fixture = kwargs.pop('fixture', 0)
|
||||||
|
|
||||||
values = self.get_recordset_fixture(domain['name'], type=type,
|
values = self.get_recordset_fixture(zone['name'], type=type,
|
||||||
fixture=fixture,
|
fixture=fixture,
|
||||||
values=kwargs)
|
values=kwargs)
|
||||||
|
|
||||||
return self.central_service.create_recordset(
|
return self.central_service.create_recordset(
|
||||||
context, domain['id'], objects.RecordSet.from_dict(values),
|
context, zone['id'], objects.RecordSet.from_dict(values),
|
||||||
increment_serial=increment_serial)
|
increment_serial=increment_serial)
|
||||||
|
|
||||||
def create_record(self, domain, recordset, increment_serial=True,
|
def create_record(self, zone, recordset, increment_serial=True,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
context = kwargs.pop('context', self.admin_context)
|
context = kwargs.pop('context', self.admin_context)
|
||||||
fixture = kwargs.pop('fixture', 0)
|
fixture = kwargs.pop('fixture', 0)
|
||||||
@ -605,7 +605,7 @@ class TestCase(base.BaseTestCase):
|
|||||||
values=kwargs)
|
values=kwargs)
|
||||||
|
|
||||||
return self.central_service.create_record(
|
return self.central_service.create_record(
|
||||||
context, domain['id'], recordset['id'],
|
context, zone['id'], recordset['id'],
|
||||||
objects.Record.from_dict(values),
|
objects.Record.from_dict(values),
|
||||||
increment_serial=increment_serial)
|
increment_serial=increment_serial)
|
||||||
|
|
||||||
@ -645,15 +645,15 @@ class TestCase(base.BaseTestCase):
|
|||||||
context, default_pool_id,
|
context, default_pool_id,
|
||||||
objects.PoolAttribute.from_dict(values))
|
objects.PoolAttribute.from_dict(values))
|
||||||
|
|
||||||
def create_zone_transfer_request(self, domain, **kwargs):
|
def create_zone_transfer_request(self, zone, **kwargs):
|
||||||
context = kwargs.pop('context', self.admin_context)
|
context = kwargs.pop('context', self.admin_context)
|
||||||
fixture = kwargs.pop('fixture', 0)
|
fixture = kwargs.pop('fixture', 0)
|
||||||
|
|
||||||
values = self.get_zone_transfer_request_fixture(
|
values = self.get_zone_transfer_request_fixture(
|
||||||
fixture=fixture, values=kwargs)
|
fixture=fixture, values=kwargs)
|
||||||
|
|
||||||
if 'domain_id' not in values:
|
if 'zone_id' not in values:
|
||||||
values['domain_id'] = domain.id
|
values['zone_id'] = zone.id
|
||||||
|
|
||||||
return self.central_service.create_zone_transfer_request(
|
return self.central_service.create_zone_transfer_request(
|
||||||
context, objects.ZoneTransferRequest.from_dict(values))
|
context, objects.ZoneTransferRequest.from_dict(values))
|
||||||
@ -669,8 +669,8 @@ class TestCase(base.BaseTestCase):
|
|||||||
if 'zone_transfer_request_id' not in values:
|
if 'zone_transfer_request_id' not in values:
|
||||||
values['zone_transfer_request_id'] = zone_transfer_request.id
|
values['zone_transfer_request_id'] = zone_transfer_request.id
|
||||||
|
|
||||||
if 'domain_id' not in values:
|
if 'zone_id' not in values:
|
||||||
values['domain_id'] = zone_transfer_request.domain_id
|
values['zone_id'] = zone_transfer_request.zone_id
|
||||||
|
|
||||||
if 'key' not in values:
|
if 'key' not in values:
|
||||||
values['key'] = zone_transfer_request.key
|
values['key'] = zone_transfer_request.key
|
||||||
|
@ -37,28 +37,28 @@ class Bind9AgentBackendTestCase(TestCase, BackendTestMixin):
|
|||||||
self.backend.agent_service.stop()
|
self.backend.agent_service.stop()
|
||||||
self.backend.stop()
|
self.backend.stop()
|
||||||
|
|
||||||
def test_find_domain_serial(self):
|
def test_find_zone_serial(self):
|
||||||
self.backend.find_domain_serial('example.org.')
|
self.backend.find_zone_serial('example.org.')
|
||||||
|
|
||||||
@mock.patch('designate.utils.execute')
|
@mock.patch('designate.utils.execute')
|
||||||
@mock.patch(('designate.backend.agent_backend.impl_bind9.Bind9Backend'
|
@mock.patch(('designate.backend.agent_backend.impl_bind9.Bind9Backend'
|
||||||
'._sync_domain'))
|
'._sync_zone'))
|
||||||
def test_create_domain(self, execute, sync):
|
def test_create_zone(self, execute, sync):
|
||||||
domain = self._create_dnspy_zone('example.org')
|
zone = self._create_dnspy_zone('example.org')
|
||||||
self.backend.create_domain(domain)
|
self.backend.create_zone(zone)
|
||||||
|
|
||||||
@mock.patch('designate.utils.execute')
|
@mock.patch('designate.utils.execute')
|
||||||
@mock.patch(('designate.backend.agent_backend.impl_bind9.Bind9Backend'
|
@mock.patch(('designate.backend.agent_backend.impl_bind9.Bind9Backend'
|
||||||
'._sync_domain'))
|
'._sync_zone'))
|
||||||
def test_update_domain(self, execute, sync):
|
def test_update_zone(self, execute, sync):
|
||||||
domain = self._create_dnspy_zone('example.org')
|
zone = self._create_dnspy_zone('example.org')
|
||||||
self.backend.update_domain(domain)
|
self.backend.update_zone(zone)
|
||||||
|
|
||||||
@mock.patch('designate.utils.execute')
|
@mock.patch('designate.utils.execute')
|
||||||
@mock.patch(('designate.backend.agent_backend.impl_bind9.Bind9Backend'
|
@mock.patch(('designate.backend.agent_backend.impl_bind9.Bind9Backend'
|
||||||
'._sync_domain'))
|
'._sync_zone'))
|
||||||
def test_delete_domain(self, execute, sync):
|
def test_delete_zone(self, execute, sync):
|
||||||
self.backend.delete_domain('example.org.')
|
self.backend.delete_zone('example.org.')
|
||||||
|
|
||||||
# Helper
|
# Helper
|
||||||
def _create_dnspy_zone(self, name):
|
def _create_dnspy_zone(self, name):
|
||||||
|
@ -40,8 +40,8 @@ class DenominatorAgentBackendTestCase(TestCase, BackendTestMixin):
|
|||||||
@mock.patch('designate.utils.execute', return_value=(
|
@mock.patch('designate.utils.execute', return_value=(
|
||||||
'example.org SOA 86400 ns1.designate.com. '
|
'example.org SOA 86400 ns1.designate.com. '
|
||||||
'hostmaster@example.org. 475 3600 600 604800 1800', None))
|
'hostmaster@example.org. 475 3600 600 604800 1800', None))
|
||||||
def test_find_domain_serial(self, execute):
|
def test_find_zone_serial(self, execute):
|
||||||
serial = self.backend.find_domain_serial('example.org.')
|
serial = self.backend.find_zone_serial('example.org.')
|
||||||
|
|
||||||
# Ensure returned right serial number
|
# Ensure returned right serial number
|
||||||
self.assertEqual(475, serial)
|
self.assertEqual(475, serial)
|
||||||
@ -51,22 +51,22 @@ class DenominatorAgentBackendTestCase(TestCase, BackendTestMixin):
|
|||||||
self.assertIn('get', execute.call_args[0])
|
self.assertIn('get', execute.call_args[0])
|
||||||
|
|
||||||
@mock.patch('designate.utils.execute', return_value=('', None))
|
@mock.patch('designate.utils.execute', return_value=('', None))
|
||||||
def test_find_domain_serial_fail(self, execute):
|
def test_find_zone_serial_fail(self, execute):
|
||||||
serial = self.backend.find_domain_serial('example.org.')
|
serial = self.backend.find_zone_serial('example.org.')
|
||||||
self.assertIsNone(serial)
|
self.assertIsNone(serial)
|
||||||
|
|
||||||
@mock.patch('designate.utils.execute', return_value=(None, None))
|
@mock.patch('designate.utils.execute', return_value=(None, None))
|
||||||
def test_create_domain(self, execute):
|
def test_create_zone(self, execute):
|
||||||
domain = self._create_dnspy_zone('example.org.')
|
zone = self._create_dnspy_zone('example.org.')
|
||||||
self.backend.create_domain(domain)
|
self.backend.create_zone(zone)
|
||||||
|
|
||||||
# Ensure denominator called for each record (except SOA)
|
# Ensure denominator called for each record (except SOA)
|
||||||
# plus one to update zone data
|
# plus one to update zone data
|
||||||
self.assertEqual(len(list(domain.iterate_rdatas())),
|
self.assertEqual(len(list(zone.iterate_rdatas())),
|
||||||
execute.call_count)
|
execute.call_count)
|
||||||
|
|
||||||
@mock.patch('designate.utils.execute')
|
@mock.patch('designate.utils.execute')
|
||||||
def test_update_domain(self, execute):
|
def test_update_zone(self, execute):
|
||||||
# Output from 'designate record list' command
|
# Output from 'designate record list' command
|
||||||
records = ('example.org SOA 86400 ns1.designate.com. '
|
records = ('example.org SOA 86400 ns1.designate.com. '
|
||||||
'hostmaster@example.org. 475 3600 600 604800 1800\n'
|
'hostmaster@example.org. 475 3600 600 604800 1800\n'
|
||||||
@ -74,12 +74,12 @@ class DenominatorAgentBackendTestCase(TestCase, BackendTestMixin):
|
|||||||
'example.org NS 86400 ns2.designator.net.\n'
|
'example.org NS 86400 ns2.designator.net.\n'
|
||||||
'example.org MX 86400 10 mx1.designator.net.')
|
'example.org MX 86400 10 mx1.designator.net.')
|
||||||
|
|
||||||
# That should force update_domain to delete A and AAAA records
|
# That should force update_zone to delete A and AAAA records
|
||||||
# from the zone and create a new MX record.
|
# from the zone and create a new MX record.
|
||||||
execute.return_value = (records, None)
|
execute.return_value = (records, None)
|
||||||
|
|
||||||
domain = self._create_dnspy_zone('example.org.')
|
zone = self._create_dnspy_zone('example.org.')
|
||||||
self.backend.update_domain(domain)
|
self.backend.update_zone(zone)
|
||||||
|
|
||||||
# Ensure denominator called to:
|
# Ensure denominator called to:
|
||||||
# *update zone info
|
# *update zone info
|
||||||
@ -99,7 +99,7 @@ class DenominatorAgentBackendTestCase(TestCase, BackendTestMixin):
|
|||||||
setattr(self.backend.denominator, method, mock.Mock(
|
setattr(self.backend.denominator, method, mock.Mock(
|
||||||
return_value=records))
|
return_value=records))
|
||||||
|
|
||||||
self.backend.update_domain(domain)
|
self.backend.update_zone(zone)
|
||||||
self.assertEqual(1, self.backend.denominator.update_zone.call_count)
|
self.assertEqual(1, self.backend.denominator.update_zone.call_count)
|
||||||
self.assertEqual(1, self.backend.denominator.get_records.call_count)
|
self.assertEqual(1, self.backend.denominator.get_records.call_count)
|
||||||
self.assertEqual(4, self.backend.denominator.create_record.call_count)
|
self.assertEqual(4, self.backend.denominator.create_record.call_count)
|
||||||
@ -107,8 +107,8 @@ class DenominatorAgentBackendTestCase(TestCase, BackendTestMixin):
|
|||||||
self.assertEqual(1, self.backend.denominator.delete_record.call_count)
|
self.assertEqual(1, self.backend.denominator.delete_record.call_count)
|
||||||
|
|
||||||
@mock.patch('designate.utils.execute', return_value=(None, None))
|
@mock.patch('designate.utils.execute', return_value=(None, None))
|
||||||
def test_delete_domain(self, execute):
|
def test_delete_zone(self, execute):
|
||||||
self.backend.delete_domain('example.org.')
|
self.backend.delete_zone('example.org.')
|
||||||
|
|
||||||
# Ensure called 'denominator zone delete'
|
# Ensure called 'denominator zone delete'
|
||||||
self.assertEqual(1, execute.call_count)
|
self.assertEqual(1, execute.call_count)
|
||||||
|
@ -36,19 +36,19 @@ class FakeAgentBackendTestCase(TestCase, BackendTestMixin):
|
|||||||
self.backend.agent_service.stop()
|
self.backend.agent_service.stop()
|
||||||
self.backend.stop()
|
self.backend.stop()
|
||||||
|
|
||||||
def test_find_domain_serial(self):
|
def test_find_zone_serial(self):
|
||||||
self.backend.find_domain_serial('example.org.')
|
self.backend.find_zone_serial('example.org.')
|
||||||
|
|
||||||
def test_create_domain(self):
|
def test_create_zone(self):
|
||||||
domain = self._create_dnspy_zone('example.org')
|
zone = self._create_dnspy_zone('example.org')
|
||||||
self.backend.create_domain(domain)
|
self.backend.create_zone(zone)
|
||||||
|
|
||||||
def test_update_domain(self):
|
def test_update_zone(self):
|
||||||
domain = self._create_dnspy_zone('example.org')
|
zone = self._create_dnspy_zone('example.org')
|
||||||
self.backend.update_domain(domain)
|
self.backend.update_zone(zone)
|
||||||
|
|
||||||
def test_delete_domain(self):
|
def test_delete_zone(self):
|
||||||
self.backend.delete_domain('example.org.')
|
self.backend.delete_zone('example.org.')
|
||||||
|
|
||||||
# Helper
|
# Helper
|
||||||
def _create_dnspy_zone(self, name):
|
def _create_dnspy_zone(self, name):
|
||||||
|
@ -106,7 +106,7 @@ class AgentRequestHandlerTest(AgentTestCase):
|
|||||||
request.environ = {'addr': ["0.0.0.0", 1234]}
|
request.environ = {'addr': ["0.0.0.0", 1234]}
|
||||||
with mock.patch.object(
|
with mock.patch.object(
|
||||||
designate.backend.agent_backend.impl_fake.FakeBackend,
|
designate.backend.agent_backend.impl_fake.FakeBackend,
|
||||||
'find_domain_serial', return_value=None):
|
'find_zone_serial', return_value=None):
|
||||||
|
|
||||||
response = next(self.handler(request)).to_wire()
|
response = next(self.handler(request)).to_wire()
|
||||||
self.assertEqual(expected_response, binascii.b2a_hex(response))
|
self.assertEqual(expected_response, binascii.b2a_hex(response))
|
||||||
@ -205,7 +205,7 @@ class AgentRequestHandlerTest(AgentTestCase):
|
|||||||
request.environ = {'addr': ["0.0.0.0", 1234]}
|
request.environ = {'addr': ["0.0.0.0", 1234]}
|
||||||
with mock.patch.object(
|
with mock.patch.object(
|
||||||
designate.backend.agent_backend.impl_fake.FakeBackend,
|
designate.backend.agent_backend.impl_fake.FakeBackend,
|
||||||
'find_domain_serial', return_value=None):
|
'find_zone_serial', return_value=None):
|
||||||
response = next(self.handler(request)).to_wire()
|
response = next(self.handler(request)).to_wire()
|
||||||
doaxfr.assert_called_with('example.com.', [], source="1.2.3.4")
|
doaxfr.assert_called_with('example.com.', [], source="1.2.3.4")
|
||||||
self.assertEqual(expected_response, binascii.b2a_hex(response))
|
self.assertEqual(expected_response, binascii.b2a_hex(response))
|
||||||
|
@ -46,8 +46,8 @@ class AdminApiQuotasTest(AdminApiTestCase):
|
|||||||
|
|
||||||
max_zones = response.json['quota']['zones']
|
max_zones = response.json['quota']['zones']
|
||||||
max_zone_records = response.json['quota']['zone_records']
|
max_zone_records = response.json['quota']['zone_records']
|
||||||
self.assertEqual(cfg.CONF.quota_domains, max_zones)
|
self.assertEqual(cfg.CONF.quota_zones, max_zones)
|
||||||
self.assertEqual(cfg.CONF.quota_domain_records, max_zone_records)
|
self.assertEqual(cfg.CONF.quota_zone_records, max_zone_records)
|
||||||
|
|
||||||
def test_patch_quotas(self):
|
def test_patch_quotas(self):
|
||||||
self.policy({'set_quotas': '@'})
|
self.policy({'set_quotas': '@'})
|
||||||
|
@ -45,10 +45,10 @@ class AdminApiReportsTest(AdminApiTestCase):
|
|||||||
self.assertEqual(0, response.json['counts'][0]['records'])
|
self.assertEqual(0, response.json['counts'][0]['records'])
|
||||||
self.assertEqual(0, response.json['counts'][0]['tenants'])
|
self.assertEqual(0, response.json['counts'][0]['tenants'])
|
||||||
|
|
||||||
# Add a domain and check the counts
|
# Add a zone and check the counts
|
||||||
self.create_domain()
|
self.create_zone()
|
||||||
response = self.client.get('/reports/counts')
|
response = self.client.get('/reports/counts')
|
||||||
# Should be one domain
|
# Should be one zone
|
||||||
self.assertEqual(1, response.json['counts'][0]['zones'])
|
self.assertEqual(1, response.json['counts'][0]['zones'])
|
||||||
# Should be 1 NS and 1 SOA records
|
# Should be 1 NS and 1 SOA records
|
||||||
self.assertEqual(2, response.json['counts'][0]['records'])
|
self.assertEqual(2, response.json['counts'][0]['records'])
|
||||||
@ -56,7 +56,7 @@ class AdminApiReportsTest(AdminApiTestCase):
|
|||||||
self.assertEqual(1, response.json['counts'][0]['tenants'])
|
self.assertEqual(1, response.json['counts'][0]['tenants'])
|
||||||
|
|
||||||
def test_get_counts_zones(self):
|
def test_get_counts_zones(self):
|
||||||
self.policy({'count_domains': '@'})
|
self.policy({'count_zones': '@'})
|
||||||
response = self.client.get('/reports/counts/zones')
|
response = self.client.get('/reports/counts/zones')
|
||||||
|
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
@ -67,9 +67,9 @@ class AdminApiReportsTest(AdminApiTestCase):
|
|||||||
|
|
||||||
self.assertEqual(0, response.json['counts'][0]['zones'])
|
self.assertEqual(0, response.json['counts'][0]['zones'])
|
||||||
|
|
||||||
# Create 2 domains
|
# Create 2 zones
|
||||||
self.create_domain(fixture=0)
|
self.create_zone(fixture=0)
|
||||||
self.create_domain(fixture=1)
|
self.create_zone(fixture=1)
|
||||||
|
|
||||||
response = self.client.get('/reports/counts/zones')
|
response = self.client.get('/reports/counts/zones')
|
||||||
|
|
||||||
@ -87,8 +87,8 @@ class AdminApiReportsTest(AdminApiTestCase):
|
|||||||
|
|
||||||
self.assertEqual(0, response.json['counts'][0]['records'])
|
self.assertEqual(0, response.json['counts'][0]['records'])
|
||||||
|
|
||||||
# Create a domain
|
# Create a zone
|
||||||
self.create_domain()
|
self.create_zone()
|
||||||
|
|
||||||
response = self.client.get('/reports/counts/records')
|
response = self.client.get('/reports/counts/records')
|
||||||
|
|
||||||
@ -107,8 +107,8 @@ class AdminApiReportsTest(AdminApiTestCase):
|
|||||||
|
|
||||||
self.assertEqual(0, response.json['counts'][0]['tenants'])
|
self.assertEqual(0, response.json['counts'][0]['tenants'])
|
||||||
|
|
||||||
# Create a domain
|
# Create a zone
|
||||||
self.create_domain()
|
self.create_zone()
|
||||||
|
|
||||||
response = self.client.get('/reports/counts/tenants')
|
response = self.client.get('/reports/counts/tenants')
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ class AdminApiReportsTest(AdminApiTestCase):
|
|||||||
|
|
||||||
def test_get_tenants(self):
|
def test_get_tenants(self):
|
||||||
self.policy({'find_tenants': '@'})
|
self.policy({'find_tenants': '@'})
|
||||||
self.create_domain()
|
self.create_zone()
|
||||||
|
|
||||||
response = self.client.get('/reports/tenants')
|
response = self.client.get('/reports/tenants')
|
||||||
|
|
||||||
@ -131,8 +131,8 @@ class AdminApiReportsTest(AdminApiTestCase):
|
|||||||
|
|
||||||
def test_get_tenant(self):
|
def test_get_tenant(self):
|
||||||
self.policy({'find_tenants': '@'})
|
self.policy({'find_tenants': '@'})
|
||||||
domain = self.create_domain()
|
zone = self.create_zone()
|
||||||
tenant = domain.tenant_id
|
tenant = zone.tenant_id
|
||||||
|
|
||||||
response = self.client.get('/reports/tenants/%s' % tenant)
|
response = self.client.get('/reports/tenants/%s' % tenant)
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
|
@ -230,7 +230,7 @@ class FaultMiddlewareTest(ApiTestCase):
|
|||||||
|
|
||||||
class RaisingRequest(FakeRequest):
|
class RaisingRequest(FakeRequest):
|
||||||
def get_response(self, request):
|
def get_response(self, request):
|
||||||
raise exceptions.DuplicateDomain()
|
raise exceptions.DuplicateZone()
|
||||||
|
|
||||||
request = RaisingRequest()
|
request = RaisingRequest()
|
||||||
ctxt = context.DesignateContext()
|
ctxt = context.DesignateContext()
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user