libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject [1/2] libcloud git commit: [LIBCLOUD-640] Add support for Softlayer DNS driver.
Date Tue, 16 Dec 2014 21:51:26 GMT
Repository: libcloud
Updated Branches:
  refs/heads/trunk 791ff6a46 -> ab68dd92c


[LIBCLOUD-640] Add support for Softlayer DNS driver.

Closes #413

Signed-off-by: Tomaz Muraus <tomaz@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/dd7ba77e
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/dd7ba77e
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/dd7ba77e

Branch: refs/heads/trunk
Commit: dd7ba77eb71448373ccf5845145ac64d4c2937c4
Parents: 791ff6a
Author: Vanč Levstik <vanc.levstik@gmail.com>
Authored: Mon Dec 8 19:08:37 2014 +0100
Committer: Tomaz Muraus <tomaz@apache.org>
Committed: Tue Dec 16 22:43:19 2014 +0100

----------------------------------------------------------------------
 CHANGES.rst                                     |   7 +
 libcloud/common/softlayer.py                    |  88 ++++
 libcloud/compute/drivers/softlayer.py           |  63 +--
 libcloud/dns/drivers/softlayer.py               | 213 ++++++++
 libcloud/dns/providers.py                       |   2 +
 libcloud/dns/types.py                           |   1 +
 .../test/dns/fixtures/softlayer/not_found.xml   |  21 +
 ...r_Dns_Domain_ResourceRecord_createObject.xml | 331 ++++++++++++
 ...r_Dns_Domain_ResourceRecord_deleteObject.xml |   8 +
 ...yer_Dns_Domain_ResourceRecord_editObject.xml |   8 +
 ...ayer_Dns_Domain_ResourceRecord_getObject.xml |  81 +++
 ..._Domain_ResourceRecord_getObject_changed.xml |  81 +++
 .../v3_SoftLayer_Dns_Domain_createObject.xml    | 506 +++++++++++++++++++
 .../v3_SoftLayer_Dns_Domain_deleteObject.xml    |   8 +
 .../v3_SoftLayer_Dns_Domain_getByDomainName.xml |  39 ++
 .../v3_SoftLayer_Dns_Domain_getObject.xml       |  39 ++
 ..._SoftLayer_Dns_Domain_getResourceRecords.xml | 297 +++++++++++
 libcloud/test/dns/test_softlayer.py             | 255 ++++++++++
 18 files changed, 1986 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index c7a0aba..a90d2ff 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -111,6 +111,13 @@ Storage
   (GITHUB-408, LIBCLOUD-639)
   [Peter Schmidt]
 
+DNS
+~~~
+
+- New driver for Softlayer DNS service.
+  (GITHUB-413, LIBCLOUD-640)
+  [Vanč Levstik]
+
 Changes with Apache Libcloud 0.16.0
 -----------------------------------
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/common/softlayer.py
----------------------------------------------------------------------
diff --git a/libcloud/common/softlayer.py b/libcloud/common/softlayer.py
new file mode 100644
index 0000000..d41b431
--- /dev/null
+++ b/libcloud/common/softlayer.py
@@ -0,0 +1,88 @@
+# 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.
+"""
+Softlayer connection
+"""
+
+from libcloud.common.base import ConnectionUserAndKey
+from libcloud.common.xmlrpc import XMLRPCResponse, XMLRPCConnection
+from libcloud.common.types import InvalidCredsError, LibcloudError
+
+
+class SoftLayerException(LibcloudError):
+    """
+    Exception class for SoftLayer driver
+    """
+    pass
+
+
+class SoftLayerObjectDoesntExist(LibcloudError):
+    """
+    Exception class for SoftLayer driver object doesnt exist
+    """
+    pass
+
+
+class SoftLayerResponse(XMLRPCResponse):
+    defaultExceptionCls = SoftLayerException
+    exceptions = {
+        'SoftLayer_Account': InvalidCredsError,
+        'SoftLayer_Exception_ObjectNotFound': SoftLayerObjectDoesntExist
+    }
+
+
+class SoftLayerConnection(XMLRPCConnection, ConnectionUserAndKey):
+    responseCls = SoftLayerResponse
+    host = 'api.softlayer.com'
+    endpoint = '/xmlrpc/v3'
+
+    def request(self, service, method, *args, **kwargs):
+        headers = {}
+        headers.update(self._get_auth_headers())
+        headers.update(self._get_init_params(service, kwargs.get('id')))
+        headers.update(
+            self._get_object_mask(service, kwargs.get('object_mask')))
+        headers.update(
+            self._get_object_mask(service, kwargs.get('object_mask')))
+
+        args = ({'headers': headers}, ) + args
+        endpoint = '%s/%s' % (self.endpoint, service)
+        return super(SoftLayerConnection, self).request(method, *args,
+                                                        **{'endpoint':
+                                                            endpoint})
+
+    def _get_auth_headers(self):
+        return {
+            'authenticate': {
+                'username': self.user_id,
+                'apiKey': self.key
+            }
+        }
+
+    def _get_init_params(self, service, id):
+        if id is not None:
+            return {
+                '%sInitParameters' % service: {'id': id}
+            }
+        else:
+            return {}
+
+    def _get_object_mask(self, service, mask):
+        if mask is not None:
+            return {
+                '%sObjectMask' % service: {'mask': mask}
+            }
+        else:
+            return {}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/compute/drivers/softlayer.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/softlayer.py b/libcloud/compute/drivers/softlayer.py
index 61a1e1a..238fd5f 100644
--- a/libcloud/compute/drivers/softlayer.py
+++ b/libcloud/compute/drivers/softlayer.py
@@ -23,9 +23,7 @@ try:
 except ImportError:
     crypto = False
 
-from libcloud.common.base import ConnectionUserAndKey
-from libcloud.common.xmlrpc import XMLRPCResponse, XMLRPCConnection
-from libcloud.common.types import InvalidCredsError, LibcloudError
+from libcloud.common.softlayer import SoftLayerConnection, SoftLayerException
 from libcloud.compute.types import Provider, NodeState
 from libcloud.compute.base import NodeDriver, Node, NodeLocation, NodeSize, \
     NodeImage, KeyPair
