summaryrefslogtreecommitdiff
path: root/trove/dns
diff options
context:
space:
mode:
authorSteve Leon <steve.leon@hp.com>2013-10-29 13:05:51 -0700
committerSteve Leon <steve.leon@hp.com>2013-11-22 10:47:22 -0800
commit4d7be83905be37048dd684f756cd6037c6f4e4ac (patch)
treed88ad092c58b268427a8e352de610fe89c7092bb /trove/dns
parentd488e37a698d6f1727d3abeb31d7c6a7699af778 (diff)
downloadtrove-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__.py15
-rw-r--r--trove/dns/designate/driver.py181
-rw-r--r--trove/dns/manager.py4
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):