libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject svn commit: r1338285 - in /libcloud/trunk/libcloud/dns: drivers/route53.py providers.py types.py
Date Mon, 14 May 2012 16:45:57 GMT
Author: tomaz
Date: Mon May 14 16:45:56 2012
New Revision: 1338285

URL: http://svn.apache.org/viewvc?rev=1338285&view=rev
Log:
Add work in progress version of Route53 DNS driver. Part of
LIBCLOUD-153, based on changes by Ryan Lewon from
https://github.com/rlewon/libcloud/tree/route53_dns.

Added:
    libcloud/trunk/libcloud/dns/drivers/route53.py
Modified:
    libcloud/trunk/libcloud/dns/providers.py
    libcloud/trunk/libcloud/dns/types.py

Added: libcloud/trunk/libcloud/dns/drivers/route53.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/dns/drivers/route53.py?rev=1338285&view=auto
==============================================================================
--- libcloud/trunk/libcloud/dns/drivers/route53.py (added)
+++ libcloud/trunk/libcloud/dns/drivers/route53.py Mon May 14 16:45:56 2012
@@ -0,0 +1,206 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+__all__ = [
+    'Route53DNSDriver'
+]
+
+import base64
+import hmac
+import datetime
+
+from hashlib import sha1
+from xml.etree import ElementTree as ET
+
+from libcloud.utils.py3 import b
+
+from libcloud.utils.xml import findtext, findall, fixxpath
+from libcloud.dns.types import Provider, RecordType
+from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError
+from libcloud.dns.base import DNSDriver, Zone, Record
+from libcloud.common.types import LibcloudError
+from libcloud.common.aws import AWSBaseResponse
+from libcloud.common.base import ConnectionUserAndKey
+
+
+API_VERSION = '2012-02-29'
+API_HOST = 'route53.amazonaws.com'
+API_ROOT = '/%s/' % (API_VERSION)
+
+NAMESPACE = 'https://%s/doc%s' % (API_HOST, API_ROOT)
+
+
+class Route53Error(LibcloudError):
+    def __init__(self, code, errors):
+        self.code = code
+        self.errors = errors or []
+
+    def __str__(self):
+        return 'Errors: %s' % (', '.join(self.errors))
+
+    def __repr__(self):
+        return('<Route53 response code=%s>' %
+                (self.code, len(self.errors)))
+
+
+class Route53DNSResponse(AWSBaseResponse):
+    """
+    Amazon Route53 response class.
+    """
+    def success(self):
+        return self.status in [httplib.OK, httplib.CREATED, httplib.ACCEPTED]
+
+    def error(self):
+        status = int(self.status)
+
+        if status == 403:
+            if not self.body:
+                raise InvalidCredsError(str(self.status) + ': ' + self.error)
+            else:
+                raise InvalidCredsError(self.body)
+
+        elif status == 400:
+            context = self.connection.context
+            messages = []
+            if context['InvalidChangeBatch']['Messages']:
+                for message in context['InvalidChangeBatch']['Messages']:
+                    messages.append(message['Message'])
+
+                raise Route53Error('InvalidChangeBatch message(s): %s ',
+                        messages)
+
+
+class Route53Connection(ConnectionUserAndKey):
+    host = API_HOST
+
+    def pre_connect_hook(self, params, headers):
+        time_string = datetime.datetime.utcnow() \
+                              .strftime('%a, %d %b %Y %H:%M:%S GMT')
+        headers['Date'] = time_string
+        tmp = []
+
+        signature = self._get_aws_auth_b64(self.key, time_string)
+        auth = {'AWSAccessKeyId': self.user_id, 'Signature': signature,
+                'Algorithm': 'HmacSHA1'}
+
+        for k, v in auth.items():
+            tmp.append('%s=%s' % (k, v))
+
+        headers['X-Amzn-Authorization'] = 'AWS3-HTTPS ' + ','.join(tmp)
+
+        return params, headers
+
+    def _get_aws_auth_b64(self, secret_key, time_string):
+        b64_hmac = base64.b64encode(
+            hmac.new(b(secret_key), b(time_string), digestmod=sha1).digest()
+        )
+
+        return b64_hmac
+
+
+class Route53DNSDriver(DNSDriver):
+    type = Provider.ROUTE53
+    name = 'Route53 DNS'
+    connectionCls = Route53Connection
+
+    RECORD_TYPE_MAP = {
+        RecordType.NS: 'NS',
+        RecordType.MX: 'MX',
+        RecordType.A: 'A',
+        RecordType.AAAA: 'AAAA',
+        RecordType.CNAME: 'CNAME',
+        RecordType.TXT: 'TXT',
+        RecordType.SRV: 'SRV'
+    }
+
+    def list_zones(self):
+        data = ET.XML(self.connection.request(API_ROOT + 'hostedzone').object)
+        zones = self._to_zones(data=data)
+        return zones
+
+    def list_records(self, zone):
+        data = ET.XML(self.connection.request(API_ROOT + 'hostedzone/'
+                      + zone.id + '/rrset').object)
+        records = self._to_records(data=data, zone=zone)
+        return records
+
+    def get_zone(self, zone_id):
+        data = ET.XML(self.connection.request(API_ROOT + 'hostedzone/'
+                      + zone_id).object)
+        zone = self._to_zone(elem=findall(element=data, xpath='HostedZone',
+                                          namespace=NAMESPACE)[0])
+        return zone
+
+    def get_record(self, zone_id, record_id):
+        zone = self.get_zone(zone_id=zone_id)
+        data = ET.XML(self.connection.request(API_ROOT + 'hostedzone/'
+                      + zone_id + '/rrset?maxitems=1&name=' + record_id)
+                      .object)
+
+        record = self._to_records(data=data, zone=zone)
+        return record
+
+    def _to_zones(self, data):
+        zones = []
+        for element in data.findall(fixxpath(xpath='HostedZones/HostedZone',
+                                             namespace=NAMESPACE)):
+            zones.append(self._to_zone(element))
+
+        return zones
+
+    def _to_zone(self, elem):
+        name = findtext(element=elem, xpath='Name', namespace=NAMESPACE)
+        id = findtext(element=elem, xpath='Id',
+                namespace=NAMESPACE).replace('/hostedzone/', '')
+        comment = findtext(element=elem, xpath='Config/Comment',
+                           namespace=NAMESPACE)
+        resource_record_count = int(findtext(element=elem,
+                                             xpath='ResourceRecordSetCount',
+                                             namespace=NAMESPACE))
+
+        extra = {'Comment': comment, 'ResourceRecordSetCount':
+                resource_record_count}
+
+        zone = Zone(id=id, domain=name, type='master', ttl=0, driver=self,
+                    extra=extra)
+        return zone
+
+    def _to_records(self, data, zone):
+        records = []
+        for elem in \
+        data.findall(fixxpath(xpath='ResourceRecordSets/ResourceRecordSet',
+            namespace=NAMESPACE)):
+            records.append(self._to_record(elem, zone))
+
+        return records
+
+    def _to_record(self, elem, zone):
+        name = findtext(element=elem, xpath='Name',
+                namespace=NAMESPACE)
+        type = self._string_to_record_type(findtext(element=elem, xpath='Type',
+                namespace=NAMESPACE))
+        ttl = findtext(element=elem, xpath='TTL', namespace=NAMESPACE)
+
+        # TODO: Support records with multiple values
+        value_elem = elem.findall(
+                fixxpath(xpath='ResourceRecords/ResourceRecord',
+                         namespace=NAMESPACE))[0]
+        data = findtext(element=(value_elem), xpath='Value',
+                        namespace=NAMESPACE)
+
+        extra = {'ttl': ttl}
+        record = Record(id=name, name=name, type=type, data=data, zone=zone,
+                        driver=self, extra=extra)
+        return record