@@ -134,65 +132,6 @@ for i, template in enumerate(SL_BASE_TEMPLATES):
     SL_TEMPLATES[i] = local
 
 
-class SoftLayerException(LibcloudError):
-    """
-    Exception class for SoftLayer driver
-    """
-    pass
-
-
-class SoftLayerResponse(XMLRPCResponse):
-    defaultExceptionCls = SoftLayerException
-    exceptions = {
-        'SoftLayer_Account': InvalidCredsError,
-    }
-
-
-class SoftLayerConnection(XMLRPCConnection, ConnectionUserAndKey):
-    responseCls = SoftLayerResponse
-    host = 'api.softlayer.com'
-    endpoint = '/xmlrpc/v3'
-
-    def request(self, service, method, *args, **kwargs):
-        headers = {}
-        headers.update(self._get_auth_headers())
-        headers.update(self._get_init_params(service, kwargs.get('id')))
-        headers.update(
-            self._get_object_mask(service, kwargs.get('object_mask')))
-        headers.update(
-            self._get_object_mask(service, kwargs.get('object_mask')))
-
-        args = ({'headers': headers}, ) + args
-        endpoint = '%s/%s' % (self.endpoint, service)
-        return super(SoftLayerConnection, self).request(method, *args,
-                                                        **{'endpoint':
-                                                            endpoint})
-
-    def _get_auth_headers(self):
-        return {
-            'authenticate': {
-                'username': self.user_id,
-                'apiKey': self.key
-            }
-        }
-
-    def _get_init_params(self, service, id):
-        if id is not None:
-            return {
-                '%sInitParameters' % service: {'id': id}
-            }
-        else:
-            return {}
-
-    def _get_object_mask(self, service, mask):
-        if mask is not None:
-            return {
-                '%sObjectMask' % service: {'mask': mask}
-            }
-        else:
-            return {}
-
-
 class SoftLayerNodeDriver(NodeDriver):
     """
     SoftLayer node driver

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/dns/drivers/softlayer.py
----------------------------------------------------------------------
diff --git a/libcloud/dns/drivers/softlayer.py b/libcloud/dns/drivers/softlayer.py
new file mode 100644
index 0000000..43a537c
--- /dev/null
+++ b/libcloud/dns/drivers/softlayer.py
@@ -0,0 +1,213 @@
+# 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__ = [
+    'SoftLayerDNSDriver'
+]
+
+
+from libcloud.common.softlayer import SoftLayerConnection
+from libcloud.common.softlayer import SoftLayerObjectDoesntExist
+from libcloud.dns.types import Provider, RecordType
+from libcloud.dns.types import ZoneDoesNotExistError, RecordDoesNotExistError
+from libcloud.dns.base import DNSDriver, Zone, Record
+
+
+VALID_RECORD_EXTRA_PARAMS = ['priority', 'ttl']
+
+
+class SoftLayerDNSDriver(DNSDriver):
+    type = Provider.SOFTLAYER
+    name = 'Softlayer DNS'
+    website = 'https://www.softlayer.com'
+    connectionCls = SoftLayerConnection
+
+    RECORD_TYPE_MAP = {
+        RecordType.A: 'a',
+        RecordType.AAAA: 'aaaa',
+        RecordType.CNAME: 'cname',
+        RecordType.MX: 'mx',
+        RecordType.NS: 'ns',
+        RecordType.PTR: 'ptr',
+        RecordType.SOA: 'soa',
+        RecordType.SPF: 'spf',
+        RecordType.SRV: 'srv',
+        RecordType.TXT: 'txt',
+    }
+
+    def create_zone(self, domain, ttl=None, extra=None):
+        self.connection.set_context({'resource': 'zone', 'id': domain})
+        data = {
+            'name': domain,
+            'resourceRecords': []
+        }
+        response = self.connection.request(
+            'SoftLayer_Dns_Domain', 'createObject', data
+        ).object
+        zone = Zone(id=response['id'], domain=domain,
+                    type='master', ttl=3600, driver=self)
+        return zone
+
+    def get_zone(self, zone_id):
+        self.connection.set_context({'resource': 'zone', 'id': zone_id})
+        try:
+            response = self.connection.request(
+                'SoftLayer_Dns_Domain', 'getObject', id=zone_id
+            ).object
+        except SoftLayerObjectDoesntExist:
+            raise ZoneDoesNotExistError(value='', driver=self,
+                                        zone_id=zone_id)
+        return self._to_zone(response)
+
+    def delete_zone(self, zone):
+        self.connection.set_context({'resource': 'zone', 'id': zone.id})
+        try:
+            self.connection.request(
+                'SoftLayer_Dns_Domain', 'deleteObject', id=zone.id
+            ).object
+        except SoftLayerObjectDoesntExist:
+            raise ZoneDoesNotExistError(value='', driver=self,
+                                        zone_id=zone.id)
+        else:
+            return True
+
+    def iterate_zones(self):
+        zones_list = self.connection.request(
+            'SoftLayer_Dns_Domain', 'getByDomainName', '.'
+        ).object
+        for item in zones_list:
+            yield self._to_zone(item)
+
+    def iterate_records(self, zone):
+        self.connection.set_context({'resource': 'zone', 'id': zone.id})
+        records_list = self.connection.request(
+            'SoftLayer_Dns_Domain', 'getResourceRecords', id=zone.id
+        ).object
+        for item in records_list:
+            yield self._to_record(item, zone=zone)
+
+    def get_record(self, zone_id, record_id):
+        try:
+            record = self.connection.request(
+                'SoftLayer_Dns_Domain_ResourceRecord',
+                'getObject',
+                id=record_id
+            ).object
+            return self._to_record(record, zone=self.get_zone(zone_id))
+        except SoftLayerObjectDoesntExist:
+            raise RecordDoesNotExistError(value='', driver=self,
+                                          record_id=record_id)
+
+    def delete_record(self, record):
+        try:
+            self.connection.request(
+                'SoftLayer_Dns_Domain_ResourceRecord',
+                'deleteObject',
+                id=record.id
+            ).object
+        except SoftLayerObjectDoesntExist:
+            raise RecordDoesNotExistError(value='', driver=self,
+                                          record_id=record.id)
+        else:
+            return True
+
+    def create_record(self, name, zone, type, data, extra=None):
+        params = {
+            'domainId': zone.id,
+            'type': self.RECORD_TYPE_MAP[type],
+            'host': name,
+            'data': data
+        }
+        if extra:
+            if extra.get('ttl'):
+                params['ttl'] = extra['ttl']
+            if extra.get('refresh'):
+                params['refresh'] = extra['refresh']
+            if extra.get('retry'):
+                params['retry'] = extra['retry']
+            if extra.get('expire'):
+                params['expire'] = extra['expire']
+            if extra.get('priority'):
+                params['mxPriority'] = extra['priority']
+        response = self.connection.request(
+            'SoftLayer_Dns_Domain_ResourceRecord',
+            'createObject',
+            params
+        ).object
+
+        return self._to_record(response, zone=zone)
+
+    def update_record(
+            self, record, name=None, type=None, data=None, extra=None):
+        params = {}
+        if type:
+            params['type'] = self.RECORD_TYPE_MAP[type]
+        if name:
+            params['host'] = name
+        if data:
+            params['data'] = data
+
+        if extra:
+            if extra.get('ttl'):
+                params['ttl'] = extra['ttl']
+            if extra.get('refresh'):
+                params['refresh'] = extra['refresh']
+            if extra.get('retry'):
+                params['retry'] = extra['retry']
+            if extra.get('expire'):
+                params['expire'] = extra['expire']
+            if extra.get('priority'):
+                params['mxPriority'] = extra['priority']
+
+        response = self.connection.request(
+            'SoftLayer_Dns_Domain_ResourceRecord',
+            'editObject',
+            params,
+            id=record.id,
+        ).object
+
+        if response:
+            changed_record = self.connection.request(
+                'SoftLayer_Dns_Domain_ResourceRecord',
+                'getObject',
+                id=record.id,
+            ).object
+            return self._to_record(changed_record, zone=record.zone)
+        else:
+            return False
+
+    def _to_zone(self, item):
+        ttl = item.get('ttl', 3600)
+        zone = Zone(id=item['id'], domain=item['name'],
+                    type='master', ttl=ttl, driver=self)
+        return zone
+
+    def _to_record(self, item, zone=None):
+        extra = {
+            'ttl': item['ttl'],
+            'expire': item['expire'],
+            'mxPriority': item['mxPriority'],
+            'refresh': item['refresh'],
+            'retry': item['retry'],
+            }
+        record = Record(
+            id=item['id'],
+            name=item['host'],
+            type=self._string_to_record_type(item['type']),
+            data=item['data'],
+            zone=zone,
+            driver=self,
+            extra=extra
+        )
+        return record

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/dns/providers.py
----------------------------------------------------------------------
diff --git a/libcloud/dns/providers.py b/libcloud/dns/providers.py
index 64483a4..dc80460 100644
--- a/libcloud/dns/providers.py
+++ b/libcloud/dns/providers.py
@@ -33,6 +33,8 @@ DRIVERS = {
     Provider.GANDI:
     ('libcloud.dns.drivers.gandi', 'GandiDNSDriver'),
     Provider.GOOGLE: ('libcloud.dns.drivers.google', 'GoogleDNSDriver'),
+    Provider.SOFTLAYER:
+    ('libcloud.dns.drivers.softlayer', 'SoftLayerDNSDriver'),
     # Deprecated
     Provider.RACKSPACE_US:
     ('libcloud.dns.drivers.rackspace', 'RackspaceUSDNSDriver'),

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/dns/types.py
----------------------------------------------------------------------
diff --git a/libcloud/dns/types.py b/libcloud/dns/types.py
index 3b3a79e..32bceb5 100644
--- a/libcloud/dns/types.py
+++ b/libcloud/dns/types.py
@@ -36,6 +36,7 @@ class Provider(object):
     HOSTVIRTUAL = 'hostvirtual'
     GANDI = 'gandi'
     GOOGLE = 'google'
+    SOFTLAYER = 'softlayer'
 
     # Deprecated
     RACKSPACE_US = 'rackspace_us'

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/not_found.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/not_found.xml b/libcloud/test/dns/fixtures/softlayer/not_found.xml
new file mode 100644
index 0000000..5a4eed8
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/not_found.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<methodResponse>
+<fault>
+ <value>
+  <struct>
+   <member>
+    <name>faultCode</name>
+    <value>
+     <string>SoftLayer_Exception_ObjectNotFound</string>
+    </value>
+   </member>
+   <member>
+    <name>faultString</name>
+    <value>
+     <string>Unable to find object with id of \'333\'.</string>
+    </value>
+   </member>
+  </struct>
+ </value>
+</fault>
+</methodResponse>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_createObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_createObject.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_createObject.xml
new file mode 100644
index 0000000..dc412c7
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_createObject.xml
@@ -0,0 +1,331 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <struct>
+   <member>
+    <name>data</name>
+    <value>
+     <string>127.0.0.1</string>
+    </value>
+   </member>
+   <member>
+    <name>domainId</name>
+    <value>
+     <int>1752717</int>
+    </value>
+   </member>
+   <member>
+    <name>expire</name>
+    <value>
+     <string/>
+    </value>
+   </member>
+   <member>
+    <name>host</name>
+    <value>
+     <string>www</string>
+    </value>
+   </member>
+   <member>
+    <name>id</name>
+    <value>
+     <int>50772870</int>
+    </value>
+   </member>
+   <member>
+    <name>minimum</name>
+    <value>
+     <string/>
+    </value>
+   </member>
+   <member>
+    <name>mxPriority</name>
+    <value>
+     <string/>
+    </value>
+   </member>
+   <member>
+    <name>refresh</name>
+    <value>
+     <string/>
+    </value>
+   </member>
+   <member>
+    <name>retry</name>
+    <value>
+     <string/>
+    </value>
+   </member>
+   <member>
+    <name>ttl</name>
+    <value>
+     <int>86400</int>
+    </value>
+   </member>
+   <member>
+    <name>type</name>
+    <value>
+     <string>A</string>
+    </value>
+   </member>
+   <member>
+    <name>domain</name>
+    <value>
+     <struct>
+      <member>
+       <name>id</name>
+       <value>
+        <int>1752717</int>
+       </value>
+      </member>
+      <member>
+       <name>name</name>
+       <value>
+        <string>bar.com</string>
+       </value>
+      </member>
+      <member>
+       <name>serial</name>
+       <value>
+        <int>2014120804</int>
+       </value>
+      </member>
+      <member>
+       <name>updateDate</name>
+       <value>
+        <string>2014-12-08T11:36:55-06:00</string>
+       </value>
+      </member>
+      <member>
+       <name>resourceRecords</name>
+       <value>
+        <array>
+         <data>
+          <value>
+           <struct>
+            <member>
+             <name>data</name>
+             <value>
+              <string>ns1.softlayer.com.</string>
+             </value>
+            </member>
+            <member>
+             <name>domainId</name>
+             <value>
+              <int>123</int>
+             </value>
+            </member>
+            <member>
+             <name>expire</name>
+             <value>
+              <int>1728000</int>
+             </value>
+            </member>
+            <member>
+             <name>host</name>
+             <value>
+              <string>@</string>
+             </value>
+            </member>
+            <member>
+             <name>id</name>
+             <value>
+              <int>50772366</int>
+             </value>
+            </member>
+            <member>
+             <name>minimum</name>
+             <value>
+              <int>43200</int>
+             </value>
+            </member>
+            <member>
+             <name>mxPriority</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>refresh</name>
+             <value>
+              <int>7200</int>
+             </value>
+            </member>
+            <member>
+             <name>responsiblePerson</name>
+             <value>
+              <string>support.softlayer.com.</string>
+             </value>
+            </member>
+            <member>
+             <name>retry</name>
+             <value>
+              <int>600</int>
+             </value>
+            </member>
+            <member>
+             <name>ttl</name>
+             <value>
+              <int>86400</int>
+             </value>
+            </member>
+            <member>
+             <name>type</name>
+             <value>
+              <string>soa</string>
+             </value>
+            </member>
+           </struct>
+          </value>
+          <value>
+           <struct>
+            <member>
+             <name>data</name>
+             <value>
+              <string>ns1.softlayer.com.</string>
+             </value>
+            </member>
+            <member>
+             <name>domainId</name>
+             <value>
+              <int>1752717</int>
+             </value>
+            </member>
+            <member>
+             <name>expire</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>host</name>
+             <value>
+              <string>@</string>
+             </value>
+            </member>
+            <member>
+             <name>id</name>
+             <value>
+              <int>50772367</int>
+             </value>
+            </member>
+            <member>
+             <name>minimum</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>mxPriority</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>refresh</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>retry</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>ttl</name>
+             <value>
+              <int>86400</int>
+             </value>
+            </member>
+            <member>
+             <name>type</name>
+             <value>
+              <string>ns</string>
+             </value>
+            </member>
+           </struct>
+          </value>
+          <value>
+           <struct>
+            <member>
+             <name>data</name>
+             <value>
+              <string>ns2.softlayer.com.</string>
+             </value>
+            </member>
+            <member>
+             <name>domainId</name>
+             <value>
+              <int>1752717</int>
+             </value>
+            </member>
+            <member>
+             <name>expire</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>host</name>
+             <value>
+              <string>@</string>
+             </value>
+            </member>
+            <member>
+             <name>id</name>
+             <value>
+              <int>50772368</int>
+             </value>
+            </member>
+            <member>
+             <name>minimum</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>mxPriority</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>refresh</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>retry</name>
+             <value>
+              <string/>
+             </value>
+            </member>
+            <member>
+             <name>ttl</name>
+             <value>
+              <int>86400</int>
+             </value>
+            </member>
+            <member>
+             <name>type</name>
+             <value>
+              <string>ns</string>
+             </value>
+            </member>
+           </struct>
+          </value>
+         </data>
+        </array>
+       </value>
+      </member>
+     </struct>
+    </value>
+   </member>
+  </struct>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_deleteObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_deleteObject.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_deleteObject.xml
new file mode 100644
index 0000000..5dca377
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_deleteObject.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <boolean>1</boolean>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_editObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_editObject.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_editObject.xml
new file mode 100644
index 0000000..5dca377
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_editObject.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <boolean>1</boolean>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_getObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_getObject.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_getObject.xml
new file mode 100644
index 0000000..5b006af
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_getObject.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <struct>
+   <member>
+    <name>data</name>
+    <value>
+     <string>ns1.softlayer.com.</string>
+    </value>
+   </member>
+   <member>
+    <name>domainId</name>
+    <value>
+     <int>123</int>
+    </value>
+   </member>
+   <member>
+    <name>expire</name>
+    <value>
+     <int>1728000</int>
+    </value>
+   </member>
+   <member>
+    <name>host</name>
+    <value>
+     <string>@</string>
+    </value>
+   </member>
+   <member>
+    <name>id</name>
+    <value>
+     <int>50772366</int>
+    </value>
+   </member>
+   <member>
+    <name>minimum</name>
+    <value>
+     <int>43200</int>
+    </value>
+   </member>
+   <member>
+    <name>mxPriority</name>
+    <value>
+     <string/>
+    </value>
+   </member>
+   <member>
+    <name>refresh</name>
+    <value>
+     <int>7200</int>
+    </value>
+   </member>
+   <member>
+    <name>responsiblePerson</name>
+    <value>
+     <string>support.softlayer.com.</string>
+    </value>
+   </member>
+   <member>
+    <name>retry</name>
+    <value>
+     <int>600</int>
+    </value>
+   </member>
+   <member>
+    <name>ttl</name>
+    <value>
+     <int>86400</int>
+    </value>
+   </member>
+   <member>
+    <name>type</name>
+    <value>
+     <string>soa</string>
+    </value>
+   </member>
+  </struct>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_getObject_changed.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_getObject_changed.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_getObject_changed.xml
new file mode 100644
index 0000000..190edef
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_ResourceRecord_getObject_changed.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <struct>
+   <member>
+    <name>data</name>
+    <value>
+     <string>1.1.1.1</string>
+    </value>
+   </member>
+   <member>
+    <name>domainId</name>
+    <value>
+     <int>123</int>
+    </value>
+   </member>
+   <member>
+    <name>expire</name>
+    <value>
+     <int>1728000</int>
+    </value>
+   </member>
+   <member>
+    <name>host</name>
+    <value>
+     <string>www</string>
+    </value>
+   </member>
+   <member>
+    <name>id</name>
+    <value>
+     <int>123</int>
+    </value>
+   </member>
+   <member>
+    <name>minimum</name>
+    <value>
+     <int>43200</int>
+    </value>
+   </member>
+   <member>
+    <name>mxPriority</name>
+    <value>
+     <string/>
+    </value>
+   </member>
+   <member>
+    <name>refresh</name>
+    <value>
+     <int>7200</int>
+    </value>
+   </member>
+   <member>
+    <name>responsiblePerson</name>
+    <value>
+     <string>support.softlayer.com.</string>
+    </value>
+   </member>
+   <member>
+    <name>retry</name>
+    <value>
+     <int>600</int>
+    </value>
+   </member>
+   <member>
+    <name>ttl</name>
+    <value>
+     <int>30</int>
+    </value>
+   </member>
+   <member>
+    <name>type</name>
+    <value>
+     <string>a</string>
+    </value>
+   </member>
+  </struct>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_createObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_createObject.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_createObject.xml
new file mode 100644
index 0000000..02f058c
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_createObject.xml
@@ -0,0 +1,506 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <struct>
+   <member>
+    <name>id</name>
+    <value>
+     <int>123</int>
+    </value>
+   </member>
+   <member>
+    <name>name</name>
+    <value>
+     <string>bar.com</string>
+    </value>
+   </member>
+   <member>
+    <name>serial</name>
+    <value>
+     <int>2014120802</int>
+    </value>
+   </member>
+   <member>
+    <name>updateDate</name>
+    <value>
+     <string>2014-12-08T08:00:41-06:00</string>
+    </value>
+   </member>
+   <member>
+    <name>account</name>
+    <value>
+     <struct>
+      <member>
+       <name>accountManagedResourcesFlag</name>
+       <value>
+        <boolean>0</boolean>
+       </value>
+      </member>
+      <member>
+       <name>accountStatusId</name>
+       <value>
+        <int>1111</int>
+       </value>
+      </member>
+      <member>
+       <name>address1</name>
+       <value>
+        <string>Test 1</string>
+       </value>
+      </member>
+      <member>
+       <name>allowedPptpVpnQuantity</name>
+       <value>
+        <int>1</int>
+       </value>
+      </member>
+      <member>
+       <name>brandId</name>
+       <value>
+        <int>1</int>
+       </value>
+      </member>
+      <member>
+       <name>city</name>
+       <value>
+        <string>World</string>
+       </value>
+      </member>
+      <member>
+       <name>claimedTaxExemptTxFlag</name>
+       <value>
+        <boolean>0</boolean>
+       </value>
+      </member>
+      <member>
+       <name>companyName</name>
+       <value>
+        <string>Test</string>
+       </value>
+      </member>
+      <member>
+       <name>country</name>
+       <value>
+        <string>SI</string>
+       </value>
+      </member>
+      <member>
+       <name>createDate</name>
+       <value>
+        <string>2014-11-27T12:19:34-06:00</string>
+       </value>
+      </member>
+      <member>
+       <name>email</name>
+       <value>
+        <string>foo@bar.com</string>
+       </value>
+      </member>
+      <member>
+       <name>firstName</name>
+       <value>
+        <string>foo</string>
+       </value>
+      </member>
+      <member>
+       <name>id</name>
+       <value>
+        <int>11111</int>
+       </value>
+      </member>
+      <member>
+       <name>isReseller</name>
+       <value>
+        <int>0</int>
+       </value>
+      </member>
+      <member>
+       <name>lastName</name>
+       <value>
+        <string>Bar</string>
+       </value>
+      </member>
+      <member>
+       <name>lateFeeProtectionFlag</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>modifyDate</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>officePhone</name>
+       <value>
+        <string>1111111111</string>
+       </value>
+      </member>
+      <member>
+       <name>postalCode</name>
+       <value>
+        <string>1111</string>
+       </value>
+      </member>
+      <member>
+       <name>state</name>
+       <value>
+        <string>OT</string>
+       </value>
+      </member>
+      <member>
+       <name>statusDate</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>attributes</name>
+       <value>
+        <array>
+         <data/>
+        </array>
+       </value>
+      </member>
+      <member>
+       <name>brand</name>
+       <value>
+        <struct>
+         <member>
+          <name>catalogId</name>
+          <value>
+           <int>14</int>
+          </value>
+         </member>
+         <member>
+          <name>id</name>
+          <value>
+           <int>21</int>
+          </value>
+         </member>
+         <member>
+          <name>keyName</name>
+          <value>
+           <string>SOFTLAYER_EU</string>
+          </value>
+         </member>
+         <member>
+          <name>longName</name>
+          <value>
+           <string>SoftLayer Dutch Holdings B.V.</string>
+          </value>
+         </member>
+         <member>
+          <name>name</name>
+          <value>
+           <string>SoftLayer EU</string>
+          </value>
+         </member>
+        </struct>
+       </value>
+      </member>
+     </struct>
+    </value>
+   </member>
+   <member>
+    <name>resourceRecords</name>
+    <value>
+     <array>
+      <data>
+       <value>
+        <struct>
+         <member>
+          <name>data</name>
+          <value>
+           <string>127.0.0.1</string>
+          </value>
+         </member>
+         <member>
+          <name>domainId</name>
+          <value>
+           <int>123</int>
+          </value>
+         </member>
+         <member>
+          <name>expire</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>host</name>
+          <value>
+           <string>@</string>
+          </value>
+         </member>
+         <member>
+          <name>id</name>
+          <value>
+           <int>50771583</int>
+          </value>
+         </member>
+         <member>
+          <name>minimum</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>mxPriority</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>refresh</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>retry</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>ttl</name>
+          <value>
+           <int>86400</int>
+          </value>
+         </member>
+         <member>
+          <name>type</name>
+          <value>
+           <string>A</string>
+          </value>
+         </member>
+        </struct>
+       </value>
+       <value>
+        <struct>
+         <member>
+          <name>data</name>
+          <value>
+           <string>ns1.softlayer.com.</string>
+          </value>
+         </member>
+         <member>
+          <name>domainId</name>
+          <value>
+           <int>123</int>
+          </value>
+         </member>
+         <member>
+          <name>expire</name>
+          <value>
+           <int>604800</int>
+          </value>
+         </member>
+         <member>
+          <name>host</name>
+          <value>
+           <string>@</string>
+          </value>
+         </member>
+         <member>
+          <name>id</name>
+          <value>
+           <int>111111</int>
+          </value>
+         </member>
+         <member>
+          <name>minimum</name>
+          <value>
+           <int>3600</int>
+          </value>
+         </member>
+         <member>
+          <name>mxPriority</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>refresh</name>
+          <value>
+           <int>3600</int>
+          </value>
+         </member>
+         <member>
+          <name>responsiblePerson</name>
+          <value>
+           <string>root.bar.com.</string>
+          </value>
+         </member>
+         <member>
+          <name>retry</name>
+          <value>
+           <int>300</int>
+          </value>
+         </member>
+         <member>
+          <name>ttl</name>
+          <value>
+           <int>86400</int>
+          </value>
+         </member>
+         <member>
+          <name>type</name>
+          <value>
+           <string>SOA</string>
+          </value>
+         </member>
+        </struct>
+       </value>
+       <value>
+        <struct>
+         <member>
+          <name>data</name>
+          <value>
+           <string>ns1.softlayer.com.</string>
+          </value>
+         </member>
+         <member>
+          <name>domainId</name>
+          <value>
+           <int>1752657</int>
+          </value>
+         </member>
+         <member>
+          <name>expire</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>host</name>
+          <value>
+           <string>@</string>
+          </value>
+         </member>
+         <member>
+          <name>id</name>
+          <value>
+           <int>111111</int>
+          </value>
+         </member>
+         <member>
+          <name>minimum</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>mxPriority</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>refresh</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>retry</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>ttl</name>
+          <value>
+           <int>86400</int>
+          </value>
+         </member>
+         <member>
+          <name>type</name>
+          <value>
+           <string>NS</string>
+          </value>
+         </member>
+        </struct>
+       </value>
+       <value>
+        <struct>
+         <member>
+          <name>data</name>
+          <value>
+           <string>ns2.softlayer.com.</string>
+          </value>
+         </member>
+         <member>
+          <name>domainId</name>
+          <value>
+           <int>1111111</int>
+          </value>
+         </member>
+         <member>
+          <name>expire</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>host</name>
+          <value>
+           <string>@</string>
+          </value>
+         </member>
+         <member>
+          <name>id</name>
+          <value>
+           <int>50771586</int>
+          </value>
+         </member>
+         <member>
+          <name>minimum</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>mxPriority</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>refresh</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>retry</name>
+          <value>
+           <string/>
+          </value>
+         </member>
+         <member>
+          <name>ttl</name>
+          <value>
+           <int>86400</int>
+          </value>
+         </member>
+         <member>
+          <name>type</name>
+          <value>
+           <string>NS</string>
+          </value>
+         </member>
+        </struct>
+       </value>
+      </data>
+     </array>
+    </value>
+   </member>
+  </struct>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_deleteObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_deleteObject.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_deleteObject.xml
new file mode 100644
index 0000000..5dca377
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_deleteObject.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <boolean>1</boolean>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getByDomainName.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getByDomainName.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getByDomainName.xml
new file mode 100644
index 0000000..95a51c8
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getByDomainName.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <array>
+   <data>
+    <value>
+     <struct>
+      <member>
+       <name>id</name>
+       <value>
+        <int>123</int>
+       </value>
+      </member>
+      <member>
+       <name>name</name>
+       <value>
+        <string>bar.com</string>
+       </value>
+      </member>
+      <member>
+       <name>serial</name>
+       <value>
+        <int>2014120802</int>
+       </value>
+      </member>
+      <member>
+       <name>updateDate</name>
+       <value>
+        <string>2014-12-08T14:00:50-06:00</string>
+       </value>
+      </member>
+     </struct>
+    </value>
+   </data>
+  </array>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getObject.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getObject.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getObject.xml
new file mode 100644
index 0000000..2a09cc8
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getObject.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <struct>
+   <member>
+    <name>id</name>
+    <value>
+     <int>123</int>
+    </value>
+   </member>
+   <member>
+    <name>name</name>
+    <value>
+     <string>bar.com</string>
+    </value>
+   </member>
+   <member>
+    <name>serial</name>
+    <value>
+     <int>2014120802</int>
+    </value>
+   </member>
+   <member>
+    <name>updateDate</name>
+    <value>
+     <string>2014-12-08T14:00:50-06:00</string>
+    </value>
+   </member>
+   <member>
+    <name>managedResourceFlag</name>
+    <value>
+     <boolean>0</boolean>
+    </value>
+   </member>
+  </struct>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getResourceRecords.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getResourceRecords.xml b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getResourceRecords.xml
new file mode 100644
index 0000000..d723e87
--- /dev/null
+++ b/libcloud/test/dns/fixtures/softlayer/v3_SoftLayer_Dns_Domain_getResourceRecords.xml
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+  <array>
+   <data>
+    <value>
+     <struct>
+      <member>
+       <name>data</name>
+       <value>
+        <string>ns1.softlayer.com.</string>
+       </value>
+      </member>
+      <member>
+       <name>domainId</name>
+       <value>
+        <int>123</int>
+       </value>
+      </member>
+      <member>
+       <name>expire</name>
+       <value>
+        <int>604800</int>
+       </value>
+      </member>
+      <member>
+       <name>host</name>
+       <value>
+        <string>@</string>
+       </value>
+      </member>
+      <member>
+       <name>id</name>
+       <value>
+        <int>50772366</int>
+       </value>
+      </member>
+      <member>
+       <name>minimum</name>
+       <value>
+        <int>3600</int>
+       </value>
+      </member>
+      <member>
+       <name>mxPriority</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>refresh</name>
+       <value>
+        <int>3600</int>
+       </value>
+      </member>
+      <member>
+       <name>responsiblePerson</name>
+       <value>
+        <string>root.bar.com.</string>
+       </value>
+      </member>
+      <member>
+       <name>retry</name>
+       <value>
+        <int>300</int>
+       </value>
+      </member>
+      <member>
+       <name>ttl</name>
+       <value>
+        <int>86400</int>
+       </value>
+      </member>
+      <member>
+       <name>type</name>
+       <value>
+        <string>soa</string>
+       </value>
+      </member>
+     </struct>
+    </value>
+    <value>
+     <struct>
+      <member>
+       <name>data</name>
+       <value>
+        <string>ns1.softlayer.com.</string>
+       </value>
+      </member>
+      <member>
+       <name>domainId</name>
+       <value>
+        <int>1752717</int>
+       </value>
+      </member>
+      <member>
+       <name>expire</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>host</name>
+       <value>
+        <string>@</string>
+       </value>
+      </member>
+      <member>
+       <name>id</name>
+       <value>
+        <int>50772367</int>
+       </value>
+      </member>
+      <member>
+       <name>minimum</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>mxPriority</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>refresh</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>retry</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>ttl</name>
+       <value>
+        <int>86400</int>
+       </value>
+      </member>
+      <member>
+       <name>type</name>
+       <value>
+        <string>ns</string>
+       </value>
+      </member>
+     </struct>
+    </value>
+    <value>
+     <struct>
+      <member>
+       <name>data</name>
+       <value>
+        <string>ns2.softlayer.com.</string>
+       </value>
+      </member>
+      <member>
+       <name>domainId</name>
+       <value>
+        <int>123</int>
+       </value>
+      </member>
+      <member>
+       <name>expire</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>host</name>
+       <value>
+        <string>@</string>
+       </value>
+      </member>
+      <member>
+       <name>id</name>
+       <value>
+        <int>50772368</int>
+       </value>
+      </member>
+      <member>
+       <name>minimum</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>mxPriority</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>refresh</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>retry</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>ttl</name>
+       <value>
+        <int>86400</int>
+       </value>
+      </member>
+      <member>
+       <name>type</name>
+       <value>
+        <string>ns</string>
+       </value>
+      </member>
+     </struct>
+    </value>
+    <value>
+     <struct>
+      <member>
+       <name>data</name>
+       <value>
+        <string>127.0.0.1</string>
+       </value>
+      </member>
+      <member>
+       <name>domainId</name>
+       <value>
+        <int>123</int>
+       </value>
+      </member>
+      <member>
+       <name>expire</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>host</name>
+       <value>
+        <string>@</string>
+       </value>
+      </member>
+      <member>
+       <name>id</name>
+       <value>
+        <int>50772365</int>
+       </value>
+      </member>
+      <member>
+       <name>minimum</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>mxPriority</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>refresh</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>retry</name>
+       <value>
+        <string/>
+       </value>
+      </member>
+      <member>
+       <name>ttl</name>
+       <value>
+        <int>86400</int>
+       </value>
+      </member>
+      <member>
+       <name>type</name>
+       <value>
+        <string>a</string>
+       </value>
+      </member>
+     </struct>
+    </value>
+   </data>
+  </array>
+ </value>
+</param>
+</params>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/dd7ba77e/libcloud/test/dns/test_softlayer.py
----------------------------------------------------------------------
diff --git a/libcloud/test/dns/test_softlayer.py b/libcloud/test/dns/test_softlayer.py
new file mode 100644
index 0000000..fcb6d4d
--- /dev/null
+++ b/libcloud/test/dns/test_softlayer.py
@@ -0,0 +1,255 @@
+# 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.
+
+import sys
+from libcloud.test import unittest
+
+from libcloud.utils.py3 import httplib
+from libcloud.dns.types import RecordDoesNotExistError
+from libcloud.dns.types import RecordType
+from libcloud.dns.types import ZoneDoesNotExistError
+from libcloud.dns.drivers.softlayer import SoftLayerDNSDriver
+from libcloud.test import MockHttp
+from libcloud.test.file_fixtures import DNSFileFixtures
+from libcloud.test.secrets import SOFTLAYER_PARAMS
+from libcloud.utils.py3 import xmlrpclib
+
+
+class SoftLayerTests(unittest.TestCase):
+
+    def setUp(self):
+        SoftLayerDNSDriver.connectionCls.conn_classes = (
+            SoftLayerDNSMockHttp, SoftLayerDNSMockHttp)
+        SoftLayerDNSMockHttp.type = None
+        self.driver = SoftLayerDNSDriver(*SOFTLAYER_PARAMS)
+
+    def test_create_zone(self):
+        zone = self.driver.create_zone(domain='bar.com')
+        self.assertEqual(zone.id, '123')
+        self.assertEqual(zone.domain, 'bar.com')
+
+    def test_list_zones(self):
+        zones = self.driver.list_zones()
+        self.assertEqual(len(zones), 1)
+
+        zone = zones[0]
+        self.assertEqual(zone.id, '123')
+        self.assertEqual(zone.type, 'master')
+        self.assertEqual(zone.domain, 'bar.com')
+
+    def test_get_zone(self):
+        zone = self.driver.get_zone(zone_id='123')
+        self.assertEqual(zone.id, '123')
+        self.assertEqual(zone.type, 'master')
+        self.assertEqual(zone.domain, 'bar.com')
+
+    def test_get_zone_does_not_exist(self):
+        SoftLayerDNSMockHttp.type = 'ZONE_DOES_NOT_EXIST'
+
+        with self.assertRaises(ZoneDoesNotExistError):
+            self.driver.get_zone(zone_id='333')
+
+    def test_delete_zone(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]
+
+        SoftLayerDNSMockHttp.type = 'ZONE_DOES_NOT_EXIST'
+
+        with self.assertRaises(ZoneDoesNotExistError):
+            self.driver.delete_zone(zone=zone)
+
+    def test_list_records(self):
+        zone = self.driver.list_zones()[0]
+
+        records = zone.list_records()
+
+        self.assertEqual(records[0].id, '50772366')
+        self.assertEqual(records[0].type, RecordType.SOA)
+        self.assertEqual(records[0].data, 'ns1.softlayer.com.')
+        self.assertEqual(
+            records[0].extra,
+            {
+                'mxPriority': '',
+                'expire': 604800,
+                'retry': 300,
+                'refresh': 3600,
+                'ttl': 86400
+            }
+        )
+        self.assertEqual(records[1].id, '50772367')
+        self.assertEqual(records[1].type, RecordType.NS)
+        self.assertEqual(records[1].data, 'ns1.softlayer.com.')
+
+        self.assertEqual(records[2].id, '50772368')
+        self.assertEqual(records[2].type, RecordType.NS)
+        self.assertEqual(records[2].data, 'ns2.softlayer.com.')
+
+        self.assertEqual(records[3].id, '50772365')
+        self.assertEqual(records[3].type, RecordType.A)
+        self.assertEqual(records[3].data, '127.0.0.1')
+
+    def test_list_record_types(self):
+        record_types = self.driver.list_record_types()
+        self.assertEqual(len(record_types), 10)
+        self.assertTrue(RecordType.A in record_types)
+
+    def test_get_record(self):
+        record = self.driver.get_record(zone_id='123', record_id='50772366')
+
+        self.assertEqual(record.id, '50772366')
+        self.assertEqual(record.type, RecordType.SOA)
+        self.assertEqual(record.data, 'ns1.softlayer.com.')
+
+    def test_get_record_record_does_not_exist(self):
+        SoftLayerDNSMockHttp.type = 'RECORD_DOES_NOT_EXIST'
+
+        with self.assertRaises(RecordDoesNotExistError):
+            self.driver.get_record(zone_id='123',
+                                   record_id='1')
+
+    def test_delete_record(self):
+        record = self.driver.get_record(zone_id='123', record_id='50772366')
+        status = self.driver.delete_record(record=record)
+        self.assertTrue(status)
+
+    def test_delete_record_does_not_exist(self):
+        record = self.driver.get_record(zone_id='123', record_id='50772366')
+
+        SoftLayerDNSMockHttp.type = 'RECORD_DOES_NOT_EXIST'
+
+        with self.assertRaises(RecordDoesNotExistError):
+            self.driver.delete_record(record=record)
+
+    def test_create_record(self):
+        zone = self.driver.list_zones()[0]
+        record = self.driver.create_record(
+            name='www', zone=zone,
+            type=RecordType.A, data='127.0.0.1',
+            extra={'ttl': 30}
+        )
+
+        self.assertEqual(record.id, '50772870')
+        self.assertEqual(record.name, 'www')
+        self.assertEqual(record.zone, zone)
+        self.assertEqual(record.type, RecordType.A)
+        self.assertEqual(record.data, '127.0.0.1')
+
+    def test_update_record(self):
+        zone = self.driver.list_zones()[0]
+        record = self.driver.list_records(zone=zone)[1]
+
+        SoftLayerDNSMockHttp.type = 'CHANGED'
+        params = {
+            'record': record,
+            'name': 'www',
+            'type': RecordType.A,
+            'data': '1.1.1.1',
+            'extra': {'ttl': 30}}
+        updated_record = self.driver.update_record(**params)
+
+        self.assertEqual(record.data, 'ns1.softlayer.com.')
+
+        self.assertEqual(updated_record.id, '123')
+        self.assertEqual(updated_record.name, 'www')
+        self.assertEqual(updated_record.zone, record.zone)
+        self.assertEqual(updated_record.type, RecordType.A)
+        self.assertEqual(updated_record.data, '1.1.1.1')
+
+
+class SoftLayerDNSMockHttp(MockHttp):
+    fixtures = DNSFileFixtures('softlayer')
+
+    def _get_method_name(self, type, use_param, qs, path):
+        return "_xmlrpc"
+
+    def _xmlrpc(self, method, url, body, headers):
+        params, meth_name = xmlrpclib.loads(body)
+        url = url.replace("/", "_")
+        meth_name = "%s_%s" % (url, meth_name)
+        return getattr(self, meth_name)(method, url, body, headers)
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_createObject(
+            self, method, url, body, headers):
+        body = self.fixtures.load(
+            'v3_SoftLayer_Dns_Domain_createObject.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_getByDomainName(
+            self, method, url, body, headers):
+        body = self.fixtures.load(
+            'v3_SoftLayer_Dns_Domain_getByDomainName.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_getObject(
+            self, method, url, body, headers):
+        fixture = {
+            None: 'v3_SoftLayer_Dns_Domain_getObject.xml',
+            'ZONE_DOES_NOT_EXIST': 'not_found.xml',
+        }[self.type]
+        body = self.fixtures.load(fixture)
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_deleteObject(
+            self, method, url, body, headers):
+        fixture = {
+            None: 'v3_SoftLayer_Dns_Domain_deleteObject.xml',
+            'ZONE_DOES_NOT_EXIST': 'not_found.xml',
+        }[self.type]
+        body = self.fixtures.load(fixture)
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_getResourceRecords(
+            self, method, url, body, headers):
+        body = self.fixtures.load(
+            'v3_SoftLayer_Dns_Domain_getResourceRecords.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_ResourceRecord_getObject(
+            self, method, url, body, headers):
+        fixture = {
+            None: 'v3_SoftLayer_Dns_Domain_ResourceRecord_getObject.xml',
+            'RECORD_DOES_NOT_EXIST': 'not_found.xml',
+            'CHANGED': 'v3_SoftLayer_Dns_Domain_ResourceRecord_getObject_changed.xml',
+        }[self.type]
+        body = self.fixtures.load(fixture)
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_ResourceRecord_deleteObject(
+            self, method, url, body, headers):
+        fixture = {
+            None: 'v3_SoftLayer_Dns_Domain_ResourceRecord_deleteObject.xml',
+            'RECORD_DOES_NOT_EXIST': 'not_found.xml',
+        }[self.type]
+        body = self.fixtures.load(fixture)
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_ResourceRecord_createObject(
+            self, method, url, body, headers):
+        body = self.fixtures.load(
+            'v3_SoftLayer_Dns_Domain_ResourceRecord_createObject.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _xmlrpc_v3_SoftLayer_Dns_Domain_ResourceRecord_editObject(
+            self, method, url, body, headers):
+        body = self.fixtures.load(
+            'v3_SoftLayer_Dns_Domain_ResourceRecord_editObject.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())


Mime
View raw message