You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2011/10/30 01:03:23 UTC

svn commit: r1195069 - in /libcloud/trunk: libcloud/common/ libcloud/dns/ libcloud/dns/drivers/ test/ test/dns/ test/dns/fixtures/rackspace/

Author: tomaz
Date: Sat Oct 29 23:03:22 2011
New Revision: 1195069

URL: http://svn.apache.org/viewvc?rev=1195069&view=rev
Log:
Add a new DNS driver for Rackspace Cloud DNS (US, UK).

Added:
    libcloud/trunk/libcloud/dns/drivers/rackspace.py
    libcloud/trunk/test/dns/fixtures/rackspace/
    libcloud/trunk/test/dns/fixtures/rackspace/auth_1_1.json
    libcloud/trunk/test/dns/fixtures/rackspace/create_record_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/create_zone_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/create_zone_validation_error.json
    libcloud/trunk/test/dns/fixtures/rackspace/delete_record_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/delete_zone_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/does_not_exist.json
    libcloud/trunk/test/dns/fixtures/rackspace/get_record_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/get_zone_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/list_records_no_results.json
    libcloud/trunk/test/dns/fixtures/rackspace/list_records_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/list_zones_no_results.json
    libcloud/trunk/test/dns/fixtures/rackspace/list_zones_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/unauthorized.json
    libcloud/trunk/test/dns/fixtures/rackspace/update_record_success.json
    libcloud/trunk/test/dns/fixtures/rackspace/update_zone_success.json
    libcloud/trunk/test/dns/test_rackspace.py
Modified:
    libcloud/trunk/libcloud/common/openstack.py
    libcloud/trunk/libcloud/dns/base.py
    libcloud/trunk/libcloud/dns/providers.py
    libcloud/trunk/libcloud/dns/types.py
    libcloud/trunk/test/secrets.py-dist

Modified: libcloud/trunk/libcloud/common/openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/common/openstack.py?rev=1195069&r1=1195068&r2=1195069&view=diff
==============================================================================
--- libcloud/trunk/libcloud/common/openstack.py (original)
+++ libcloud/trunk/libcloud/common/openstack.py Sat Oct 29 23:03:22 2011
@@ -246,9 +246,10 @@ class OpenStackBaseConnection(Connection
             # TODO: this is even more broken, the service catalog does NOT show load
             # balanacers :(  You must hard code in the Rackspace Load balancer URLs...
             self.lb_url = self.server_url.replace("servers", "ord.loadbalancers")
+            self.dns_url = self.server_url.replace("servers", "dns")
 
             for key in ['server_url', 'storage_url', 'cdn_management_url',
-                        'lb_url']:
+                        'lb_url', 'dns_url']:
                 base_url = None
                 if self._force_base_url != None:
                     base_url = self._force_base_url

Modified: libcloud/trunk/libcloud/dns/base.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/dns/base.py?rev=1195069&r1=1195068&r2=1195069&view=diff
==============================================================================
--- libcloud/trunk/libcloud/dns/base.py (original)
+++ libcloud/trunk/libcloud/dns/base.py Sat Oct 29 23:03:22 2011
@@ -63,7 +63,7 @@ class Zone(object):
         return self.driver.create_record(name=name, zone=self, type=type,
                                          data=data, extra=extra)
 
-    def update(self, domain, type='master', ttl=None, extra=None):
+    def update(self, domain=None, type=None, ttl=None, extra=None):
         return self.driver.update_zone(zone=self, domain=domain, type=type,
                                        ttl=ttl, extra=extra)
 
@@ -111,7 +111,7 @@ class Record(object):
         self.driver = driver
         self.extra = extra or {}
 
-    def update(self, name, type, data, extra):
+    def update(self, name=None, type=None, data=None, extra=None):
         return self.driver.update_record(record=self, name=name, type=type,
                                          data=data, extra=extra)
 