Modified: libcloud/trunk/libcloud/dns/providers.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/dns/providers.py?rev=1338285&r1=1338284&r2=1338285&view=diff
==============================================================================
--- libcloud/trunk/libcloud/dns/providers.py (original)
+++ libcloud/trunk/libcloud/dns/providers.py Mon May 14 16:45:56 2012
@@ -27,8 +27,8 @@ DRIVERS = {
         ('libcloud.dns.drivers.rackspace', 'RackspaceUSDNSDriver'),
     Provider.RACKSPACE_UK:
         ('libcloud.dns.drivers.rackspace', 'RackspaceUKDNSDriver'),
-    Provider.ROUTE_53:
-        ('libcloud.dns.drivers.route_53', 'Route53DNSDriver')
+    Provider.ROUTE53:
+        ('libcloud.dns.drivers.route53', 'Route53DNSDriver')
 }
 
 

Modified: libcloud/trunk/libcloud/dns/types.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/dns/types.py?rev=1338285&r1=1338284&r2=1338285&view=diff
==============================================================================
--- libcloud/trunk/libcloud/dns/types.py (original)
+++ libcloud/trunk/libcloud/dns/types.py Mon May 14 16:45:56 2012
@@ -33,7 +33,7 @@ class Provider(object):
     ZERIGO = 2
     RACKSPACE_US = 3
     RACKSPACE_UK = 4
-    ROUTE_53 = 5
+    ROUTE53 = 5
 
 
 class RecordType(object):



Mime
View raw message