diff options
author | Steve Leon <steve.leon@hp.com> | 2013-10-29 13:05:51 -0700 |
---|---|---|
committer | Steve Leon <steve.leon@hp.com> | 2013-11-22 10:47:22 -0800 |
commit | 4d7be83905be37048dd684f756cd6037c6f4e4ac (patch) | |
tree | d88ad092c58b268427a8e352de610fe89c7092bb /trove/dns | |
parent | d488e37a698d6f1727d3abeb31d7c6a7699af778 (diff) | |
download | trove-4d7be83905be37048dd684f756cd6037c6f4e4ac.tar.gz |
Adding designate dns support to trove
Implements: blueprint designate-dnsaas-support
Change-Id: I69a8455595b519a6459f70efa8eef8a4013bd9f6
Diffstat (limited to 'trove/dns')
-rw-r--r-- | trove/dns/designate/__init__.py | 15 | ||||
-rw-r--r-- | trove/dns/designate/driver.py | 181 | ||||
-rw-r--r-- | trove/dns/manager.py | 4 |
3 files changed, 198 insertions, 2 deletions
diff --git a/trove/dns/designate/__init__.py b/trove/dns/designate/__init__.py new file mode 100644 index 00000000..89ba40d6 --- /dev/null +++ b/trove/dns/designate/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2013 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# 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. diff --git a/trove/dns/designate/driver.py b/trove/dns/designate/driver.py new file mode 100644 index 00000000..43b3ebfb --- /dev/null +++ b/trove/dns/designate/driver.py @@ -0,0 +1,181 @@ +# Copyright (c) 2013 OpenStack Foundation +# All Rights Reserved. +# +# 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. + +""" +Dns Driver that uses Designate DNSaaS. +""" + +from trove.common import cfg +from trove.common import exception +from trove.dns import driver +from trove.openstack.common import log as logging +from designateclient.v1 import Client +from designateclient.v1.records import Record +import base64 +import hashlib + + +CONF = cfg.CONF + +DNS_TENANT_ID = CONF.dns_account_id +DNS_AUTH_URL = CONF.dns_auth_url +DNS_ENDPOINT_URL = CONF.dns_endpoint_url +DNS_SERVICE_TYPE = CONF.dns_service_type +DNS_REGION = CONF.dns_region +DNS_USERNAME = CONF.dns_username +DNS_PASSKEY = CONF.dns_passkey +DNS_TTL = CONF.dns_ttl +DNS_DOMAIN_ID = CONF.dns_domain_id +DNS_DOMAIN_NAME = CONF.dns_domain_name + + +LOG = logging.getLogger(__name__) + + +class DesignateObjectConverter(object): + + def domain_to_zone(self, domain): + return DesignateDnsZone(id=domain.id, name=domain.name) + + def record_to_entry(self, record, dns_zone): + return driver.DnsEntry(name=record.name, content=record.data, + type=record.type, ttl=record.ttl, + priority=record.priority, dns_zone=dns_zone) + + +def create_designate_client(): + """Creates a Designate DNSaaS client.""" + client = Client(auth_url=DNS_AUTH_URL, + username=DNS_USERNAME, + password=DNS_PASSKEY, + tenant_id=DNS_TENANT_ID, + endpoint=DNS_ENDPOINT_URL, + service_type=DNS_SERVICE_TYPE, + region_name=DNS_REGION) + return client + + +class DesignateDriver(driver.DnsDriver): + + def __init__(self): + self.dns_client = create_designate_client() + self.converter = DesignateObjectConverter() + self.default_dns_zone = DesignateDnsZone(id=DNS_DOMAIN_ID, + name=DNS_DOMAIN_NAME) + + def create_entry(self, entry): + """Creates the entry in the driver at the given dns zone.""" + dns_zone = entry.dns_zone or self.default_dns_zone + if not dns_zone.id: + raise TypeError("The entry's dns_zone must have an ID specified.") + name = entry.name + LOG.debug("Creating DNS entry %s." % name) + client = self.dns_client + # Record name has to end with a '.' by dns standard + record = Record(name=entry.name + '.', + type=entry.type, + data=entry.content, + ttl=entry.ttl, + priority=entry.priority) + client.records.create(dns_zone.id, record) + + def delete_entry(self, name, type, dns_zone=None): + """Deletes an entry with the given name and type from a dns zone.""" + dns_zone = dns_zone or self.default_dns_zone + records = self._get_records(dns_zone) + matching_record = [rec for rec in records + if rec.name == name + '.' and rec.type == type] + if not matching_record: + raise exception.DnsRecordNotFound(name) + LOG.debug("Deleting DNS entry %s." % name) + self.dns_client.records.delete(dns_zone.id, matching_record[0].id) + + def get_entries_by_content(self, content, dns_zone=None): + """Retrieves all entries in a dns_zone with a matching content field""" + records = self._get_records(dns_zone) + return [self.converter.record_to_entry(record, dns_zone) + for record in records if record.data == content] + + def get_entries_by_name(self, name, dns_zone): + records = self._get_records(dns_zone) + return [self.converter.record_to_entry(record, dns_zone) + for record in records if record.name == name] + + def get_dns_zones(self, name=None): + """Returns all dns zones (optionally filtered by the name argument.""" + domains = self.dns_client.domains.list() + return [self.converter.domain_to_zone(domain) + for domain in domains if not name or domain.name == name] + + def modify_content(self, name, content, dns_zone): + # We dont need this in trove for now + raise NotImplementedError("Not implemented for Designate DNS.") + + def rename_entry(self, content, name, dns_zone): + # We dont need this in trove for now + raise NotImplementedError("Not implemented for Designate DNS.") + + def _get_records(self, dns_zone): + dns_zone = dns_zone or self.default_dns_zone + if not dns_zone: + raise TypeError('DNS domain is must be specified') + return self.dns_client.records.list(dns_zone.id) + + +class DesignateInstanceEntryFactory(driver.DnsInstanceEntryFactory): + """Defines how instance DNS entries are created for instances.""" + + def create_entry(self, instance): + zone = DesignateDnsZone(id=DNS_DOMAIN_ID, name=DNS_DOMAIN_NAME) + # Constructing the hostname by hashing the instance ID. + name = base64.urlsafe_b64encode(hashlib.md5(instance).digest())[:11] + hostname = ("%s.%s" % (name, zone.name)) + #Removing the leading dot if present + if hostname.endswith('.'): + hostname = hostname[:-1] + + return driver.DnsEntry(name=hostname, content=None, type="A", + ttl=DNS_TTL, dns_zone=zone) + + +class DesignateDnsZone(driver.DnsZone): + + def __init__(self, id, name): + self._name = name + self._id = id + + @property + def name(self): + return self._name + + @name.setter + def name(self, value): + self._name = value + + @property + def id(self): + return self._id + + @id.setter + def id(self, value): + self._id = value + + def __eq__(self, other): + return (isinstance(other, DesignateDnsZone) and + self.name == other.name and + self.id == other.id) + + def __str__(self): + return "%s:%s" % (self.id, self.name) diff --git a/trove/dns/manager.py b/trove/dns/manager.py index a2fd4d98..6e6a7918 100644 --- a/trove/dns/manager.py +++ b/trove/dns/manager.py @@ -35,12 +35,12 @@ class DnsManager(object): *args, **kwargs): if not dns_driver: dns_driver = CONF.dns_driver - dns_driver = utils.import_object(dns_driver) + dns_driver = utils.import_class(dns_driver) self.driver = dns_driver() if not dns_instance_entry_factory: dns_instance_entry_factory = CONF.dns_instance_entry_factory - entry_factory = utils.import_object(dns_instance_entry_factory) + entry_factory = utils.import_class(dns_instance_entry_factory) self.entry_factory = entry_factory() def create_instance_entry(self, instance_id, content): |