Added: libcloud/trunk/libcloud/dns/drivers/rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/dns/drivers/rackspace.py?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/libcloud/dns/drivers/rackspace.py (added)
+++ libcloud/trunk/libcloud/dns/drivers/rackspace.py Sat Oct 29 23:03:22 2011
@@ -0,0 +1,351 @@
+# 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__ = [
+    'RackspaceUSDNSDriver',
+    'RackspaceUKDNSDriver'
+]
+
+import httplib
+import copy
+
+from libcloud.common.base import PollingConnection
+from libcloud.common.types import LibcloudError
+from libcloud.utils import merge_valid_keys, get_new_obj
+from libcloud.common.rackspace import AUTH_URL_US, AUTH_URL_UK
+from libcloud.compute.drivers.openstack import OpenStack_1_1_Connection
+from libcloud.compute.drivers.openstack import OpenStack_1_1_Response
+
+from libcloud.dns.types import Provider, RecordType
+from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError
+from libcloud.dns.base import DNSDriver, Zone, Record
+
+VALID_ZONE_EXTRA_PARAMS = ['email', 'comment', 'ns1']
+VALID_RECORD_EXTRA_PARAMS = ['ttl', 'comment']
+
+RECORD_TYPE_MAP = {
+    RecordType.A: 'A',
+    RecordType.AAAA: 'AAAA',
+    RecordType.CNAME: 'CNAME',
+    RecordType.MX: 'MX',
+    RecordType.NS: 'NS',
+    RecordType.TXT: 'TXT',
+    RecordType.SRV: 'SRV',
+}
+
+
+class RackspaceDNSResponse(OpenStack_1_1_Response):
+    """
+    Rackspace DNS Response class.
+    """
+
+    def parse_error(self):
+        # Holy fucking jesus,
+        # "The request could not be understood by the server due to malformed
+        # syntax." is returned if record already exists
+        status = int(self.status)
+        context = self.connection.context
+        body = self.parse_body()
+
+        if status == httplib.NOT_FOUND:
+            if context['resource'] == 'zone':
+                raise ZoneDoesNotExistError(value='', driver=self,
+                                            zone_id=context['id'])
+            elif context['resource'] == 'record':
+                raise RecordDoesNotExistError(value='', driver=self,
+                                              record_id=context['id'])
+
+        if 'code' and 'message' in body:
+            err = '%s - %s (%s)' % (body['code'], body['message'],
+                                    body['details'])
+        elif 'validationErrors' in body:
+            errors = [m for m in body['validationErrors']['messages']]
+            err = 'Validation errors: %s' % ', '.join(errors)
+
+        return err
+
+
+class RackspaceDNSConnection(OpenStack_1_1_Connection, PollingConnection):
+    """
+    Rackspace DNS Connection class.
+    """
+
+    responseCls = RackspaceDNSResponse
+    _url_key = 'dns_url'
+    XML_NAMESPACE = None
+
+    def get_poll_request_kwargs(self, response, context):
+        job_id = response.object['jobId']
+        kwargs = {'action': '/status/%s' % (job_id),
+                'params': {'showDetails': True}}
+        return kwargs
+
+    def has_completed(self, response):
+        status = response.object['status']
+        if status == 'ERROR':
+            raise LibcloudError(response.object['error']['message'],
+                                driver=self.driver)
+
+        return status == 'COMPLETED'
+
+
+class RackspaceUSDNSConnection(RackspaceDNSConnection):
+    auth_url = AUTH_URL_US
+
+
+class RackspaceUKDNSConnection(RackspaceDNSConnection):
+    auth_url = AUTH_URL_UK
+
+
+class RackspaceDNSDriver(DNSDriver):
+    def list_zones(self):
+        response = self.connection.request(action='/domains')
+        zones = self._to_zones(data=response.object['domains'])
+        return zones
+
+    def list_records(self, zone):
+        self.connection.set_context({'resource': 'zone', 'id': zone.id})
+        response = self.connection.request(action='/domains/%s' % (zone.id),
+                                           params={'showRecord': True}).object
+        records = self._to_records(data=response['recordsList']['records'],
+                                   zone=zone)
+        return records
+
+    def get_zone(self, zone_id):
+        self.connection.set_context({'resource': 'zone', 'id': zone_id})
+        response = self.connection.request(action='/domains/%s' % (zone_id))
+        zone = self._to_zone(data=response.object)
+        return zone
+
+    def get_record(self, zone_id, record_id):
+        zone = self.get_zone(zone_id=zone_id)
+        self.connection.set_context({'resource': 'record', 'id': record_id})
+        response = self.connection.request(action='/domains/%s/records/%s' %
+                                           (zone_id, record_id)).object
+        record = self._to_record(data=response, zone=zone)
+        return record
+
+    def create_zone(self, domain, type='master', ttl=None, extra=None):
+        extra = extra if extra else {}
+
+        # Email address is required
+        if not 'email' in extra:
+            raise ValueError('"email" key must be present in extra dictionary')
+
+        payload = {'name': domain, 'emailAddress': extra['email'],
+                   'recordsList': {'records': []}}
+
+        if ttl:
+            payload['ttl'] = ttl
+
+        if 'comment' in extra:
+            payload['comment'] = extra['comment']
+
+        data = {'domains': [payload]}
+        response = self.connection.async_request(action='/domains',
+                                                 method='POST', data=data)
+        zone = self._to_zone(data=response.object['response']['domains'][0])
+        return zone
+
+    def update_zone(self, zone, domain=None, type=None, ttl=None, extra=None):
+        # Only ttl, comment and email address can be changed
+        extra = extra if extra else {}
+
+        if domain:
+            raise LibcloudError('Domain cannot be changed', driver=self)
+
+        data = {}
+
+        if ttl:
+            data['ttl'] = int(ttl)
+
+        if 'email' in extra:
+            data['emailAddress'] = extra['email']
+
+        if 'comment' in extra:
+            data['comment'] = extra['comment']
+
+        type = type if type else zone.type
+        ttl = ttl if ttl else zone.ttl
+
+        self.connection.set_context({'resource': 'zone', 'id': zone.id})
+        self.connection.async_request(action='/domains/%s' % (zone.id),
+                                      method='PUT', data=data)
+        merged = merge_valid_keys(params=copy.deepcopy(zone.extra),
+                                  valid_keys=VALID_ZONE_EXTRA_PARAMS,
+                                  extra=extra)
+        updated_zone = get_new_obj(obj=zone, klass=Zone,
+                                   attributes={'type': type,
+                                               'ttl': ttl,
+                                               'extra': merged})
+        return updated_zone
+
+    def create_record(self, name, zone, type, data, extra=None):
+        # Name must be a FQDN - e.g. if domain is "foo.com" then a record
+        # name is "bar.foo.com"
+        extra = extra if extra else {}
+
+        name = self._to_full_record_name(domain=zone.domain, name=name)
+        data = {'name': name, 'type': RECORD_TYPE_MAP[type], 'data': data}
+
+        if 'ttl' in extra:
+            data['ttl'] = int(extra['ttl'])
+
+        payload = {'records': [data]}
+        self.connection.set_context({'resource': 'zone', 'id': zone.id})
+        response = self.connection.async_request(action='/domains/%s/records'
+                                                 % (zone.id), data=payload,
+                                                 method='POST').object
+        record = self._to_record(data=response['response']['records'][0],
+                                 zone=zone)
+        return record
+
+    def update_record(self, record, name=None, type=None, data=None,
+                      extra=None):
+        # Only data, ttl, and comment attributes can be modified, but name
+        # attribute must always be present.
+        extra = extra if extra else {}
+
+        name = self._to_full_record_name(domain=record.zone.domain,
+                                         name=record.name)
+        payload = {'name': name}
+
+        if data:
+            payload['data'] = data
+
+        if 'ttl' in extra:
+            payload['ttl'] = extra['ttl']
+
+        if 'comment' in extra:
+            payload['comment'] = extra['comment']
+
+        type = type if type else record.type
+        data = data if data else record.data
+
+        self.connection.set_context({'resource': 'record', 'id': record.id})
+        self.connection.async_request(action='/domains/%s/records/%s' %
+                                      (record.zone.id, record.id),
+                                      method='PUT', data=payload)
+
+        merged = merge_valid_keys(params=copy.deepcopy(record.extra),
+                                  valid_keys=VALID_RECORD_EXTRA_PARAMS,
+                                  extra=extra)
+        updated_record = get_new_obj(obj=record, klass=Record,
+                                     attributes={'type': type,
+                                                 'data': data,
+                                                 'extra': merged})
+        return updated_record
+
+    def delete_zone(self, zone):
+        self.connection.set_context({'resource': 'zone', 'id': zone.id})
+        self.connection.async_request(action='/domains/%s' % (zone.id),
+                                      method='DELETE')
+        return True
+
+    def delete_record(self, record):
+        self.connection.set_context({'resource': 'record', 'id': record.id})
+        self.connection.async_request(action='/domains/%s/records/%s' %
+                                      (record.zone.id, record.id),
+                                      method='DELETE')
+        return True
+
+    def _to_zones(self, data):
+        zones = []
+        for item in data:
+            zone = self._to_zone(data=item)
+            zones.append(zone)
+
+        return zones
+
+    def _to_zone(self, data):
+        id = data['id']
+        domain = data['name']
+        type = 'master'
+        ttl = data.get('ttl', 0)
+        extra = {}
+
+        if 'emailAddress' in data:
+            extra['email'] = data['emailAddress']
+
+        if 'comment' in data:
+            extra['comment'] = data['comment']
+
+        zone = Zone(id=str(id), domain=domain, type=type, ttl=int(ttl),
+                    driver=self, extra=extra)
+        return zone
+
+    def _to_records(self, data, zone):
+        records = []
+        for item in data:
+            record = self._to_record(data=item, zone=zone)
+            records.append(record)
+
+        return records
+
+    def _to_record(self, data, zone):
+        id = data['id']
+        fqdn = data['name']
+        name = self._to_partial_record_name(domain=zone.domain, name=fqdn)
+        type = self._string_to_record_type(data['type'])
+        record_data = data['data']
+        extra = {'fqdn': fqdn}
+
+        if 'ttl' in data:
+            extra['ttl'] = data['ttl']
+
+        if 'comment' in data:
+            extra['comment'] = data['comment']
+
+        record = Record(id=str(id), name=name, type=type, data=record_data,
+                        zone=zone, driver=self, extra=extra)
+        return record
+
+    def _to_full_record_name(self, domain, name):
+        """
+        Build a FQDN from a domain and record name.
+
+        @param domain: Domain name.
+        @type domain: C{str}
+
+        @param name: Record name.
+        @type name: C{str}
+        """
+        name = '%s.%s' % (name, domain)
+        return name
+
+    def _to_partial_record_name(self, domain, name):
+        """
+        Strip domain portion from the record name.
+
+        @param domain: Domain name.
+        @type domain: C{str}
+
+        @param name: Full record name (fqdn).
+        @type name: C{str}
+        """
+        name = name.replace('.%s' % (domain), '')
+        return name
+
+
+class RackspaceUSDNSDriver(RackspaceDNSDriver):
+    name = 'Rackspace DNS (US)'
+    type = Provider.RACKSPACE_US
+    connectionCls = RackspaceUSDNSConnection
+
+
+class RackspaceUKDNSDriver(RackspaceDNSDriver):
+    name = 'Rackspace DNS (UK)'
+    type = Provider.RACKSPACE_UK
+    connectionCls = RackspaceUKDNSConnection

Modified: libcloud/trunk/libcloud/dns/providers.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/dns/providers.py?rev=1195069&r1=1195068&r2=1195069&view=diff
==============================================================================
--- libcloud/trunk/libcloud/dns/providers.py (original)
+++ libcloud/trunk/libcloud/dns/providers.py Sat Oct 29 23:03:22 2011
@@ -22,7 +22,11 @@ DRIVERS = {
     Provider.LINODE:
         ('libcloud.dns.drivers.linode', 'LinodeDNSDriver'),
     Provider.ZERIGO:
-        ('libcloud.dns.drivers.zerigo', 'ZerigoDNSDriver')
+        ('libcloud.dns.drivers.zerigo', 'ZerigoDNSDriver'),
+    Provider.RACKSPACE_US:
+        ('libcloud.dns.drivers.rackspace', 'RackspaceUSDNSDriver'),
+    Provider.RACKSPACE_UK:
+        ('libcloud.dns.drivers.rackspace', 'RackspaceUKDNSDriver')
 }
 
 

Modified: libcloud/trunk/libcloud/dns/types.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/dns/types.py?rev=1195069&r1=1195068&r2=1195069&view=diff
==============================================================================
--- libcloud/trunk/libcloud/dns/types.py (original)
+++ libcloud/trunk/libcloud/dns/types.py Sat Oct 29 23:03:22 2011
@@ -31,6 +31,8 @@ class Provider(object):
     DUMMY = 0
     LINODE = 1
     ZERIGO = 2
+    RACKSPACE_US = 3
+    RACKSPACE_UK = 4
 
 
 class RecordType(object):

Added: libcloud/trunk/test/dns/fixtures/rackspace/auth_1_1.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/auth_1_1.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/auth_1_1.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/auth_1_1.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,31 @@
+{
+   "auth":{
+      "token":{
+         "id":"fooo-bar-fooo-bar-fooo-bar",
+         "expires":"2011-10-29T17:39:28.000-05:00"
+      },
+      "serviceCatalog":{
+         "cloudFilesCDN":[
+            {
+               "region":"ORD",
+               "publicURL":"https:\/\/cdn2.clouddrive.com\/v1\/MossoCloudFS_f66473fb-2e1e-4a44-barr-foooooo",
+               "v1Default":true
+            }
+         ],
+         "cloudFiles":[
+            {
+               "region":"ORD",
+               "publicURL":"https:\/\/storage101.ord1.clouddrive.com\/v1\/MossoCloudFS_fbarr-foooo-barr",
+               "v1Default":true,
+               "internalURL":"https:\/\/snet-storage101.ord1.clouddrive.com\/v1\/MossoCloudFS_fbarr-foooo-barr"
+            }
+         ],
+         "cloudServers":[
+            {
+               "publicURL":"https:\/\/servers.api.rackspacecloud.com\/v1.0\/11111",
+               "v1Default":true
+            }
+         ]
+      }
+   }
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/create_record_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/create_record_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/create_record_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/create_record_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,21 @@
+{
+   "request":"{\"records\": [{\"data\": \"127.1.1.1\", \"type\": \"A\", \"name\": \"www.foo4.bar.com\"}]}",
+   "response":{
+      "records":[
+         {
+            "name":"www.foo4.bar.com",
+            "id":"A-7423317",
+            "type":"A",
+            "data":"127.1.1.1",
+            "updated":"2011-10-29T20:50:41.000+0000",
+            "ttl":3600,
+            "created":"2011-10-29T20:50:41.000+0000"
+         }
+      ]
+   },
+   "status":"COMPLETED",
+   "verb":"POST",
+   "jobId":"586605c8-5739-43fb-8939-f3a2c4c0e99c",
+   "callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/546514/status/586605c8-5739-43fb-8939-f3a2c4c0e99c",
+   "requestUrl":"http://dns.api.rackspacecloud.com/v1.0/546514/domains/2946173/records"
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/create_zone_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/create_zone_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/create_zone_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/create_zone_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,29 @@
+{
+   "request":"{\"domains\": [{\"recordsList\": {\"records\": []}, \"emailAddress\": \"test@test.com\", \"name\": \"bar.foo1.com\"}]}",
+   "response":{
+      "domains":[
+         {
+            "name":"bar.foo1.com",
+            "id":2946173,
+            "accountId":11111,
+            "updated":"2011-10-29T20:28:59.000+0000",
+            "ttl":3600,
+            "emailAddress":"test@test.com",
+            "nameservers":[
+               {
+                  "name":"ns.rackspace.com"
+               },
+               {
+                  "name":"ns2.rackspace.com"
+               }
+            ],
+            "created":"2011-10-29T20:28:59.000+0000"
+         }
+      ]
+   },
+   "status":"COMPLETED",
+   "verb":"POST",
+   "jobId":"288795f9-e74d-48be-880b-a9e36e0de61e",
+   "callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/11111/status/288795f9-e74d-48be-880b-a9e36e0de61e",
+   "requestUrl":"http://dns.api.rackspacecloud.com/v1.0/11111/domains"
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/create_zone_validation_error.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/create_zone_validation_error.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/create_zone_validation_error.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/create_zone_validation_error.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1 @@
+{"validationErrors":{"messages":["Domain TTL is required and must be greater than or equal to 300"]},"code":400}

Added: libcloud/trunk/test/dns/fixtures/rackspace/delete_record_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/delete_record_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/delete_record_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/delete_record_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,8 @@
+{
+   "status":"COMPLETED",
+   "verb":"DELETE",
+   "jobId":"0b40cd14-2e5d-490f-bb6e-fdc65d1118a9",
+   "callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/11111/status/0b40cd14-2e5d-490f-bb6e-fdc65d1118a9",
+   "requestUrl":"http://dns.api.rackspacecloud.com/v1.0/11111/domains/2946181/records/2346"
+}
+

Added: libcloud/trunk/test/dns/fixtures/rackspace/delete_zone_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/delete_zone_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/delete_zone_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/delete_zone_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,7 @@
+{
+   "status":"COMPLETED",
+   "verb":"DELETE",
+   "jobId":"0b40cd14-2e5d-490f-bb6e-fdc65d1118a9",
+   "callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/11111/status/0b40cd14-2e5d-490f-bb6e-fdc65d1118a9",
+   "requestUrl":"http://dns.api.rackspacecloud.com/v1.0/11111/domains/2946181"
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/does_not_exist.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/does_not_exist.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/does_not_exist.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/does_not_exist.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1 @@
+{"message":"Object not Found.","code":404,"details":""}

Added: libcloud/trunk/test/dns/fixtures/rackspace/get_record_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/get_record_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/get_record_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/get_record_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,10 @@
+{
+   "name":"test3.foo4.bar.com",
+   "id":"A-7423034",
+   "type":"A",
+   "comment":"lulz",
+   "data":"127.7.7.7",
+   "updated":"2011-10-29T18:42:28.000+0000",
+   "ttl":777,
+   "created":"2011-10-29T15:29:29.000+0000"
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/get_zone_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/get_zone_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/get_zone_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/get_zone_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,51 @@
+{
+   "name":"foo4.bar.com",
+   "id":2946063,
+   "comment":"wazaaa",
+   "accountId":11111,
+   "updated":"2011-10-29T18:42:28.000+0000",
+   "ttl":855,
+   "recordsList":{
+      "records":[
+         {
+            "name":"test3.foo4.bar.com",
+            "id":"A-7423034",
+            "type":"A",
+            "comment":"lulz",
+            "data":"127.7.7.7",
+            "updated":"2011-10-29T18:42:28.000+0000",
+            "ttl":777,
+            "created":"2011-10-29T15:29:29.000+0000"
+         },
+         {
+            "name":"foo4.bar.com",
+            "id":"NS-6717885",
+            "type":"NS",
+            "data":"dns1.stabletransit.com",
+            "updated":"2011-10-29T14:47:09.000+0000",
+            "ttl":3600,
+            "created":"2011-10-29T14:47:09.000+0000"
+         },
+         {
+            "name":"foo4.bar.com",
+            "id":"NS-6717886",
+            "type":"NS",
+            "data":"dns2.stabletransit.com",
+            "updated":"2011-10-29T14:47:09.000+0000",
+            "ttl":3600,
+            "created":"2011-10-29T14:47:09.000+0000"
+         }
+      ],
+      "totalEntries":3
+   },
+   "emailAddress":"test@test.com",
+   "nameservers":[
+      {
+         "name":"ns.rackspace.com"
+      },
+      {
+         "name":"ns2.rackspace.com"
+      }
+   ],
+   "created":"2011-10-29T14:47:09.000+0000"
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/list_records_no_results.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/list_records_no_results.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/list_records_no_results.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/list_records_no_results.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,22 @@
+{
+   "name":"foo4.bar.com",
+   "id":2946063,
+   "comment":"wazaaa",
+   "accountId":11111,
+   "updated":"2011-10-29T18:42:28.000+0000",
+   "ttl":855,
+   "recordsList":{
+      "records":[],
+      "totalEntries":0
+   },
+   "emailAddress":"kami@kami.si",
+   "nameservers":[
+      {
+         "name":"ns.rackspace.com"
+      },
+      {
+         "name":"ns2.rackspace.com"
+      }
+   ],
+   "created":"2011-10-29T14:47:09.000+0000"
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/list_records_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/list_records_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/list_records_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/list_records_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,51 @@
+{
+   "name":"foo4.bar.com",
+   "id":2946063,
+   "comment":"wazaaa",
+   "accountId":11111,
+   "updated":"2011-10-29T18:42:28.000+0000",
+   "ttl":855,
+   "recordsList":{
+      "records":[
+         {
+            "name":"test3.foo4.bar.com",
+            "id":"A-7423034",
+            "type":"A",
+            "comment":"lulz",
+            "data":"127.7.7.7",
+            "updated":"2011-10-29T18:42:28.000+0000",
+            "ttl":777,
+            "created":"2011-10-29T15:29:29.000+0000"
+         },
+         {
+            "name":"foo4.bar.com",
+            "id":"NS-6717885",
+            "type":"NS",
+            "data":"dns1.stabletransit.com",
+            "updated":"2011-10-29T14:47:09.000+0000",
+            "ttl":3600,
+            "created":"2011-10-29T14:47:09.000+0000"
+         },
+         {
+            "name":"foo4.bar.com",
+            "id":"NS-6717886",
+            "type":"NS",
+            "data":"dns2.stabletransit.com",
+            "updated":"2011-10-29T14:47:09.000+0000",
+            "ttl":3600,
+            "created":"2011-10-29T14:47:09.000+0000"
+         }
+      ],
+      "totalEntries":3
+   },
+   "emailAddress":"test@test.com",
+   "nameservers":[
+      {
+         "name":"ns.rackspace.com"
+      },
+      {
+         "name":"ns2.rackspace.com"
+      }
+   ],
+   "created":"2011-10-29T14:47:09.000+0000"
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/list_zones_no_results.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/list_zones_no_results.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/list_zones_no_results.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/list_zones_no_results.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,5 @@
+{
+   "domains":[],
+   "totalEntries":0
+}
+

Added: libcloud/trunk/test/dns/fixtures/rackspace/list_zones_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/list_zones_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/list_zones_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/list_zones_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,53 @@
+{
+   "domains":[
+      {
+         "name":"foo4.bar.com",
+         "id":2946063,
+         "comment":"wazaaa",
+         "accountId":11111,
+         "updated":"2011-10-29T18:42:28.000+0000",
+         "created":"2011-10-29T14:47:09.000+0000"
+      },
+      {
+         "name":"foo5.bar.com",
+         "id":2946065,
+         "comment":"fuu",
+         "accountId":11111,
+         "updated":"2011-10-29T14:48:39.000+0000",
+         "created":"2011-10-29T14:48:39.000+0000"
+      },
+      {
+         "name":"foo6.bar.com",
+         "id":2946066,
+         "comment":"fuu",
+         "accountId":11111,
+         "updated":"2011-10-29T14:48:59.000+0000",
+         "created":"2011-10-29T14:48:58.000+0000"
+      },
+      {
+         "name":"foo7.bar.com",
+         "id":2946068,
+         "comment":"fuu",
+         "accountId":11111,
+         "updated":"2011-10-29T14:49:14.000+0000",
+         "created":"2011-10-29T14:49:13.000+0000"
+      },
+      {
+         "name":"foo8.bar.com",
+         "id":2946069,
+         "comment":"fuu",
+         "accountId":11111,
+         "updated":"2011-10-29T14:49:44.000+0000",
+         "created":"2011-10-29T14:49:43.000+0000"
+      },
+      {
+         "name":"foo9.bar.com",
+         "id":2946071,
+         "comment":"fuu",
+         "accountId":11111,
+         "updated":"2011-10-29T14:54:45.000+0000",
+         "created":"2011-10-29T14:54:45.000+0000"
+      }
+   ],
+   "totalEntries":6
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/unauthorized.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/unauthorized.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/unauthorized.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/unauthorized.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1 @@
+{"unauthorized":{"message":"Username or api key is invalid","code":401}}

Added: libcloud/trunk/test/dns/fixtures/rackspace/update_record_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/update_record_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/update_record_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/update_record_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,8 @@
+{
+   "request":"{\"comment\": \"lulz\", \"data\": \"127.3.3.3\", \"name\": \"www.bar.foo1.com\", \"ttl\": 777}",
+   "status":"COMPLETED",
+   "verb":"PUT",
+   "jobId":"251c0d0c-95bc-4e09-b99f-4b8748b66246",
+   "callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/546514/status/251c0d0c-95bc-4e09-b99f-4b8748b66246",
+   "requestUrl":"http://dns.api.rackspacecloud.com/v1.0/546514/domains/2946173/records/A-7423317"
+}

Added: libcloud/trunk/test/dns/fixtures/rackspace/update_zone_success.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/fixtures/rackspace/update_zone_success.json?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/fixtures/rackspace/update_zone_success.json (added)
+++ libcloud/trunk/test/dns/fixtures/rackspace/update_zone_success.json Sat Oct 29 23:03:22 2011
@@ -0,0 +1,8 @@
+{
+   "request":"{}",
+   "status":"COMPLETED",
+   "verb":"PUT",
+   "jobId":"116a8f17-38ac-4862-827c-506cd04800d5",
+   "callbackUrl":"https://dns.api.rackspacecloud.com/v1.0/11111/status/116a8f17-38ac-4862-827c-506cd04800d5",
+   "requestUrl":"http://dns.api.rackspacecloud.com/v1.0/11111/domains/2946173"
+}

Added: libcloud/trunk/test/dns/test_rackspace.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/dns/test_rackspace.py?rev=1195069&view=auto
==============================================================================
--- libcloud/trunk/test/dns/test_rackspace.py (added)
+++ libcloud/trunk/test/dns/test_rackspace.py Sat Oct 29 23:03:22 2011
@@ -0,0 +1,408 @@
+# 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
+
+import sys
+import httplib
+import unittest
+
+from libcloud.common.types import LibcloudError
+from libcloud.dns.types import RecordType, ZoneDoesNotExistError
+from libcloud.dns.types import RecordDoesNotExistError
+from libcloud.dns.drivers.rackspace import RackspaceUSDNSDriver
+from libcloud.dns.drivers.rackspace import RackspaceUKDNSDriver
+
+from test import MockHttp
+from test.file_fixtures import DNSFileFixtures
+from test.secrets import DNS_PARAMS_RACKSPACE
+
+
+class RackspaceUSTests(unittest.TestCase):
+    klass = RackspaceUSDNSDriver
+
+    def setUp(self):
+        self.klass.connectionCls.conn_classes = (
+                None, RackspaceMockHttp)
+        RackspaceMockHttp.type = None
+        self.driver = self.klass(*DNS_PARAMS_RACKSPACE)
+
+    def test_list_zones_success(self):
+        zones = self.driver.list_zones()
+
+        self.assertEqual(len(zones), 6)
+        self.assertEqual(zones[0].domain, 'foo4.bar.com')
+        self.assertEqual(zones[0].extra['comment'], 'wazaaa')
+
+    def test_list_zones_no_results(self):
+        RackspaceMockHttp.type = 'NO_RESULTS'
+        zones = self.driver.list_zones()
+        self.assertEqual(len(zones), 0)
+
+    def test_list_records_success(self):
+        zone = self.driver.list_zones()[0]
+        records = self.driver.list_records(zone=zone)
+
+        self.assertEqual(len(records), 3)
+        self.assertEqual(records[0].name, 'test3')
+        self.assertEqual(records[0].type, RecordType.A)
+        self.assertEqual(records[0].data, '127.7.7.7')
+        self.assertEqual(records[0].extra['ttl'], 777)
+        self.assertEqual(records[0].extra['fqdn'], 'test3.%s' %
+                         (records[0].zone.domain))
+
+    def test_list_records_no_results(self):
+        zone = self.driver.list_zones()[0]
+        RackspaceMockHttp.type = 'NO_RESULTS'
+        records = self.driver.list_records(zone=zone)
+        self.assertEqual(len(records), 0)
+
+    def test_list_records_zone_does_not_exist(self):
+        zone = self.driver.list_zones()[0]
+
+        RackspaceMockHttp.type = 'ZONE_DOES_NOT_EXIST'
+        try:
+            self.driver.list_records(zone=zone)
+        except ZoneDoesNotExistError, e:
+            self.assertEqual(e.zone_id, zone.id)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_get_zone_success(self):
+        RackspaceMockHttp.type = 'GET_ZONE'
+        zone = self.driver.get_zone(zone_id='2946063')
+
+        self.assertEqual(zone.id, '2946063')
+        self.assertEqual(zone.domain, 'foo4.bar.com')
+        self.assertEqual(zone.type, 'master')
+        self.assertEqual(zone.extra['email'], 'test@test.com')
+
+    def test_get_zone_does_not_exist(self):
+        RackspaceMockHttp.type = 'DOES_NOT_EXIST'
+
+        try:
+            self.driver.get_zone(zone_id='4444')
+        except ZoneDoesNotExistError, e:
+            self.assertEqual(e.zone_id, '4444')
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_get_record_success(self):
+        record = self.driver.get_record(zone_id='12345678',
+                                        record_id='23456789')
+        self.assertEqual(record.id, 'A-7423034')
+        self.assertEqual(record.name, 'test3')
+        self.assertEqual(record.type, RecordType.A)
+        self.assertEqual(record.extra['comment'], 'lulz')
+
+    def test_get_record_zone_does_not_exist(self):
+        RackspaceMockHttp.type = 'ZONE_DOES_NOT_EXIST'
+
+        try:
+            self.driver.get_record(zone_id='444', record_id='28536')
+        except ZoneDoesNotExistError:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_get_record_record_does_not_exist(self):
+        RackspaceMockHttp.type = 'RECORD_DOES_NOT_EXIST'
+
+        try:
+            self.driver.get_record(zone_id='12345678',
+                                   record_id='28536')
+        except RecordDoesNotExistError:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_create_zone_success(self):
+        RackspaceMockHttp.type = 'CREATE_ZONE'
+
+        zone = self.driver.create_zone(domain='bar.foo1.com', type='master',
+                                       ttl=None,
+                                       extra={'email': 'test@test.com'})
+        self.assertEqual(zone.id, '2946173')
+        self.assertEqual(zone.domain, 'bar.foo1.com')
+        self.assertEqual(zone.type, 'master')
+        self.assertEqual(zone.extra['email'], 'test@test.com')
+
+    def test_create_zone_validaton_error(self):
+        RackspaceMockHttp.type = 'CREATE_ZONE_VALIDATION_ERROR'
+
+        try:
+            self.driver.create_zone(domain='foo.bar.com', type='master',
+                                    ttl=10,
+                                    extra={'email': 'test@test.com'})
+        except Exception, e:
+            self.assertEqual(str(e), 'Validation errors: Domain TTL is ' +
+                                      'required and must be greater than ' +
+                                      'or equal to 300')
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_update_zone_success(self):
+        zone = self.driver.list_zones()[0]
+        updated_zone = self.driver.update_zone(zone=zone,
+                                               extra={'comment':
+                                                      'bar foo'})
+
+        self.assertEqual(zone.extra['comment'], 'wazaaa')
+
+        self.assertEqual(updated_zone.id, zone.id)
+        self.assertEqual(updated_zone.domain, 'foo4.bar.com')
+        self.assertEqual(updated_zone.type, zone.type)
+        self.assertEqual(updated_zone.ttl, zone.ttl)
+        self.assertEqual(updated_zone.extra['comment'], 'bar foo')
+
+    def test_update_zone_domain_cannot_be_changed(self):
+        zone = self.driver.list_zones()[0]
+
+        try:
+            self.driver.update_zone(zone=zone, domain='libcloud.org')
+        except LibcloudError:
+            pass
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_create_record_success(self):
+        zone = self.driver.list_zones()[0]
+
+        RackspaceMockHttp.type = 'CREATE_RECORD'
+        record = self.driver.create_record(name='www', zone=zone,
+                                           type=RecordType.A, data='127.1.1.1')
+
+        self.assertEqual(record.id, 'A-7423317')
+        self.assertEqual(record.name, 'www')
+        self.assertEqual(record.zone, zone)
+        self.assertEqual(record.type, RecordType.A)
+        self.assertEqual(record.data, '127.1.1.1')
+        self.assertEqual(record.extra['fqdn'], 'www.%s' % (zone.domain))
+
+    def test_update_record_success(self):
+        zone = self.driver.list_zones()[0]
+        record = self.driver.list_records(zone=zone)[0]
+        updated_record = self.driver.update_record(record=record,
+                                                   data='127.3.3.3')
+
+        self.assertEqual(record.name, 'test3')
+        self.assertEqual(record.data, '127.7.7.7')
+
+        self.assertEqual(updated_record.id, record.id)
+        self.assertEqual(updated_record.name, record.name)
+        self.assertEqual(updated_record.zone, record.zone)
+        self.assertEqual(updated_record.type, record.type)
+        self.assertEqual(updated_record.data, '127.3.3.3')
+
+    def test_delete_zone_success(self):
+        zone = self.driver.list_zones()[0]
+        status = self.driver.delete_zone(zone=zone)
+        self.assertTrue(status)
+
+    def test_delete_zone_does_not_exist(self):
+        zone = self.driver.list_zones()[0]
+
+        RackspaceMockHttp.type = 'ZONE_DOES_NOT_EXIST'
+
+        try:
+            self.driver.delete_zone(zone=zone)
+        except ZoneDoesNotExistError, e:
+            self.assertEqual(e.zone_id, zone.id)
+        else:
+            self.fail('Exception was not thrown')
+
+    def test_delete_record_success(self):
+        zone = self.driver.list_zones()[0]
+        record = self.driver.list_records(zone=zone)[0]
+        status = self.driver.delete_record(record=record)
+        self.assertTrue(status)
+
+    def test_delete_record_does_not_exist(self):
+        zone = self.driver.list_zones()[0]
+        record = self.driver.list_records(zone=zone)[0]
+
+        RackspaceMockHttp.type = 'RECORD_DOES_NOT_EXIST'
+
+        try:
+            self.driver.delete_record(record=record)
+        except RecordDoesNotExistError, e:
+            self.assertEqual(e.record_id, record.id)
+        else:
+            self.fail('Exception was not thrown')
+
+
+class RackspaceUK1Tests(RackspaceUSTests):
+    klass = RackspaceUKDNSDriver
+
+
+class RackspaceMockHttp(MockHttp):
+    fixtures = DNSFileFixtures('rackspace')
+    base_headers = {'content-type': 'application/json'}
+
+    # fake auth token response
+    def _v1_1__auth(self, method, url, body, headers):
+        body = self.fixtures.load('auth_1_1.json')
+        headers = {'content-length': '657', 'vary': 'Accept,Accept-Encoding',
+                   'server': 'Apache/2.2.13 (Red Hat)',
+                   'connection': 'Keep-Alive',
+                   'date': 'Sat, 29 Oct 2011 19:29:45 GMT',
+                   'content-type': 'application/json'}
+        return (httplib.OK, body, headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains(self, method, url, body, headers):
+        body = self.fixtures.load('list_zones_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_NO_RESULTS(self, method, url, body, headers):
+        body = self.fixtures.load('list_zones_no_results.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_2946063(self, method, url, body, headers):
+        if method == 'GET':
+            body = self.fixtures.load('list_records_success.json')
+        elif method == 'PUT':
+            # Async - update_zone
+            body = self.fixtures.load('update_zone_success.json')
+        elif method == 'DELETE':
+            # Aync - delete_zone
+            body = self.fixtures.load('delete_zone_success.json')
+
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_2946063_NO_RESULTS(self, method, url, body,
+                                               headers):
+        body = self.fixtures.load('list_records_no_results.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_2946063_ZONE_DOES_NOT_EXIST(self, method, url,
+                                                        body, headers):
+        body = self.fixtures.load('does_not_exist.json')
+        return (httplib.NOT_FOUND, body, self.base_headers,
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _v1_0_11111_domains_2946063_GET_ZONE(self, method, url, body, headers):
+        body = self.fixtures.load('get_zone_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_4444_DOES_NOT_EXIST(self, method, url, body,
+                                                headers):
+        body = self.fixtures.load('does_not_exist.json')
+        return (httplib.NOT_FOUND, body, self.base_headers,
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _v1_0_11111_domains_12345678(self, method, url, body, headers):
+        body = self.fixtures.load('get_zone_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_12345678_records_23456789(self, method, url, body,
+                                                      headers):
+        body = self.fixtures.load('get_record_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_444_ZONE_DOES_NOT_EXIST(self, method, url, body,
+                                                    headers):
+        body = self.fixtures.load('does_not_exist.json')
+        return (httplib.NOT_FOUND, body, self.base_headers,
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _v1_0_11111_domains_12345678_RECORD_DOES_NOT_EXIST(self, method, url,
+                                                           body, headers):
+        body = self.fixtures.load('get_zone_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_12345678_records_28536_RECORD_DOES_NOT_EXIST(self,
+            method, url, body, headers):
+        body = self.fixtures.load('does_not_exist.json')
+        return (httplib.NOT_FOUND, body, self.base_headers,
+                httplib.responses[httplib.NOT_FOUND])
+
+    def _v1_0_11111_domains_CREATE_ZONE(self, method, url, body, headers):
+        # Async response - create_zone
+        body = self.fixtures.load('create_zone_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_status_288795f9_e74d_48be_880b_a9e36e0de61e_CREATE_ZONE(self,
+            method, url, body, headers):
+        # Async status - create_zone
+        body = self.fixtures.load('create_zone_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_CREATE_ZONE_VALIDATION_ERROR(self, method, url, body, headers):
+        body = self.fixtures.load('create_zone_validation_error.json')
+        return (httplib.BAD_REQUEST, body, self.base_headers,
+                httplib.responses[httplib.BAD_REQUEST])
+
+    def _v1_0_11111_status_116a8f17_38ac_4862_827c_506cd04800d5(self, method, url, body, headers):
+        # Aync status - update_zone
+        body = self.fixtures.load('update_zone_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_status_586605c8_5739_43fb_8939_f3a2c4c0e99c_CREATE_RECORD(self, method, url, body, headers):
+        # Aync status - create_record
+        body = self.fixtures.load('create_record_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_2946063_records_CREATE_RECORD(self, method, url, body, headers):
+        # Aync response - create_record
+        body = self.fixtures.load('create_record_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_status_251c0d0c_95bc_4e09_b99f_4b8748b66246(self, method, url, body, headers):
+        # Aync response - update_record
+        body = self.fixtures.load('update_record_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_2946063_records_A_7423034(self, method, url, body,
+                                                      headers):
+        # Aync response - update_record
+        body = self.fixtures.load('update_record_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_status_0b40cd14_2e5d_490f_bb6e_fdc65d1118a9(self, method,
+                                                                url, body,
+                                                                headers):
+        # Async status - delete_zone
+        body = self.fixtures.load('delete_zone_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_status_0b40cd14_2e5d_490f_bb6e_fdc65d1118a9_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
+        # Async status - delete_record
+        body = self.fixtures.load('delete_record_success.json')
+        return (httplib.OK, body, self.base_headers,
+                httplib.responses[httplib.OK])
+
+    def _v1_0_11111_domains_2946063_records_A_7423034_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
+        # Async response - delete_record
+        body = self.fixtures.load('does_not_exist.json')
+        return (httplib.NOT_FOUND, body, self.base_headers,
+                httplib.responses[httplib.NOT_FOUND])
+
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())

Modified: libcloud/trunk/test/secrets.py-dist
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/secrets.py-dist?rev=1195069&r1=1195068&r2=1195069&view=diff
==============================================================================
--- libcloud/trunk/test/secrets.py-dist (original)
+++ libcloud/trunk/test/secrets.py-dist Sat Oct 29 23:03:22 2011
@@ -42,3 +42,4 @@ STORAGE_GOOGLE_STORAGE_PARAMS = ('key', 
 # DNS
 DNS_PARAMS_LINODE = ('user', 'key')
 DNS_PARAMS_ZERIGO = ('email', 'api token')
+DNS_PARAMS_RACKSPACE = ('user', 'key')