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 2015/08/30 14:32:49 UTC

[01/21] libcloud git commit: Merge pull request #1 from apache/trunk

Repository: libcloud
Updated Branches:
  refs/heads/trunk 61bb1b52e -> 1695d45b1


Merge pull request #1 from apache/trunk

Update fork to apache trunk

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

Branch: refs/heads/trunk
Commit: 9a9fafe7e0391653faac04f368295a7f33013e3c
Parents: 5a9bf7c 59de189
Author: Anthony Shaw <an...@gmail.com>
Authored: Tue Aug 25 07:47:37 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Tue Aug 25 07:47:37 2015 +1000

----------------------------------------------------------------------
 CHANGES.rst                                     |  169 +-
 .../generate_provider_feature_matrix_table.py   |   14 +-
 demos/gce_demo.py                               |  116 +-
 doap_libcloud.rdf                               |    7 +
 .../_static/images/provider_logos/cloudwatt.png |  Bin 0 -> 24813 bytes
 .../images/provider_logos/dimensiondata.png     |  Bin 0 -> 52936 bytes
 docs/_static/images/provider_logos/onapp.png    |  Bin 0 -> 6134 bytes
 docs/_static/images/provider_logos/packet.png   |  Bin 0 -> 41262 bytes
 docs/_static/images/provider_logos/runabove.png |  Bin 0 -> 15052 bytes
 .../_supported_methods_block_storage.rst        |   14 +-
 .../_supported_methods_image_management.rst     |   14 +-
 .../_supported_methods_key_pair_management.rst  |   20 +-
 docs/compute/_supported_methods_main.rst        |   14 +-
 docs/compute/_supported_providers.rst           |   16 +-
 docs/compute/drivers/auroracompute.rst          |   11 +-
 docs/compute/drivers/cloudwatt.rst              |   50 +
 docs/compute/drivers/digital_ocean.rst          |   18 +-
 docs/compute/drivers/dimensiondata.rst          |   54 +
 docs/compute/drivers/gandi.rst                  |   36 +
 docs/compute/drivers/onapp.rst                  |   51 +
 docs/compute/drivers/packet.rst                 |   25 +
 docs/compute/drivers/runabove.rst               |   77 +
 docs/compute/index.rst                          |    4 +-
 docs/dns/_supported_methods.rst                 |    4 +
 docs/dns/_supported_providers.rst               |   32 +-
 docs/dns/drivers/digital_ocean.rst              |   32 +
 docs/examples/compute/cloudwatt/create_node.py  |    9 +
 .../examples/compute/cloudwatt/create_volume.py |    9 +
 .../compute/digitalocean/create_api_v2.0.py     |   18 +
 .../digitalocean/instantiate_api_v2.0.py        |    3 -
 docs/examples/compute/gandi/create_node.py      |   12 +
 docs/examples/compute/onapp/functionality.py    |   61 +
 .../compute/packet/instantiate_api_v1.0.py      |   10 +
 docs/examples/compute/runabove/attach_volume.py |   11 +
 docs/examples/compute/runabove/create_node.py   |   12 +
 .../dns/digitalocean/instantiate_driver.py      |    5 +
 .../softlayer/ex_place_balancer_order.py        |    2 +-
 docs/loadbalancer/_supported_methods.rst        |    2 +
 docs/loadbalancer/_supported_providers.rst      |    2 +
 docs/other/ssl-certificate-validation.rst       |    2 +-
 docs/storage/_supported_methods.rst             |    2 +
 docs/storage/_supported_methods_cdn.rst         |    4 +
 docs/storage/_supported_methods_main.rst        |    4 +
 docs/storage/_supported_providers.rst           |    4 +
 docs/storage/drivers/auroraobjects.rst          |   57 +
 docs/storage/drivers/google_storage.rst         |    4 +-
 docs/storage/supported_providers.rst            |    2 +-
 libcloud/__init__.py                            |    2 +-
 libcloud/common/abiquo.py                       |    7 +-
 libcloud/common/aws.py                          |   15 +-
 libcloud/common/base.py                         |   86 +-
 libcloud/common/cloudstack.py                   |   14 +-
 libcloud/common/digitalocean.py                 |  250 +
 libcloud/common/exceptions.py                   |   75 +
 libcloud/common/gandi.py                        |    8 +-
 libcloud/common/google.py                       |   22 +-
 libcloud/common/onapp.py                        |   48 +
 libcloud/common/openstack.py                    |    6 +-
 libcloud/common/runabove.py                     |  164 +
 libcloud/compute/base.py                        |   14 +-
 libcloud/compute/drivers/__init__.py            |    2 +
 libcloud/compute/drivers/auroracompute.py       |    2 +-
 libcloud/compute/drivers/azure.py               |  303 +-
 libcloud/compute/drivers/cloudframes.py         |    7 +-
 libcloud/compute/drivers/cloudsigma.py          |   11 +-
 libcloud/compute/drivers/cloudstack.py          |  359 +-
 libcloud/compute/drivers/cloudwatt.py           |  154 +
 libcloud/compute/drivers/digitalocean.py        |  401 +-
 libcloud/compute/drivers/dimensiondata.py       |  669 +++
 libcloud/compute/drivers/ec2.py                 |    2 +-
 libcloud/compute/drivers/gandi.py               |  220 +-
 libcloud/compute/drivers/gce.py                 |  307 +-
 libcloud/compute/drivers/onapp.py               |  406 ++
 libcloud/compute/drivers/openstack.py           |   18 +-
 libcloud/compute/drivers/packet.py              |  258 +
 libcloud/compute/drivers/rimuhosting.py         |    6 +-
 libcloud/compute/drivers/runabove.py            |  453 ++
 libcloud/compute/drivers/vultr.py               |   28 +-
 libcloud/compute/providers.py                   |   10 +
 libcloud/compute/ssh.py                         |   71 +-
 libcloud/compute/types.py                       |    7 +
 libcloud/dns/drivers/digitalocean.py            |  292 +
 libcloud/dns/drivers/google.py                  |   36 +
 libcloud/dns/providers.py                       |    2 +
 libcloud/dns/types.py                           |    1 +
 libcloud/storage/drivers/auroraobjects.py       |   52 +
 libcloud/storage/providers.py                   |    2 +
 libcloud/storage/types.py                       |    2 +
 .../digitalocean/_v1_events_12345670.json       |    1 +
 .../_v1_events_12345670_UNAUTHORIZED.json       |    1 +
 .../fixtures/digitalocean/_v2_account.json      |    1 +
 .../digitalocean/_v2_account_UNAUTHORIZED.json  |    1 +
 .../fixtures/digitalocean/_v2_actions.json      |    1 +
 .../digitalocean/_v2_actions_12345670.json      |    1 +
 .../digitalocean/_v2_actions_page_1.json        |    1 +
 .../digitalocean/_v2_actions_page_2.json        |    1 +
 libcloud/test/common/test_digitalocean_v1.py    |   82 +
 libcloud/test/common/test_digitalocean_v2.py    |  104 +
 libcloud/test/common/test_retry_limit.py        |   76 +
 libcloud/test/common/test_runabove.py           |   29 +
 ...18758e6e_services_storageservices_dss123.xml |    1 +
 .../cloudstack/listProjects_default.json        |    4 +-
 ...f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server.xml |    6 +
 ...c_2745_4d8a_9cbc_8dabe5a7d0e4_datacenter.xml |   12 +
 ...8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml |   11 +
 ..._4d8a_9cbc_8dabe5a7d0e4_server_11_delete.xml |    7 +
 ...8dabe5a7d0e4_server_11_delete_INPROGRESS.xml |    7 +
 ...d8a_9cbc_8dabe5a7d0e4_server_11_poweroff.xml |    7 +
 ...abe5a7d0e4_server_11_poweroff_INPROGRESS.xml |    7 +
 ...4d8a_9cbc_8dabe5a7d0e4_server_11_restart.xml |    6 +
 ...dabe5a7d0e4_server_11_restart_INPROGRESS.xml |    7 +
 ...d8a_9cbc_8dabe5a7d0e4_server_11_shutdown.xml |    6 +
 ...abe5a7d0e4_server_11_shutdown_INPROGRESS.xml |    7 +
 ...5_4d8a_9cbc_8dabe5a7d0e4_server_11_start.xml |    7 +
 ..._8dabe5a7d0e4_server_11_start_INPROGRESS.xml |    7 +
 ...5_4d8a_9cbc_8dabe5a7d0e4_server_deployed.xml |   46 +
 ...a_9cbc_8dabe5a7d0e4_server_pendingDeploy.xml |   26 +
 .../dimensiondata/oec_0_9_base_image.xml        |  339 ++
 .../dimensiondata/oec_0_9_myaccount.xml         |   26 +
 .../test/compute/fixtures/gandi/ssh_delete.xml  |    8 +
 .../test/compute/fixtures/gandi/ssh_info.xml    |   25 +
 .../test/compute/fixtures/gandi/ssh_list.xml    |   23 +
 .../compute/fixtures/gce/regions-paged-1.json   |   97 +
 .../compute/fixtures/gce/regions-paged-2.json   |   52 +
 libcloud/test/compute/fixtures/gce/zones.json   |   12 +-
 .../compute/fixtures/onapp/create_node.json     |   87 +
 .../test/compute/fixtures/onapp/list_nodes.json |   89 +
 .../openstack_v1.1/_servers_detail.json         |    8 +
 .../compute/fixtures/packet/device_create.json  |   74 +
 .../test/compute/fixtures/packet/devices.json   |   57 +
 .../compute/fixtures/packet/facilities.json     |   12 +
 .../fixtures/packet/operatingsystems.json       |   28 +
 .../test/compute/fixtures/packet/plans.json     |   21 +
 .../compute/fixtures/packet/sshkey_create.json  |   10 +
 .../test/compute/fixtures/packet/sshkeys.json   |   34 +
 .../fixtures/runabove/auth_time_get.json        |    1 +
 .../compute/fixtures/runabove/flavor_get.json   |    1 +
 .../fixtures/runabove/flavor_get_detail.json    |    1 +
 .../compute/fixtures/runabove/image_get.json    |    1 +
 .../fixtures/runabove/image_get_detail.json     |    1 +
 .../compute/fixtures/runabove/instance_get.json |    1 +
 .../fixtures/runabove/instance_get_detail.json  |    1 +
 .../fixtures/runabove/instance_post.json        |    1 +
 .../compute/fixtures/runabove/region_get.json   |    1 +
 .../test/compute/fixtures/runabove/ssh_get.json |    2 +
 .../fixtures/runabove/ssh_get_detail.json       |    1 +
 .../compute/fixtures/runabove/volume_get.json   |    1 +
 .../fixtures/runabove/volume_get_detail.json    |    1 +
 libcloud/test/compute/test_azure.py             |   35 +
 libcloud/test/compute/test_cloudstack.py        |   17 +
 libcloud/test/compute/test_digitalocean_v1.py   |   24 +-
 libcloud/test/compute/test_digitalocean_v2.py   |   14 +-
 libcloud/test/compute/test_dimensiondata.py     |  251 +
 libcloud/test/compute/test_gandi.py             |   41 +
 libcloud/test/compute/test_gce.py               |  105 +-
 libcloud/test/compute/test_onapp.py             |   94 +
 libcloud/test/compute/test_openstack.py         |    7 +-
 libcloud/test/compute/test_packet.py            |  184 +
 libcloud/test/compute/test_runabove.py          |  201 +
 libcloud/test/compute/test_ssh_client.py        |    6 +-
 .../dns/fixtures/digitalocean/_v2_domains.json  |    1 +
 .../digitalocean/_v2_domains_CREATE.json        |    1 +
 .../digitalocean/_v2_domains_EMPTY.json         |    1 +
 .../digitalocean/_v2_domains_UNAUTHORIZED.json  |    1 +
 .../digitalocean/_v2_domains_testdomain.json    |    1 +
 .../_v2_domains_testdomain_NOT_FOUND.json       |    1 +
 .../_v2_domains_testdomain_records.json         |    1 +
 .../_v2_domains_testdomain_records_1234560.json |    1 +
 .../_v2_domains_testdomain_records_1234561.json |    1 +
 .../_v2_domains_testdomain_records_1234562.json |    1 +
 .../_v2_domains_testdomain_records_1234564.json |    1 +
 ...ns_testdomain_records_1234564_NOT_FOUND.json |    1 +
 ...mains_testdomain_records_1234564_UPDATE.json |    1 +
 .../_v2_domains_testdomain_records_CREATE.json  |    1 +
 .../dns/fixtures/google/record_changes.json     |   28 +
 libcloud/test/dns/test_digitalocean.py          |  211 +
 libcloud/test/dns/test_google.py                |   15 +
 libcloud/test/file_fixtures.py                  |    1 +
 ...3__SoftLayer_Account_getAdcLoadBalancers.xml |  802 +++
 ...v3__SoftLayer_Billing_Item_cancelService.xml |    8 +
 ...Layer_Location_Datacenter_getDatacenters.xml |  683 +++
 ...roller_LoadBalancer_Service_deleteObject.xml |    8 +
 ...LoadBalancer_VirtualIpAddress_editObject.xml |    8 +
 ...Balancer_VirtualIpAddress_getBillingItem.xml |  147 +
 ..._LoadBalancer_VirtualIpAddress_getObject.xml |  803 +++
 ..._Network_Subnet_IpAddress_getByIpAddress.xml |  148 +
 .../v3__SoftLayer_Product_Order_placeOrder.xml  |  709 +++
 .../v3__SoftLayer_Product_Package_getItems.xml  | 5448 ++++++++++++++++++
 libcloud/test/loadbalancer/test_softlayer.py    |  190 +
 libcloud/test/secrets.py-dist                   |    4 +
 libcloud/test/test_connection.py                |   58 +-
 libcloud/utils/misc.py                          |   57 +
 libcloud/utils/networking.py                    |   13 +-
 requirements-tests.txt                          |    1 +
 setup.py                                        |    4 +-
 tox.ini                                         |   18 +-
 196 files changed, 17161 insertions(+), 490 deletions(-)
----------------------------------------------------------------------



[08/21] libcloud git commit: [LIBCLOUD-737] Created function for creating a node.

Posted by to...@apache.org.
[LIBCLOUD-737] Created function for creating a node.


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

Branch: refs/heads/trunk
Commit: b4ed5ea6701eacdc3688527a53dbc86a7a451a6c
Parents: b90c561
Author: Anthony Shaw <an...@gmail.com>
Authored: Wed Aug 26 19:48:31 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Wed Aug 26 19:48:31 2015 +1000

----------------------------------------------------------------------
 libcloud/loadbalancer/drivers/dimensiondata.py | 30 ++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/b4ed5ea6/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index d294a9a..e44b77e 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -83,9 +83,13 @@ class DimensionDataLBDriver(Driver):
         kwargs['region'] = self.selected_region
         return kwargs
 
+    def create_balancer(self, name, port, protocol, algorithm, members):
+        
+        return True
+
     def list_balancers(self):
         """
-        List all loadbalancers inside a gepgraphy.
+        List all loadbalancers inside a geography.
         
         In Dimension Data terminology these are known as virtual listeners
 
@@ -150,12 +154,36 @@ class DimensionDataLBDriver(Driver):
     def balancer_attach_member(self, balancer, member):
         return True
 
+    def balancer_attach_compute_node(self, balancer, node):
+        return True
+
     def balancer_detach_member(self, balancer, member):
         return True
 
     def destroy_balancer(self, balancer):
         return True
 
+    def ex_create_node(self,
+                       network_domain_id,
+                       name,
+                       ip,
+                       ex_description,
+                       connectionLimit=25000,
+                       connectionRateLimit=2000):
+        create_node_elm = ET.Element('createNode', {'xmlns': SERVER_NS})
+        ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
+        ET.SubElement(create_node_elm, "description").text = ex_description
+        ET.SubElement(create_node_elm, "name").text = name
+        ET.SubElement(create_node_elm, "ipv4Address").text = ip
+        ET.SubElement(create_node_elm, "connectionLimit").text = connectionLimit
+        ET.SubElement(create_node_elm, "connectionRateLimit").text = connectionRateLimit
+
+        self.connection.request_with_orgId_api_2(
+            'networkDomainVip/createNode',
+            method='POST',
+            data=ET.tostring(create_node_elm)).object
+        return True
+
     def ex_get_pools(self):
         pools = self.connection \
             .request_with_orgId_api_2('networkDomainVip/pool').object


[12/21] libcloud git commit: [LIBCLOUD-737] Fixup namespaces.

Posted by to...@apache.org.
[LIBCLOUD-737] Fixup namespaces.


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

Branch: refs/heads/trunk
Commit: 93d88c30bb78b948c676c490a79bac840097c8be
Parents: 2d2fbc0
Author: Anthony Shaw <an...@gmail.com>
Authored: Fri Aug 28 11:12:46 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Fri Aug 28 11:12:46 2015 +1000

----------------------------------------------------------------------
 libcloud/loadbalancer/drivers/dimensiondata.py | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/93d88c30/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index 2d7daaf..836d5aa 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -26,7 +26,6 @@ from libcloud.common.dimensiondata import DimensionDataVIPNode
 from libcloud.common.dimensiondata import API_ENDPOINTS
 from libcloud.common.dimensiondata import DEFAULT_REGION
 from libcloud.common.dimensiondata import TYPES_URN
-from libcloud.common.dimensiondata import SERVER_NS
 from libcloud.utils.misc import reverse_dict
 from libcloud.utils.xml import fixxpath, findtext, findall
 from libcloud.loadbalancer.types import State
@@ -259,7 +258,7 @@ class DimensionDataLBDriver(Driver):
         :return: ``True`` if member detach was successful, otherwise ``False``.
         :rtype: ``bool``
         """
-        create_pool_m = ET.Element('removePoolMember', {'xmlns': SERVER_NS,
+        create_pool_m = ET.Element('removePoolMember', {'xmlns': TYPES_URN,
                                                         'id': member.id})
 
         result = self.connection.request_with_orgId_api_2(
@@ -280,7 +279,7 @@ class DimensionDataLBDriver(Driver):
         :rtype: ``bool``
         """
         delete_listener = ET.Element('deleteVirtualListener',
-                                     {'xmlns': SERVER_NS,
+                                     {'xmlns': TYPES_URN,
                                       'id': balancer.id})
 
         result = self.connection.request_with_orgId_api_2(
@@ -324,7 +323,7 @@ class DimensionDataLBDriver(Driver):
         :return: The node member, instance of ``DimensionDataPoolMember``
         :rtype: ``DimensionDataPoolMember``
         """
-        create_pool_m = ET.Element('addPoolMember', {'xmlns': SERVER_NS})
+        create_pool_m = ET.Element('addPoolMember', {'xmlns': TYPES_URN})
         ET.SubElement(create_pool_m, "poolId").text = pool.id
         ET.SubElement(create_pool_m, "nodeId").text = node.id
         ET.SubElement(create_pool_m, "port").text = str(port)
@@ -382,7 +381,7 @@ class DimensionDataLBDriver(Driver):
         :return: Instance of ``DimensionDataVIPNode``
         :rtype: ``DimensionDataVIPNode``
         """
-        create_node_elm = ET.Element('createNode', {'xmlns': SERVER_NS})
+        create_node_elm = ET.Element('createNode', {'xmlns': TYPES_URN})
         ET.SubElement(create_node_elm, "networkDomainId") \
             .text = network_domain_id
         ET.SubElement(create_node_elm, "description").text = ex_description
@@ -444,20 +443,20 @@ class DimensionDataLBDriver(Driver):
         :return: Instance of ``DimensionDataPool``
         :rtype: ``DimensionDataPool``
         """
-        create_node_elm = ET.Element('createPool', {'xmlns': SERVER_NS})
+        create_node_elm = ET.Element('createPool', {'xmlns': TYPES_URN})
         ET.SubElement(create_node_elm, "networkDomainId") \
             .text = network_domain_id
-        ET.SubElement(create_node_elm, "description").text = ex_description
+        ET.SubElement(create_node_elm, "description").text = str(ex_description)
         ET.SubElement(create_node_elm, "name").text = name
         ET.SubElement(create_node_elm, "loadBalancerMethod") \
-            .text = balancer_method
+            .text = str(balancer_method)
         ET.SubElement(create_node_elm, "serviceDownAction") \
             .text = service_down_action
         ET.SubElement(create_node_elm, "slowRampTime").text \
             = str(slow_ramp_time)
 
         response = self.connection.request_with_orgId_api_2(
-            'networkDomainVip/createPool',
+            action='networkDomainVip/createPool',
             method='POST',
             data=ET.tostring(create_node_elm)).object
 
@@ -521,7 +520,7 @@ class DimensionDataLBDriver(Driver):
         :rtype: ``DimensionDataVirtualListener``
         """
         create_node_elm = ET.Element('createVirtualListener',
-                                     {'xmlns': SERVER_NS})
+                                     {'xmlns': TYPES_URN})
         ET.SubElement(create_node_elm, "networkDomainId") \
             .text = network_domain_id
         ET.SubElement(create_node_elm, "description").text = ex_description


[13/21] libcloud git commit: [LIBCLOUD-737] Updated against testing using north america datacenters. added ability to delete nodes, vips and pools.

Posted by to...@apache.org.
[LIBCLOUD-737] Updated against testing using north america datacenters. added ability to delete nodes, vips and pools.


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

Branch: refs/heads/trunk
Commit: 0b8ef57796d5623c8e7c3b7b3891688ba756cdf0
Parents: 93d88c3
Author: Anthony Shaw <an...@gmail.com>
Authored: Fri Aug 28 14:19:36 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Fri Aug 28 14:19:36 2015 +1000

----------------------------------------------------------------------
 libcloud/common/dimensiondata.py                |  22 +++-
 libcloud/loadbalancer/drivers/dimensiondata.py  | 129 ++++++++++++++++---
 .../test/loadbalancer/test_dimensiondata.py     |   8 +-
 3 files changed, 132 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/0b8ef577/libcloud/common/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/common/dimensiondata.py b/libcloud/common/dimensiondata.py
index a6db06e..85ca6c8 100644
--- a/libcloud/common/dimensiondata.py
+++ b/libcloud/common/dimensiondata.py
@@ -89,12 +89,19 @@ class DimensionDataResponse(XmlResponse):
 
         body = self.parse_body()
 
-        # TODO: The path is not fixed as server.
         if self.status == httplib.BAD_REQUEST:
             code = findtext(body, 'responseCode', SERVER_NS)
+            if code is None:
+                code = findtext(body, 'responseCode', TYPES_URN)
             message = findtext(body, 'message', SERVER_NS)
-            raise DimensionDataAPIException(code,
-                                            message,
+            if message is None:
+                message = findtext(body, 'message', TYPES_URN)
+            raise DimensionDataAPIException(code=code,
+                                            msg=message,
+                                            driver=self.connection.driver)
+        if self.status is not httplib.OK:
+            raise DimensionDataAPIException(code=self.status,
+                                            msg=body,
                                             driver=self.connection.driver)
 
         return self.body
@@ -146,6 +153,7 @@ class DimensionDataConnection(ConnectionUserAndKey):
         headers['Authorization'] = \
             ('Basic %s' % b64encode(b('%s:%s' % (self.user_id,
                                                  self.key))).decode('utf-8'))
+        headers['Content-Type'] = 'application/xml'
         return headers
 
     def request_api_1(self, action, params=None, data='',
@@ -330,18 +338,20 @@ class DimensionDataPoolMember(object):
     DimensionData VIP Pool Member.
     """
 
-    def __init__(self, id, name, status, ip, port):
+    def __init__(self, id, name, status, ip, port, node_id):
         self.id = str(id)
         self.name = name
         self.status = status
         self.ip = ip
         self.port = port
+        self.node_id = node_id
 
     def __repr__(self):
         return (('<DimensionDataPool: id=%s, name=%s, '
-                 'ip=%s, status=%s, port=%s>')
+                 'ip=%s, status=%s, port=%s, node_id=%s')
                 % (self.id, self.name,
-                   self.ip, self.status, self.port))
+                   self.ip, self.status, self.port,
+                   self.node_id))
 
 
 class DimensionDataVIPNode(object):

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0b8ef577/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index 836d5aa..729c1bc 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -138,8 +138,9 @@ class DimensionDataLBDriver(Driver):
         listener = self.ex_create_virtual_listener(
             network_domain_id=network_domain_id,
             name=name,
-            ex_description=None,
-            port=port)
+            ex_description=name,
+            port=port,
+            pool=pool)
 
         return LoadBalancer(
             id=listener.id,
@@ -326,7 +327,7 @@ class DimensionDataLBDriver(Driver):
         create_pool_m = ET.Element('addPoolMember', {'xmlns': TYPES_URN})
         ET.SubElement(create_pool_m, "poolId").text = pool.id
         ET.SubElement(create_pool_m, "nodeId").text = node.id
-        ET.SubElement(create_pool_m, "port").text = str(port)
+        ET.SubElement(create_pool_m, "status").text = 'ENABLED'
 
         response = self.connection.request_with_orgId_api_2(
             'networkDomainVip/addPoolMember',
@@ -346,7 +347,8 @@ class DimensionDataLBDriver(Driver):
             name=node_name,
             status=State.RUNNING,
             ip=node.ip,
-            port=port
+            port=port,
+            node_id=node.id
         )
 
     def ex_create_node(self,
@@ -384,16 +386,18 @@ class DimensionDataLBDriver(Driver):
         create_node_elm = ET.Element('createNode', {'xmlns': TYPES_URN})
         ET.SubElement(create_node_elm, "networkDomainId") \
             .text = network_domain_id
-        ET.SubElement(create_node_elm, "description").text = ex_description
         ET.SubElement(create_node_elm, "name").text = name
+        ET.SubElement(create_node_elm, "description").text \
+            = str(ex_description)
         ET.SubElement(create_node_elm, "ipv4Address").text = ip
+        ET.SubElement(create_node_elm, "status").text = 'ENABLED'
         ET.SubElement(create_node_elm, "connectionLimit") \
             .text = str(connection_limit)
         ET.SubElement(create_node_elm, "connectionRateLimit") \
             .text = str(connection_rate_limit)
 
         response = self.connection.request_with_orgId_api_2(
-            'networkDomainVip/createNode',
+            action='networkDomainVip/createNode',
             method='POST',
             data=ET.tostring(create_node_elm)).object
 
@@ -443,12 +447,15 @@ class DimensionDataLBDriver(Driver):
         :return: Instance of ``DimensionDataPool``
         :rtype: ``DimensionDataPool``
         """
+        # Names cannot contain spaces.
+        name.replace(' ', '_')
         create_node_elm = ET.Element('createPool', {'xmlns': TYPES_URN})
         ET.SubElement(create_node_elm, "networkDomainId") \
             .text = network_domain_id
-        ET.SubElement(create_node_elm, "description").text = str(ex_description)
         ET.SubElement(create_node_elm, "name").text = name
-        ET.SubElement(create_node_elm, "loadBalancerMethod") \
+        ET.SubElement(create_node_elm, "description").text \
+            = str(ex_description)
+        ET.SubElement(create_node_elm, "loadBalanceMethod") \
             .text = str(balancer_method)
         ET.SubElement(create_node_elm, "serviceDownAction") \
             .text = service_down_action
@@ -477,8 +484,8 @@ class DimensionDataLBDriver(Driver):
                                    name,
                                    ex_description,
                                    port,
-                                   listener_type='STANDARD',
-                                   protocol='ANY',
+                                   pool,
+                                   protocol='TCP',
                                    connection_limit=25000,
                                    connection_rate_limit=2000,
                                    source_port_preservation='PRESERVE'):
@@ -519,27 +526,35 @@ class DimensionDataLBDriver(Driver):
         :return: Instance of the listener
         :rtype: ``DimensionDataVirtualListener``
         """
+        if port is 80 or 443:
+            listener_type = 'PERFORMANCE_LAYER_4'
+            protocol = 'HTTP'
+        else:
+            listener_type = 'STANDARD'
+
         create_node_elm = ET.Element('createVirtualListener',
                                      {'xmlns': TYPES_URN})
         ET.SubElement(create_node_elm, "networkDomainId") \
             .text = network_domain_id
-        ET.SubElement(create_node_elm, "description").text = ex_description
         ET.SubElement(create_node_elm, "name").text = name
-        ET.SubElement(create_node_elm, "port").text = str(port)
+        ET.SubElement(create_node_elm, "description").text = \
+            str(ex_description)
         ET.SubElement(create_node_elm, "type").text = listener_type
+        ET.SubElement(create_node_elm, "protocol") \
+            .text = protocol
+        ET.SubElement(create_node_elm, "port").text = str(port)
+        ET.SubElement(create_node_elm, "enabled").text = 'true'
         ET.SubElement(create_node_elm, "connectionLimit") \
             .text = str(connection_limit)
         ET.SubElement(create_node_elm, "connectionRateLimit") \
             .text = str(connection_rate_limit)
         ET.SubElement(create_node_elm, "sourcePortPreservation") \
             .text = source_port_preservation
-
-        if protocol != 'ANY':
-            ET.SubElement(create_node_elm, "protocol") \
-                .text = protocol
+        ET.SubElement(create_node_elm, "poolId") \
+            .text = pool.id
 
         response = self.connection.request_with_orgId_api_2(
-            'networkDomainVip/createVirtualListener',
+            action='networkDomainVip/createVirtualListener',
             method='POST',
             data=ET.tostring(create_node_elm)).object
 
@@ -569,6 +584,18 @@ class DimensionDataLBDriver(Driver):
                                       % pool_id).object
         return self._to_pool(pool)
 
+    def ex_destroy_pool(self, pool):
+        destroy_request = ET.Element('deletePool',
+                                     {'xmlns': TYPES_URN,
+                                      'id': pool.id})
+
+        result = self.connection.request_with_orgId_api_2(
+            action='networkDomainVip/deletePool',
+            method='POST',
+            data=ET.tostring(destroy_request)).object
+        responseCode = findtext(result, 'responseCode', TYPES_URN)
+        return responseCode == 'OK'
+
     def ex_get_pool_members(self, pool_id):
         members = self.connection \
             .request_with_orgId_api_2('networkDomainVip/poolMember?poolId=%s'
@@ -581,6 +608,62 @@ class DimensionDataLBDriver(Driver):
                                       % pool_member_id).object
         return self._to_member(member)
 
+    def ex_destroy_pool_member(self, member, destroy_node=False):
+        # remove the pool member
+        destroy_request = ET.Element('removePoolMember',
+                                     {'xmlns': TYPES_URN,
+                                      'id': member.id})
+
+        self.connection.request_with_orgId_api_2(
+            action='networkDomainVip/removePoolMember',
+            method='POST',
+            data=ET.tostring(destroy_request)).object
+
+        if member.node_id is not None and destroy_node is True:
+            self.ex_destroy_node(member.node_id)
+
+    def ex_get_nodes(self):
+        nodes = self.connection \
+            .request_with_orgId_api_2('networkDomainVip/node').object
+        return self._to_nodes(nodes)
+
+    def ex_destroy_node(self, node_id):
+        # Destroy the node
+        destroy_request = ET.Element('deleteNode',
+                                     {'xmlns': TYPES_URN,
+                                      'id': node_id})
+
+        result = self.connection.request_with_orgId_api_2(
+            action='networkDomainVip/deleteNode',
+            method='POST',
+            data=ET.tostring(destroy_request)).object
+        responseCode = findtext(result, 'responseCode', TYPES_URN)
+        return responseCode == 'OK'
+
+    def _to_nodes(self, object):
+        nodes = []
+        for element in object.findall(fixxpath("node", TYPES_URN)):
+            nodes.append(self._to_node(element))
+
+        return nodes
+
+    def _to_node(self, element):
+        ipaddress = findtext(element, 'ipv4Address', TYPES_URN)
+        if ipaddress is None:
+            ipaddress = findtext(element, 'ipv6Address', TYPES_URN)
+
+        name = findtext(element, 'name', TYPES_URN)
+
+        node = DimensionDataVIPNode(
+            id=element.get('id'),
+            name=name,
+            status=self._VALUE_TO_STATE_MAP.get(
+                findtext(element, 'state', TYPES_URN),
+                State.UNKNOWN),
+            ip=ipaddress)
+
+        return node
+
     def _to_balancers(self, object):
         loadbalancers = []
         for element in object.findall(fixxpath("virtualListener", TYPES_URN)):
@@ -622,18 +705,24 @@ class DimensionDataLBDriver(Driver):
         return members
 
     def _to_member(self, element):
-        pool = DimensionDataPoolMember(
+        port = findtext(element, 'port', TYPES_URN)
+        if port is not None:
+            port = int(port)
+        pool_member = DimensionDataPoolMember(
             id=element.get('id'),
             name=element.find(fixxpath(
                 'node',
                 TYPES_URN)).get('name'),
             status=findtext(element, 'state', TYPES_URN),
+            node_id=element.find(fixxpath(
+                'node',
+                TYPES_URN)).get('id'),
             ip=element.find(fixxpath(
                 'node',
                 TYPES_URN)).get('ipAddress'),
-            port=int(findtext(element, 'port', TYPES_URN))
+            port=port
         )
-        return pool
+        return pool_member
 
     def _to_pools(self, object):
         pools = []

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0b8ef577/libcloud/test/loadbalancer/test_dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/test_dimensiondata.py b/libcloud/test/loadbalancer/test_dimensiondata.py
index d9529f3..e855415 100644
--- a/libcloud/test/loadbalancer/test_dimensiondata.py
+++ b/libcloud/test/loadbalancer/test_dimensiondata.py
@@ -204,7 +204,13 @@ class DimensionDataTests(unittest.TestCase):
             network_domain_id='12345',
             name='test',
             ex_description='test',
-            port=80)
+            port=80,
+            pool=DimensionDataPool(
+                id='1234',
+                name='test',
+                description='test',
+                status=State.RUNNING
+            ))
         self.assertEqual(listener.id, '8334f461-0df0-42d5-97eb-f4678eb26bea')
         self.assertEqual(listener.name, 'test')
 


[20/21] libcloud git commit: Update changelog.

Posted by to...@apache.org.
Update changelog.

Closes #567


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

Branch: refs/heads/trunk
Commit: c382e456daf15eb79a76121d486d069cfb901d82
Parents: 8c31ebd
Author: Tomaz Muraus <to...@apache.org>
Authored: Sun Aug 30 14:26:25 2015 +0200
Committer: Tomaz Muraus <to...@apache.org>
Committed: Sun Aug 30 14:26:25 2015 +0200

----------------------------------------------------------------------
 CHANGES.rst | 8 ++++++++
 1 file changed, 8 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/c382e456/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 2d22a62..222511b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -46,6 +46,14 @@ Storage
   (LIBCLOUD-725, GITHUB-568)
   [Torf]
 
+Loadbalancer
+~~~~~~~~~~~~
+
+- Add a new driver for DimensionData load-balancing service
+  (http://cloud.dimensiondata.com/).
+  (LIBCLOUD-737, GITHUB-567)
+  [Anthony Shaw]
+
 DNS
 ~~~
 


[11/21] libcloud git commit: [LIBCLOUD-737] Updated docs.

Posted by to...@apache.org.
[LIBCLOUD-737] Updated docs.


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

Branch: refs/heads/trunk
Commit: 2d2fbc064ab0bb09f06aa12eeadaf78d98cf1165
Parents: 84938fa
Author: Anthony Shaw <an...@gmail.com>
Authored: Fri Aug 28 09:59:58 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Fri Aug 28 09:59:58 2015 +1000

----------------------------------------------------------------------
 docs/loadbalancer/_supported_methods.rst   |  4 +++-
 docs/loadbalancer/_supported_providers.rst | 30 +++++++++++++------------
 2 files changed, 19 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/2d2fbc06/docs/loadbalancer/_supported_methods.rst
----------------------------------------------------------------------
diff --git a/docs/loadbalancer/_supported_methods.rst b/docs/loadbalancer/_supported_methods.rst
index f129af9..c9a2d8e 100644
--- a/docs/loadbalancer/_supported_methods.rst
+++ b/docs/loadbalancer/_supported_methods.rst
@@ -4,7 +4,8 @@
 Provider                               create balancer list balancers list members attach member detach member attach compute node
 ====================================== =============== ============== ============ ============= ============= ===================
 `Brightbox`_                           yes             yes            yes          yes           yes           yes                
-`CloudStack`_                          yes             yes            yes          yes           yes           no                 
+`CloudStack`_                          yes             yes            yes          yes           yes           no
+`Dimension Data`_                      yes             yes            yes          yes           yes           yes 
 `Amazon Elastic Load Balancing`_       yes             yes            yes          no            yes           yes                
 `Google Compute Engine Load Balancer`_ yes             yes            yes          yes           yes           yes                
 `GoGrid LB`_                           yes             yes            yes          yes           yes           no                 
@@ -17,6 +18,7 @@ Provider                               create balancer list balancers list membe
 
 .. _`Brightbox`: http://www.brightbox.co.uk/
 .. _`CloudStack`: http://cloudstack.org/
+.. _`Dimension Data`: http://cloud.dimensiondata.com/
 .. _`Amazon Elastic Load Balancing`: http://aws.amazon.com/elasticloadbalancing/
 .. _`Google Compute Engine Load Balancer`: https://cloud.google.com/
 .. _`GoGrid LB`: http://www.gogrid.com/

http://git-wip-us.apache.org/repos/asf/libcloud/blob/2d2fbc06/docs/loadbalancer/_supported_providers.rst
----------------------------------------------------------------------
diff --git a/docs/loadbalancer/_supported_providers.rst b/docs/loadbalancer/_supported_providers.rst
index a4e00da..a86d587 100644
--- a/docs/loadbalancer/_supported_providers.rst
+++ b/docs/loadbalancer/_supported_providers.rst
@@ -1,22 +1,24 @@
 .. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
 
-====================================== ======================================== ================= =============================================== ============================
-Provider                               Documentation                            Provider constant Module                                          Class Name                  
-====================================== ======================================== ================= =============================================== ============================
-`Brightbox`_                                                                    BRIGHTBOX         :mod:`libcloud.loadbalancer.drivers.brightbox`  :class:`BrightboxLBDriver`  
-`CloudStack`_                                                                   CLOUDSTACK        :mod:`libcloud.loadbalancer.drivers.cloudstack` :class:`CloudStackLBDriver` 
-`Amazon Elastic Load Balancing`_       :doc:`Click </loadbalancer/drivers/elb>` ELB               :mod:`libcloud.loadbalancer.drivers.elb`        :class:`ElasticLBDriver`    
-`Google Compute Engine Load Balancer`_ :doc:`Click </loadbalancer/drivers/gce>` GCE               :mod:`libcloud.loadbalancer.drivers.gce`        :class:`GCELBDriver`        
-`GoGrid LB`_                                                                    GOGRID            :mod:`libcloud.loadbalancer.drivers.gogrid`     :class:`GoGridLBDriver`     
-`Ninefold LB`_                                                                  NINEFOLD          :mod:`libcloud.loadbalancer.drivers.ninefold`   :class:`NinefoldLBDriver`   
-`Rackspace LB`_                                                                 RACKSPACE         :mod:`libcloud.loadbalancer.drivers.rackspace`  :class:`RackspaceLBDriver`  
-`Rackspace LB`_                                                                 RACKSPACE_UK      :mod:`libcloud.loadbalancer.drivers.rackspace`  :class:`RackspaceUKLBDriver`
-`Rackspace LB`_                                                                 RACKSPACE_US      :mod:`libcloud.loadbalancer.drivers.rackspace`  :class:`RackspaceLBDriver`  
-`Softlayer Load Balancing`_                                                     SOFTLAYER         :mod:`libcloud.loadbalancer.drivers.softlayer`  :class:`SoftlayerLBDriver`  
-====================================== ======================================== ================= =============================================== ============================
+====================================== ======================================== ================= ================================================== ============================
+Provider                               Documentation                            Provider constant Module                                             Class Name                  
+====================================== ======================================== ================= ================================================== ============================
+`Brightbox`_                                                                    BRIGHTBOX         :mod:`libcloud.loadbalancer.drivers.brightbox`     :class:`BrightboxLBDriver`  
+`CloudStack`_                                                                   CLOUDSTACK        :mod:`libcloud.loadbalancer.drivers.cloudstack`    :class:`CloudStackLBDriver`
+`Dimension Data`                                                                DIMENSIONDATA     :mod:`libcloud.loadbalancer.drivers.dimensiondata` :class:`DimensionDataLBDriver`
+`Amazon Elastic Load Balancing`_       :doc:`Click </loadbalancer/drivers/elb>` ELB               :mod:`libcloud.loadbalancer.drivers.elb`           :class:`ElasticLBDriver`    
+`Google Compute Engine Load Balancer`_ :doc:`Click </loadbalancer/drivers/gce>` GCE               :mod:`libcloud.loadbalancer.drivers.gce`           :class:`GCELBDriver`        
+`GoGrid LB`_                                                                    GOGRID            :mod:`libcloud.loadbalancer.drivers.gogrid`        :class:`GoGridLBDriver`     
+`Ninefold LB`_                                                                  NINEFOLD          :mod:`libcloud.loadbalancer.drivers.ninefold`      :class:`NinefoldLBDriver`   
+`Rackspace LB`_                                                                 RACKSPACE         :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceLBDriver`  
+`Rackspace LB`_                                                                 RACKSPACE_UK      :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceUKLBDriver`
+`Rackspace LB`_                                                                 RACKSPACE_US      :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceLBDriver`  
+`Softlayer Load Balancing`_                                                     SOFTLAYER         :mod:`libcloud.loadbalancer.drivers.softlayer`     :class:`SoftlayerLBDriver`  
+====================================== ======================================== ================= ================================================== ============================
 
 .. _`Brightbox`: http://www.brightbox.co.uk/
 .. _`CloudStack`: http://cloudstack.org/
+.. _`Dimension Data`: http://cloud.dimensiondata.com/
 .. _`Amazon Elastic Load Balancing`: http://aws.amazon.com/elasticloadbalancing/
 .. _`Google Compute Engine Load Balancer`: https://cloud.google.com/
 .. _`GoGrid LB`: http://www.gogrid.com/


[06/21] libcloud git commit: [LIBCLOUD-736] Fixed up whitespace in empty lines inside the unit tests

Posted by to...@apache.org.
[LIBCLOUD-736] Fixed up whitespace in empty lines inside the unit tests


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

Branch: refs/heads/trunk
Commit: fbd02daadec0133db9ef50461373af6a6372b5fc
Parents: 8e062c0
Author: Anthony Shaw <an...@gmail.com>
Authored: Tue Aug 25 17:03:26 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Tue Aug 25 17:03:26 2015 +1000

----------------------------------------------------------------------
 libcloud/test/compute/test_dimensiondata.py | 42 +++++++++++-------------
 1 file changed, 20 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/fbd02daa/libcloud/test/compute/test_dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_dimensiondata.py b/libcloud/test/compute/test_dimensiondata.py
index d6c4dba..c37ab44 100644
--- a/libcloud/test/compute/test_dimensiondata.py
+++ b/libcloud/test/compute/test_dimensiondata.py
@@ -20,7 +20,6 @@ from libcloud.common.types import InvalidCredsError
 from libcloud.compute.drivers.dimensiondata import DimensionDataNodeDriver as DimensionData
 from libcloud.compute.drivers.dimensiondata import DimensionDataAPIException
 from libcloud.compute.base import Node, NodeAuthPassword, NodeLocation
-from libcloud.compute.types import NodeState
 
 from libcloud.test import MockHttp
 from libcloud.test.compute import TestCaseMixin
@@ -53,13 +52,12 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin):
         self.assertEqual(first_node.id, 'NA10')
         self.assertEqual(first_node.name, 'US - West')
         self.assertEqual(first_node.country, 'US')
-        
+
     def test_list_nodes_response(self):
         DimensionDataMockHttp.type = None
         ret = self.driver.list_nodes()
         self.assertEqual(len(ret), 2)
-        first_node = ret[0]
-        
+
     def test_list_sizes_response(self):
         DimensionDataMockHttp.type = None
         ret = self.driver.list_sizes()
@@ -172,7 +170,7 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin):
         nets = self.driver.ex_list_networks()
         self.assertEqual(nets[0].name, 'test-net1')
         self.assertTrue(isinstance(nets[0].location, NodeLocation))
-        
+
     def test_ex_list_network_domains(self):
         nets = self.driver.ex_list_network_domains()
         self.assertEqual(nets[0].name, 'Production Network Domain')
@@ -181,7 +179,7 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin):
     def test_ex_list_vlans(self):
         vlans = self.driver.ex_list_vlans()
         self.assertEqual(vlans[0].name, "Production VLAN")
-            
+
 
 class DimensionDataMockHttp(MockHttp):
 
@@ -270,7 +268,7 @@ class DimensionDataMockHttp(MockHttp):
         body = self.fixtures.load(
             'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server.xml')
@@ -280,76 +278,76 @@ class DimensionDataMockHttp(MockHttp):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer_INPROGRESS(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer_RESOURCEBUSY.xml')
         return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer_INPROGRESS(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer_RESOURCEBUSY.xml')
         return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_infrastructure_datacenter(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_infrastructure_datacenter.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer_INPROGRESS(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer_INPROGRESS.xml')
         return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer_INPROGRESS(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer_INPROGRESS.xml')
         return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_resetServer(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_resetServer.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer_INPROGRESS(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer_INPROGRESS.xml')
         return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_networkDomain(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_networkDomain.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
 if __name__ == '__main__':
     sys.exit(unittest.main())


[21/21] libcloud git commit: Re-generate supported providers and methods tables.

Posted by to...@apache.org.
Re-generate supported providers and methods tables.


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

Branch: refs/heads/trunk
Commit: 1695d45b1925a9f0d0be4e49edef460ead6e3c81
Parents: c382e45
Author: Tomaz Muraus <to...@apache.org>
Authored: Sun Aug 30 14:27:03 2015 +0200
Committer: Tomaz Muraus <to...@apache.org>
Committed: Sun Aug 30 14:27:03 2015 +0200

----------------------------------------------------------------------
 docs/loadbalancer/_supported_methods.rst   |  6 ++---
 docs/loadbalancer/_supported_providers.rst | 32 ++++++++++++-------------
 2 files changed, 19 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/1695d45b/docs/loadbalancer/_supported_methods.rst
----------------------------------------------------------------------
diff --git a/docs/loadbalancer/_supported_methods.rst b/docs/loadbalancer/_supported_methods.rst
index c9a2d8e..669ac34 100644
--- a/docs/loadbalancer/_supported_methods.rst
+++ b/docs/loadbalancer/_supported_methods.rst
@@ -4,8 +4,8 @@
 Provider                               create balancer list balancers list members attach member detach member attach compute node
 ====================================== =============== ============== ============ ============= ============= ===================
 `Brightbox`_                           yes             yes            yes          yes           yes           yes                
-`CloudStack`_                          yes             yes            yes          yes           yes           no
-`Dimension Data`_                      yes             yes            yes          yes           yes           yes 
+`CloudStack`_                          yes             yes            yes          yes           yes           no                 
+`Dimension Data Load Balancer`_        yes             yes            yes          yes           yes           no                 
 `Amazon Elastic Load Balancing`_       yes             yes            yes          no            yes           yes                
 `Google Compute Engine Load Balancer`_ yes             yes            yes          yes           yes           yes                
 `GoGrid LB`_                           yes             yes            yes          yes           yes           no                 
@@ -18,7 +18,7 @@ Provider                               create balancer list balancers list membe
 
 .. _`Brightbox`: http://www.brightbox.co.uk/
 .. _`CloudStack`: http://cloudstack.org/
-.. _`Dimension Data`: http://cloud.dimensiondata.com/
+.. _`Dimension Data Load Balancer`: https://cloud.dimensiondata.com/
 .. _`Amazon Elastic Load Balancing`: http://aws.amazon.com/elasticloadbalancing/
 .. _`Google Compute Engine Load Balancer`: https://cloud.google.com/
 .. _`GoGrid LB`: http://www.gogrid.com/

http://git-wip-us.apache.org/repos/asf/libcloud/blob/1695d45b/docs/loadbalancer/_supported_providers.rst
----------------------------------------------------------------------
diff --git a/docs/loadbalancer/_supported_providers.rst b/docs/loadbalancer/_supported_providers.rst
index a86d587..3d1d830 100644
--- a/docs/loadbalancer/_supported_providers.rst
+++ b/docs/loadbalancer/_supported_providers.rst
@@ -1,24 +1,24 @@
 .. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
 
-====================================== ======================================== ================= ================================================== ============================
-Provider                               Documentation                            Provider constant Module                                             Class Name                  
-====================================== ======================================== ================= ================================================== ============================
-`Brightbox`_                                                                    BRIGHTBOX         :mod:`libcloud.loadbalancer.drivers.brightbox`     :class:`BrightboxLBDriver`  
-`CloudStack`_                                                                   CLOUDSTACK        :mod:`libcloud.loadbalancer.drivers.cloudstack`    :class:`CloudStackLBDriver`
-`Dimension Data`                                                                DIMENSIONDATA     :mod:`libcloud.loadbalancer.drivers.dimensiondata` :class:`DimensionDataLBDriver`
-`Amazon Elastic Load Balancing`_       :doc:`Click </loadbalancer/drivers/elb>` ELB               :mod:`libcloud.loadbalancer.drivers.elb`           :class:`ElasticLBDriver`    
-`Google Compute Engine Load Balancer`_ :doc:`Click </loadbalancer/drivers/gce>` GCE               :mod:`libcloud.loadbalancer.drivers.gce`           :class:`GCELBDriver`        
-`GoGrid LB`_                                                                    GOGRID            :mod:`libcloud.loadbalancer.drivers.gogrid`        :class:`GoGridLBDriver`     
-`Ninefold LB`_                                                                  NINEFOLD          :mod:`libcloud.loadbalancer.drivers.ninefold`      :class:`NinefoldLBDriver`   
-`Rackspace LB`_                                                                 RACKSPACE         :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceLBDriver`  
-`Rackspace LB`_                                                                 RACKSPACE_UK      :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceUKLBDriver`
-`Rackspace LB`_                                                                 RACKSPACE_US      :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceLBDriver`  
-`Softlayer Load Balancing`_                                                     SOFTLAYER         :mod:`libcloud.loadbalancer.drivers.softlayer`     :class:`SoftlayerLBDriver`  
-====================================== ======================================== ================= ================================================== ============================
+====================================== ======================================== ================= ================================================== ==============================
+Provider                               Documentation                            Provider constant Module                                             Class Name                    
+====================================== ======================================== ================= ================================================== ==============================
+`Brightbox`_                                                                    BRIGHTBOX         :mod:`libcloud.loadbalancer.drivers.brightbox`     :class:`BrightboxLBDriver`    
+`CloudStack`_                                                                   CLOUDSTACK        :mod:`libcloud.loadbalancer.drivers.cloudstack`    :class:`CloudStackLBDriver`   
+`Dimension Data Load Balancer`_                                                 DIMENSIONDATA     :mod:`libcloud.loadbalancer.drivers.dimensiondata` :class:`DimensionDataLBDriver`
+`Amazon Elastic Load Balancing`_       :doc:`Click </loadbalancer/drivers/elb>` ELB               :mod:`libcloud.loadbalancer.drivers.elb`           :class:`ElasticLBDriver`      
+`Google Compute Engine Load Balancer`_ :doc:`Click </loadbalancer/drivers/gce>` GCE               :mod:`libcloud.loadbalancer.drivers.gce`           :class:`GCELBDriver`          
+`GoGrid LB`_                                                                    GOGRID            :mod:`libcloud.loadbalancer.drivers.gogrid`        :class:`GoGridLBDriver`       
+`Ninefold LB`_                                                                  NINEFOLD          :mod:`libcloud.loadbalancer.drivers.ninefold`      :class:`NinefoldLBDriver`     
+`Rackspace LB`_                                                                 RACKSPACE         :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceLBDriver`    
+`Rackspace LB`_                                                                 RACKSPACE_UK      :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceUKLBDriver`  
+`Rackspace LB`_                                                                 RACKSPACE_US      :mod:`libcloud.loadbalancer.drivers.rackspace`     :class:`RackspaceLBDriver`    
+`Softlayer Load Balancing`_                                                     SOFTLAYER         :mod:`libcloud.loadbalancer.drivers.softlayer`     :class:`SoftlayerLBDriver`    
+====================================== ======================================== ================= ================================================== ==============================
 
 .. _`Brightbox`: http://www.brightbox.co.uk/
 .. _`CloudStack`: http://cloudstack.org/
-.. _`Dimension Data`: http://cloud.dimensiondata.com/
+.. _`Dimension Data Load Balancer`: https://cloud.dimensiondata.com/
 .. _`Amazon Elastic Load Balancing`: http://aws.amazon.com/elasticloadbalancing/
 .. _`Google Compute Engine Load Balancer`: https://cloud.google.com/
 .. _`GoGrid LB`: http://www.gogrid.com/


[14/21] libcloud git commit: [LIBCLOUD-737] Support (and test) for creating a balancer that has an empty list of members, or a NoneType for the list of members. Also creating tests for the destroy instance methods and added docstrings.

Posted by to...@apache.org.
[LIBCLOUD-737] Support (and test) for creating a balancer that has an empty list of members, or a NoneType for the list of members. Also creating tests for the destroy instance methods and added docstrings.


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

Branch: refs/heads/trunk
Commit: ed798ea955409458cc2fc62fa6eb8de2ab80d9fd
Parents: 0b8ef57
Author: Anthony Shaw <an...@gmail.com>
Authored: Sun Aug 30 11:09:23 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Sun Aug 30 11:09:23 2015 +1000

----------------------------------------------------------------------
 libcloud/loadbalancer/drivers/dimensiondata.py  | 108 ++++++++++++++++---
 ...8dabe5a7d0e4_networkDomainVip_deleteNode.xml |   9 ++
 ...8dabe5a7d0e4_networkDomainVip_deletePool.xml |   9 ++
 .../test/loadbalancer/test_dimensiondata.py     |  79 ++++++++++++++
 4 files changed, 191 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/ed798ea9/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index 729c1bc..401c6de 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -99,13 +99,14 @@ class DimensionDataLBDriver(Driver):
         :param name: Name of the new load balancer (required)
         :type  name: ``str``
 
-        :param port: Port the load balancer should listen on, defaults to 80
+        :param port: Port the load balancer should listen on,
+                    defaults to 80 (required)
         :type  port: ``str``
 
         :param protocol: Loadbalancer protocol, defaults to http.
         :type  protocol: ``str``
 
-        :param members: list of Members to attach to balancer
+        :param members: list of Members to attach to balancer (optional)
         :type  members: ``list`` of :class:`Member`
 
         :param algorithm: Load balancing algorithm, defaults to ROUND_ROBIN.
@@ -114,6 +115,12 @@ class DimensionDataLBDriver(Driver):
         :rtype: :class:`LoadBalancer`
         """
         network_domain_id = self.network_domain_id
+        if port is None:
+            port = 80
+        if protocol is None:
+            protocol = 'http'
+        if algorithm is None:
+            algorithm = Algorithm.ROUND_ROBIN
 
         # Create a pool first
         pool = self.ex_create_pool(
@@ -123,16 +130,17 @@ class DimensionDataLBDriver(Driver):
             balancer_method=self._ALGORITHM_TO_VALUE_MAP[algorithm])
 
         # Attach the members to the pool as nodes
-        for member in members:
-            node = self.ex_create_node(
-                network_domain_id=network_domain_id,
-                name=member.ip,
-                ip=member.ip,
-                ex_description=None)
-            self.ex_create_pool_member(
-                pool=pool,
-                node=node,
-                port=port)
+        if members is not None:
+            for member in members:
+                node = self.ex_create_node(
+                    network_domain_id=network_domain_id,
+                    name=member.ip,
+                    ip=member.ip,
+                    ex_description=None)
+                self.ex_create_pool_member(
+                    pool=pool,
+                    node=node,
+                    port=port)
 
         # Create the virtual listener (balancer)
         listener = self.ex_create_virtual_listener(
@@ -574,17 +582,41 @@ class DimensionDataLBDriver(Driver):
         )
 
     def ex_get_pools(self):
+        """
+        Get all of the pools inside the current geography
+
+        :return: Returns a ``list`` of type ``DimensionDataPool``
+        :rtype: ``list`` of ``DimensionDataPool``
+        """
         pools = self.connection \
             .request_with_orgId_api_2('networkDomainVip/pool').object
         return self._to_pools(pools)
 
     def ex_get_pool(self, pool_id):
+        """
+        Get a specific pool inside the current geography
+
+        :param pool_id: The identifier of the pool
+        :type  pool_id: ``str``
+
+        :return: Returns an instance of ``DimensionDataPool``
+        :rtype: ``DimensionDataPool``
+        """
         pool = self.connection \
             .request_with_orgId_api_2('networkDomainVip/pool/%s'
                                       % pool_id).object
         return self._to_pool(pool)
 
     def ex_destroy_pool(self, pool):
+        """
+        Destroy an existing pool
+
+        :param pool: The instance of ``DimensionDataPool`` to destroy
+        :type  pool: ``DimensionDataPool``
+
+        :return: ``True`` for success, ``False`` for failure
+        :rtype: ``bool``
+        """
         destroy_request = ET.Element('deletePool',
                                      {'xmlns': TYPES_URN,
                                       'id': pool.id})
@@ -597,37 +629,85 @@ class DimensionDataLBDriver(Driver):
         return responseCode == 'OK'
 
     def ex_get_pool_members(self, pool_id):
+        """
+        Get the members of a pool
+
+        :param pool: The instance of a pool
+        :type  pool: ``DimensionDataPool``
+
+        :return: Returns an ``list`` of ``DimensionDataPoolMember``
+        :rtype: ``list`` of ``DimensionDataPoolMember``
+        """
         members = self.connection \
             .request_with_orgId_api_2('networkDomainVip/poolMember?poolId=%s'
                                       % pool_id).object
         return self._to_members(members)
 
     def ex_get_pool_member(self, pool_member_id):
+        """
+        Get a specific member of a pool
+
+        :param pool: The id of a pool member
+        :type  pool: ``str``
+
+        :return: Returns an instance of ``DimensionDataPoolMember``
+        :rtype: ``DimensionDataPoolMember``
+        """
         member = self.connection \
             .request_with_orgId_api_2('networkDomainVip/poolMember/%s'
                                       % pool_member_id).object
         return self._to_member(member)
 
     def ex_destroy_pool_member(self, member, destroy_node=False):
+        """
+        Destroy a specific member of a pool
+
+        :param pool: The instance of a pool member
+        :type  pool: ``DimensionDataPoolMember``
+
+        :param destroy_node: Also destroy the associated node
+        :type  destroy_node: ``bool``
+
+        :return: ``True`` for success, ``False`` for failure
+        :rtype: ``bool``
+        """
         # remove the pool member
         destroy_request = ET.Element('removePoolMember',
                                      {'xmlns': TYPES_URN,
                                       'id': member.id})
 
-        self.connection.request_with_orgId_api_2(
+        result = self.connection.request_with_orgId_api_2(
             action='networkDomainVip/removePoolMember',
             method='POST',
             data=ET.tostring(destroy_request)).object
 
         if member.node_id is not None and destroy_node is True:
-            self.ex_destroy_node(member.node_id)
+            return self.ex_destroy_node(member.node_id)
+        else:
+            responseCode = findtext(result, 'responseCode', TYPES_URN)
+            return responseCode == 'OK'
 
     def ex_get_nodes(self):
+        """
+        Get the nodes within this geography
+
+        :return: Returns an ``list`` of ``DimensionDataVIPNode``
+        :rtype: ``list`` of ``DimensionDataVIPNode``
+        """
         nodes = self.connection \
             .request_with_orgId_api_2('networkDomainVip/node').object
         return self._to_nodes(nodes)
 
     def ex_destroy_node(self, node_id):
+        """
+        Destroy a specific node
+
+        :param node_id: The ID of of a ``DimensionDataVIPNode``
+        :type  node_id: ``str``
+
+        :return: ``True`` for success, ``False`` for failure
+        :rtype: ``bool``
+        """
         # Destroy the node
         destroy_request = ET.Element('deleteNode',
                                      {'xmlns': TYPES_URN,

http://git-wip-us.apache.org/repos/asf/libcloud/blob/ed798ea9/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteNode.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteNode.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteNode.xml
new file mode 100644
index 0000000..cd5177f
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteNode.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response requestId="na9/2015-05-14T13:37:20/62f06368-c3fb-11e3-b29c-
+001517c4643e"
+xmlns="urn:didata.com:api:cloud:types">
+<operation>DELETE_NODE</operation>
+<responseCode>OK</responseCode>
+<message>Node (id:34de6ed6-46a4-4dae-a753-2f8d3840c6f9) has been
+deleted.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/ed798ea9/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deletePool.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deletePool.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deletePool.xml
new file mode 100644
index 0000000..3883b55
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deletePool.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response requestId="na9/2015-05-14T13:37:20/62f06368-c3fb-11e3-b29c-
+001517c4643e"
+xmlns="urn:didata.com:api:cloud:types">
+<operation>DELETE_POOL</operation>
+<responseCode>OK</responseCode>
+<message>Pool (id:4d360b1f-bc2c-4ab7-9884-1f03ba2768f7) has been
+deleted.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/ed798ea9/libcloud/test/loadbalancer/test_dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/test_dimensiondata.py b/libcloud/test/loadbalancer/test_dimensiondata.py
index e855415..ff0b7fd 100644
--- a/libcloud/test/loadbalancer/test_dimensiondata.py
+++ b/libcloud/test/loadbalancer/test_dimensiondata.py
@@ -18,6 +18,7 @@ from libcloud.utils.py3 import httplib
 
 from libcloud.common.types import InvalidCredsError
 from libcloud.common.dimensiondata import DimensionDataVIPNode, DimensionDataPool
+from libcloud.common.dimensiondata import DimensionDataPoolMember
 from libcloud.loadbalancer.base import LoadBalancer, Member, Algorithm
 from libcloud.loadbalancer.drivers.dimensiondata \
     import DimensionDataLBDriver as DimensionData
@@ -66,6 +67,40 @@ class DimensionDataTests(unittest.TestCase):
         self.assertEqual(balancer.extra['pool_id'], '9e6b496d-5261-4542-91aa-b50c7f569c54')
         self.assertEqual(balancer.extra['network_domain_id'], '1234')
 
+    def test_create_balancer_no_members(self):
+        self.driver.ex_set_current_network_domain('1234')
+        members = None
+
+        balancer = self.driver.create_balancer(
+            name='test',
+            port=80,
+            protocol='http',
+            algorithm=Algorithm.ROUND_ROBIN,
+            members=members)
+        self.assertEqual(balancer.name, 'test')
+        self.assertEqual(balancer.id, '8334f461-0df0-42d5-97eb-f4678eb26bea')
+        self.assertEqual(balancer.ip, '165.180.12.22')
+        self.assertEqual(balancer.port, 80)
+        self.assertEqual(balancer.extra['pool_id'], '9e6b496d-5261-4542-91aa-b50c7f569c54')
+        self.assertEqual(balancer.extra['network_domain_id'], '1234')
+
+    def test_create_balancer_empty_members(self):
+        self.driver.ex_set_current_network_domain('1234')
+        members = []
+
+        balancer = self.driver.create_balancer(
+            name='test',
+            port=80,
+            protocol='http',
+            algorithm=Algorithm.ROUND_ROBIN,
+            members=members)
+        self.assertEqual(balancer.name, 'test')
+        self.assertEqual(balancer.id, '8334f461-0df0-42d5-97eb-f4678eb26bea')
+        self.assertEqual(balancer.ip, '165.180.12.22')
+        self.assertEqual(balancer.port, 80)
+        self.assertEqual(balancer.extra['pool_id'], '9e6b496d-5261-4542-91aa-b50c7f569c54')
+        self.assertEqual(balancer.extra['network_domain_id'], '1234')
+
     def test_list_balancers(self):
         bal = self.driver.list_balancers()
         self.assertEqual(bal[0].name, 'myProduction.Virtual.Listener')
@@ -237,6 +272,15 @@ class DimensionDataTests(unittest.TestCase):
         self.assertEqual(pool.name, 'myDevelopmentPool.1')
         self.assertEqual(pool.id, '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
 
+    def test_ex_destroy_pool(self):
+        response = self.driver.ex_destroy_pool(
+            pool=DimensionDataPool(
+                id='4d360b1f-bc2c-4ab7-9884-1f03ba2768f7',
+                name='test',
+                description='test',
+                status=State.RUNNING))
+        self.assertTrue(response)
+
     def test_get_pool_members(self):
         members = self.driver.ex_get_pool_members('4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
         self.assertEqual(2, len(members))
@@ -245,6 +289,7 @@ class DimensionDataTests(unittest.TestCase):
         self.assertEqual(members[0].status, 'NORMAL')
         self.assertEqual(members[0].ip, '10.0.3.13')
         self.assertEqual(members[0].port, 9889)
+        self.assertEqual(members[0].node_id, '3c207269-e75e-11e4-811f-005056806999')
 
     def test_get_pool_member(self):
         member = self.driver.ex_get_pool_member('3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
@@ -254,6 +299,30 @@ class DimensionDataTests(unittest.TestCase):
         self.assertEqual(member.ip, '10.0.3.13')
         self.assertEqual(member.port, 9889)
 
+    def test_ex_destroy_pool_member(self):
+        response = self.driver.ex_destroy_pool_member(
+            member=DimensionDataPoolMember(
+                id='',
+                name='test',
+                status=State.RUNNING,
+                ip='1.2.3.4',
+                port=80,
+                node_id='3c207269-e75e-11e4-811f-005056806999'),
+            destroy_node=False)
+        self.assertTrue(response)
+
+    def test_ex_destroy_pool_member_with_node(self):
+        response = self.driver.ex_destroy_pool_member(
+            member=DimensionDataPoolMember(
+                id='',
+                name='test',
+                status=State.RUNNING,
+                ip='1.2.3.4',
+                port=80,
+                node_id='34de6ed6-46a4-4dae-a753-2f8d3840c6f9'),
+            destroy_node=True)
+        self.assertTrue(response)
+
 
 class DimensionDataMockHttp(MockHttp):
 
@@ -330,6 +399,16 @@ class DimensionDataMockHttp(MockHttp):
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteVirtualListener.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deletePool(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deletePool.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteNode(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteNode.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
 
 if __name__ == '__main__':
     sys.exit(unittest.main())


[18/21] libcloud git commit: Merge branch 'trunk' into LIBCLOUD-737_Create_Dimension_Data_Load_Balancing_driver

Posted by to...@apache.org.
Merge branch 'trunk' into LIBCLOUD-737_Create_Dimension_Data_Load_Balancing_driver


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

Branch: refs/heads/trunk
Commit: 46626cb7b396f24cc26d048b642ab842ef385afe
Parents: 06b11e8 61bb1b5
Author: Tomaz Muraus <to...@apache.org>
Authored: Sun Aug 30 14:18:21 2015 +0200
Committer: Tomaz Muraus <to...@apache.org>
Committed: Sun Aug 30 14:18:21 2015 +0200

----------------------------------------------------------------------
 libcloud/dns/base.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------



[10/21] libcloud git commit: [LIBCLOUD-737] Completed implementation and unit test suite.

Posted by to...@apache.org.
[LIBCLOUD-737] Completed implementation and unit test suite.


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

Branch: refs/heads/trunk
Commit: 84938fa5b17b3887549cc9c61e05279306aaf078
Parents: 2709109
Author: Anthony Shaw <an...@gmail.com>
Authored: Fri Aug 28 09:53:58 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Fri Aug 28 09:53:58 2015 +1000

----------------------------------------------------------------------
 libcloud/common/dimensiondata.py                |  44 ++-
 libcloud/loadbalancer/drivers/dimensiondata.py  | 393 ++++++++++++-------
 libcloud/loadbalancer/types.py                  |   2 +-
 ...be5a7d0e4_networkDomainVip_addPoolMember.xml |   9 +
 ...8dabe5a7d0e4_networkDomainVip_createNode.xml |   8 +
 ...8dabe5a7d0e4_networkDomainVip_createPool.xml |   9 +
 ...4_networkDomainVip_createVirtualListener.xml |  11 +
 ...4_networkDomainVip_deleteVirtualListener.xml |   9 +
 ...a7d0e4_networkDomainVip_removePoolMember.xml |   7 +
 .../test/loadbalancer/test_dimensiondata.py     | 199 +++++++++-
 10 files changed, 535 insertions(+), 156 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/common/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/common/dimensiondata.py b/libcloud/common/dimensiondata.py
index f5cdf05..a6db06e 100644
--- a/libcloud/common/dimensiondata.py
+++ b/libcloud/common/dimensiondata.py
@@ -306,6 +306,7 @@ class DimensionDataVlan(object):
                 % (self.id, self.name, self.description,
                    self.location, self.status))
 
+
 class DimensionDataPool(object):
     """
     DimensionData VIP Pool.
@@ -322,21 +323,54 @@ class DimensionDataPool(object):
                  'description=%s, status=%s>')
                 % (self.id, self.name, self.description,
                    self.status))
-    
+
+
 class DimensionDataPoolMember(object):
     """
     DimensionData VIP Pool Member.
     """
 
-    def __init__(self, id, name, status, ip_address, port):
+    def __init__(self, id, name, status, ip, port):
         self.id = str(id)
         self.name = name
         self.status = status
-        self.ip_address = ip_address
+        self.ip = ip
         self.port = port
 
     def __repr__(self):
         return (('<DimensionDataPool: id=%s, name=%s, '
-                 'ip_address=%s, status=%s, port=%s>')
+                 'ip=%s, status=%s, port=%s>')
+                % (self.id, self.name,
+                   self.ip, self.status, self.port))
+
+
+class DimensionDataVIPNode(object):
+    def __init__(self, id, name, status, ip):
+        self.id = str(id)
+        self.name = name
+        self.status = status
+        self.ip = ip
+
+    def __repr__(self):
+        return (('<DimensionDataVIPNode: id=%s, name=%s, '
+                 'status=%s, ip=%s>')
+                % (self.id, self.name,
+                   self.status, self.ip))
+
+
+class DimensionDataVirtualListener(object):
+    """
+    DimensionData Virtual Listener.
+    """
+
+    def __init__(self, id, name, status, ip):
+        self.id = str(id)
+        self.name = name
+        self.status = status
+        self.ip = ip
+
+    def __repr__(self):
+        return (('<DimensionDataPool: id=%s, name=%s, '
+                 'status=%s, ip=%s>')
                 % (self.id, self.name,
-                   self.ip_address, self.status, self.port))
\ No newline at end of file
+                   self.status, self.ip))

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index dc6d728..2d7daaf 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -13,20 +13,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+try:
+    from lxml import etree as ET
+except ImportError:
+    from xml.etree import ElementTree as ET
+
 from libcloud.common.dimensiondata import DimensionDataConnection
 from libcloud.common.dimensiondata import DimensionDataPool
 from libcloud.common.dimensiondata import DimensionDataPoolMember
+from libcloud.common.dimensiondata import DimensionDataVirtualListener
+from libcloud.common.dimensiondata import DimensionDataVIPNode
 from libcloud.common.dimensiondata import API_ENDPOINTS
 from libcloud.common.dimensiondata import DEFAULT_REGION
 from libcloud.common.dimensiondata import TYPES_URN
 from libcloud.common.dimensiondata import SERVER_NS
-from libcloud.utils.misc import find, reverse_dict
+from libcloud.utils.misc import reverse_dict
 from libcloud.utils.xml import fixxpath, findtext, findall
 from libcloud.loadbalancer.types import State
 from libcloud.loadbalancer.base import Algorithm, Driver, LoadBalancer
-from libcloud.loadbalancer.base import DEFAULT_ALGORITHM, Member
+from libcloud.loadbalancer.base import Member
 from libcloud.loadbalancer.types import Provider
 
+
 class DimensionDataLBDriver(Driver):
     """
     DimensionData node driver.
@@ -39,6 +47,8 @@ class DimensionDataLBDriver(Driver):
     type = Provider.DIMENSIONDATA
     api_version = 1.0
 
+    network_domain_id = None
+
     _VALUE_TO_ALGORITHM_MAP = {
         'ROUND_ROBIN': Algorithm.ROUND_ROBIN,
         'LEAST_CONNECTIONS': Algorithm.LEAST_CONNECTIONS,
@@ -67,11 +77,11 @@ class DimensionDataLBDriver(Driver):
         self.selected_region = API_ENDPOINTS[region]
 
         super(DimensionDataLBDriver, self).__init__(key=key, secret=secret,
-                                                      secure=secure, host=host,
-                                                      port=port,
-                                                      api_version=api_version,
-                                                      region=region,
-                                                      **kwargs)
+                                                    secure=secure, host=host,
+                                                    port=port,
+                                                    api_version=api_version,
+                                                    region=region,
+                                                    **kwargs)
 
     def _ex_connection_class_kwargs(self):
         """
@@ -104,50 +114,58 @@ class DimensionDataLBDriver(Driver):
 
         :rtype: :class:`LoadBalancer`
         """
-        # TODO: Figure out which location is used...
-        network_domain_id=None
-        
-        # Create a pool first 
-        pool_id=self.ex_create_pool(
+        network_domain_id = self.network_domain_id
+
+        # Create a pool first
+        pool = self.ex_create_pool(
             network_domain_id=network_domain_id,
             name=name,
             ex_description=None,
-            balancer_method=_ALGORITHM_TO_VALUE_MAP.get(algorithm)
-            )
-        
+            balancer_method=self._ALGORITHM_TO_VALUE_MAP[algorithm])
+
         # Attach the members to the pool as nodes
         for member in members:
-            node_id=self.ex_create_node(
+            node = self.ex_create_node(
                 network_domain_id=network_domain_id,
-                name=member.name,
+                name=member.ip,
                 ip=member.ip,
-                ex_description=None
-                )
+                ex_description=None)
             self.ex_create_pool_member(
-                pool_id=pool_id,
-                node_id=node_id,
+                pool=pool,
+                node=node,
                 port=port)
-            
+
         # Create the virtual listener (balancer)
-        self.ex_create_virtual_listener(
-                       network_domain_id=network_domain_id,
-                       name=name,
-                       ex_description=None,
-                       port=port)
-        return True
+        listener = self.ex_create_virtual_listener(
+            network_domain_id=network_domain_id,
+            name=name,
+            ex_description=None,
+            port=port)
+
+        return LoadBalancer(
+            id=listener.id,
+            name=listener.name,
+            state=State.RUNNING,
+            ip=listener.ip,
+            port=port,
+            driver=self,
+            extra={'pool_id': pool.id,
+                   'network_domain_id': network_domain_id}
+        )
 
     def list_balancers(self):
         """
         List all loadbalancers inside a geography.
-        
+
         In Dimension Data terminology these are known as virtual listeners
 
         :rtype: ``list`` of :class:`LoadBalancer`
         """
-        
+
         return self._to_balancers(
             self.connection
-            .request_with_orgId_api_2('networkDomainVip/virtualListener').object)
+            .request_with_orgId_api_2('networkDomainVip/virtualListener')
+            .object)
 
     def get_balancer(self, balancer_id):
         """
@@ -158,7 +176,7 @@ class DimensionDataLBDriver(Driver):
 
         :rtype: :class:`LoadBalancer`
         """
-        
+
         bal = self.connection \
             .request_with_orgId_api_2('networkDomainVip/virtualListener/%s'
                                       % balancer_id).object
@@ -169,7 +187,7 @@ class DimensionDataLBDriver(Driver):
         Return a list of supported protocols.
 
         Since all protocols are support by Dimension Data, this is a list
-        of common protocols. 
+        of common protocols.
 
         :rtype: ``list`` of ``str``
         """
@@ -178,7 +196,7 @@ class DimensionDataLBDriver(Driver):
     def balancer_list_members(self, balancer):
         """
         Return list of members attached to balancer.
-        
+
         In Dimension Data terminology these are the members of the pools
         within a virtual listener.
 
@@ -187,13 +205,12 @@ class DimensionDataLBDriver(Driver):
 
         :rtype: ``list`` of :class:`Member`
         """
-        
         pool_members = self.ex_get_pool_members(balancer.extra['pool_id'])
         members = []
         for pool_member in pool_members:
             members.append(Member(
                 id=pool_member.id,
-                ip=pool_member.ip_address,
+                ip=pool_member.ip,
                 port=pool_member.port,
                 balancer=balancer,
                 extra=None
@@ -213,21 +230,21 @@ class DimensionDataLBDriver(Driver):
         :return: Member after joining the balancer.
         :rtype: :class:`Member`
         """
-        
-        nodeId= self.ex_create_node(
+        node = self.ex_create_node(
             network_domain_id=balancer.extra['network_domain_id'],
-            name=member.name,
+            name='Member.'+member.ip,
             ip=member.ip,
-            ex_description=member.description
+            ex_description=''
         )
-        if nodeId == false:
+        if node is False:
             return False
-        
-        poolMemberId = self.ex_create_pool_member(balancer.extra['pool_id'],
-                                                  nodeId,
-                                                  member.port)
-        
-        return True
+        pool = self.ex_get_pool(balancer.extra['pool_id'])
+        pool_member = self.ex_create_pool_member(
+            pool=pool,
+            node=node,
+            port=member.port)
+        member.id = pool_member.id
+        return member
 
     def balancer_detach_member(self, balancer, member):
         """
@@ -242,16 +259,15 @@ class DimensionDataLBDriver(Driver):
         :return: ``True`` if member detach was successful, otherwise ``False``.
         :rtype: ``bool``
         """
-        
         create_pool_m = ET.Element('removePoolMember', {'xmlns': SERVER_NS,
                                                         'id': member.id})
 
-        self.connection.request_with_orgId_api_2(
+        result = self.connection.request_with_orgId_api_2(
             'networkDomainVip/removePoolMember',
             method='POST',
             data=ET.tostring(create_pool_m)).object
-        
-        return True
+        responseCode = findtext(result, 'responseCode', TYPES_URN)
+        return responseCode == 'OK'
 
     def destroy_balancer(self, balancer):
         """
@@ -263,47 +279,76 @@ class DimensionDataLBDriver(Driver):
         :return: ``True`` if the destroy was successful, otherwise ``False``.
         :rtype: ``bool``
         """
-        
-        delete_listener = ET.Element('deleteVirtualListener', {'xmlns': SERVER_NS,
-                                                               'id': balancer.id})
+        delete_listener = ET.Element('deleteVirtualListener',
+                                     {'xmlns': SERVER_NS,
+                                      'id': balancer.id})
 
-        self.connection.request_with_orgId_api_2(
+        result = self.connection.request_with_orgId_api_2(
             'networkDomainVip/deleteVirtualListener',
             method='POST',
             data=ET.tostring(delete_listener)).object
-        return True
+        responseCode = findtext(result, 'responseCode', TYPES_URN)
+        return responseCode == 'OK'
 
-    def ex_create_pool_member(self, pool_id, node_id, port):
+    def ex_set_current_network_domain(self, network_domain_id):
+        """
+        Set the network domain (part of the network) of the driver
+
+        :param network_domain_id: ID of the pool (required)
+        :type  network_domain_id: ``str``
+        """
+        self.network_domain_id = network_domain_id
+
+    def ex_get_current_network_domain(self):
+        """
+        Get the current network domain ID of the driver.
+
+        :return: ID of the network domain
+        :rtype: ``str``
+        """
+        return self.network_domain_id
+
+    def ex_create_pool_member(self, pool, node, port):
         """
         Create a new member in an existing pool from an existing node
 
-        :param pool_id: ID of the pool (required)
-        :type  name: ``str``
+        :param pool: Instance of ``DimensionDataPool`` (required)
+        :type  pool: ``DimensionDataPool``
 
-        :param node_id: ID of the node (required)
-        :type  name: ``str``
+        :param node: Instance of ``DimensionDataVIPNode`` (required)
+        :type  node: ``DimensionDataVIPNode``
 
         :param port: Port the the service will listen on
         :type  port: ``str``
 
-        :return: ID of the node member, ``False`` if failed to add. 
-        :rtype: ``str``
+        :return: The node member, instance of ``DimensionDataPoolMember``
+        :rtype: ``DimensionDataPoolMember``
         """
         create_pool_m = ET.Element('addPoolMember', {'xmlns': SERVER_NS})
-        ET.SubElement(create_pool_m, "poolId").text = pool_id
-        ET.SubElement(create_pool_m, "nodeId").text = node_id
-        ET.SubElement(create_pool_m, "port").text = port
+        ET.SubElement(create_pool_m, "poolId").text = pool.id
+        ET.SubElement(create_pool_m, "nodeId").text = node.id
+        ET.SubElement(create_pool_m, "port").text = str(port)
 
         response = self.connection.request_with_orgId_api_2(
             'networkDomainVip/addPoolMember',
             method='POST',
             data=ET.tostring(create_pool_m)).object
-        
+
+        member_id = None
+        node_name = None
         for info in findall(response, 'info', TYPES_URN):
-            if info.name == 'poolMemberId':
-                return info.value
-        
-        return False
+            if info.get('name') == 'poolMemberId':
+                member_id = info.get('value')
+            if info.get('name') == 'nodeName':
+                node_name = info.get('value')
+
+        return DimensionDataPoolMember(
+            id=member_id,
+            name=node_name,
+            status=State.RUNNING,
+            ip=node.ip,
+            port=port
+        )
 
     def ex_create_node(self,
                        network_domain_id,
@@ -326,34 +371,46 @@ class DimensionDataLBDriver(Driver):
 
         :param ex_description: Description of the node
         :type  ex_description: ``str``
-        
-        :param connection_limit: Maximum number of concurrent connections per sec
+
+        :param connection_limit: Maximum number
+                of concurrent connections per sec
         :type  connection_limit: ``int``
-        
+
         :param connection_rate_limit: Maximum number of concurrent sessions
         :type  connection_rate_limit: ``int``
 
-        :return: ID of the node, ``False`` if failed to add. 
-        :rtype: ``str``
+        :return: Instance of ``DimensionDataVIPNode``
+        :rtype: ``DimensionDataVIPNode``
         """
         create_node_elm = ET.Element('createNode', {'xmlns': SERVER_NS})
-        ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
+        ET.SubElement(create_node_elm, "networkDomainId") \
+            .text = network_domain_id
         ET.SubElement(create_node_elm, "description").text = ex_description
         ET.SubElement(create_node_elm, "name").text = name
         ET.SubElement(create_node_elm, "ipv4Address").text = ip
-        ET.SubElement(create_node_elm, "connectionLimit").text = connection_limit
-        ET.SubElement(create_node_elm, "connectionRateLimit").text = connection_rate_limit
+        ET.SubElement(create_node_elm, "connectionLimit") \
+            .text = str(connection_limit)
+        ET.SubElement(create_node_elm, "connectionRateLimit") \
+            .text = str(connection_rate_limit)
 
         response = self.connection.request_with_orgId_api_2(
             'networkDomainVip/createNode',
             method='POST',
             data=ET.tostring(create_node_elm)).object
-        
+
+        node_id = None
+        node_name = None
         for info in findall(response, 'info', TYPES_URN):
-            if info.name == 'nodeId':
-                return info.value
-        
-        return None
+            if info.get('name') == 'nodeId':
+                node_id = info.get('value')
+            if info.get('name') == 'name':
+                node_name = info.get('value')
+        return DimensionDataVIPNode(
+            id=node_id,
+            name=node_name,
+            status=State.RUNNING,
+            ip=ip
+        )
 
     def ex_create_pool(self,
                        network_domain_id,
@@ -376,65 +433,131 @@ class DimensionDataLBDriver(Driver):
 
         :param ex_description: Description of the node
         :type  ex_description: ``str``
-        
-        :param service_down_action: What to do when node is unavailable NONE, DROP or RESELECT
+
+        :param service_down_action: What to do when node
+                                    is unavailable NONE, DROP or RESELECT
         :type  service_down_action: ``str``
-        
+
         :param slow_ramp_time: Number of seconds to stagger ramp up of nodes
         :type  slow_ramp_time: ``int``
 
-        :return: ID of the pool, ``False`` if failed to add. 
-        :rtype: ``str``
+        :return: Instance of ``DimensionDataPool``
+        :rtype: ``DimensionDataPool``
         """
         create_node_elm = ET.Element('createPool', {'xmlns': SERVER_NS})
-        ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
+        ET.SubElement(create_node_elm, "networkDomainId") \
+            .text = network_domain_id
         ET.SubElement(create_node_elm, "description").text = ex_description
         ET.SubElement(create_node_elm, "name").text = name
-        ET.SubElement(create_node_elm, "loadBalancerMethod").text = balancer_method
-        ET.SubElement(create_node_elm, "serviceDownAction").text = service_down_action
-        ET.SubElement(create_node_elm, "slowRampTime").text = slow_ramp_time
+        ET.SubElement(create_node_elm, "loadBalancerMethod") \
+            .text = balancer_method
+        ET.SubElement(create_node_elm, "serviceDownAction") \
+            .text = service_down_action
+        ET.SubElement(create_node_elm, "slowRampTime").text \
+            = str(slow_ramp_time)
 
         response = self.connection.request_with_orgId_api_2(
             'networkDomainVip/createPool',
             method='POST',
             data=ET.tostring(create_node_elm)).object
-        
+
+        pool_id = None
         for info in findall(response, 'info', TYPES_URN):
-            if info.name == 'poolId':
-                return info.value
-        
-        return False
+            if info.get('name') == 'poolId':
+                pool_id = info.get('value')
+
+        return DimensionDataPool(
+            id=pool_id,
+            name=name,
+            description=ex_description,
+            status=State.RUNNING
+        )
 
     def ex_create_virtual_listener(self,
-                       network_domain_id,
-                       name,
-                       ex_description,
-                       port,
-                       listener_type='STANDARD',
-                       protocol='ANY',
-                       connection_limit=25000,
-                       connection_rate_limit=2000,
-                       source_port_preservation='PRESERVE'):
-        create_node_elm = ET.Element('createVirtualListener', {'xmlns': SERVER_NS})
-        ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
+                                   network_domain_id,
+                                   name,
+                                   ex_description,
+                                   port,
+                                   listener_type='STANDARD',
+                                   protocol='ANY',
+                                   connection_limit=25000,
+                                   connection_rate_limit=2000,
+                                   source_port_preservation='PRESERVE'):
+        """
+        Create a new virtual listener (load balancer)
+
+        :param network_domain_id: Network Domain ID (required)
+        :type  name: ``str``
+
+        :param name: name of the listener (required)
+        :type  name: ``str``
+
+        :param ex_description: Description of the node
+        :type  ex_description: ``str``
+
+        :param port: Description of the node
+        :type  port: ``str``
+
+        :param listener_type: The type of balancer, one of STANDARD (default)
+                                or PERFORMANCE_LAYER_4
+        :type  listener_type: ``str``
+
+        :param protocol: For STANDARD type, ANY, TCP or UDP
+                         for PERFORMANCE_LAYER_4 choice of ANY, TCP, UDP, HTTP
+        :type  protcol: ``str``
+
+        :param connection_limit: Maximum number
+                                of concurrent connections per sec
+        :type  connection_limit: ``int``
+
+        :param connection_rate_limit: Maximum number of concurrent sessions
+        :type  connection_rate_limit: ``int``
+
+        :param source_port_preservation: Choice of PRESERVE,
+                                        PRESERVE_STRICT or CHANGE
+        :type  source_port_preservation: ``str``
+
+        :return: Instance of the listener
+        :rtype: ``DimensionDataVirtualListener``
+        """
+        create_node_elm = ET.Element('createVirtualListener',
+                                     {'xmlns': SERVER_NS})
+        ET.SubElement(create_node_elm, "networkDomainId") \
+            .text = network_domain_id
         ET.SubElement(create_node_elm, "description").text = ex_description
         ET.SubElement(create_node_elm, "name").text = name
-        ET.SubElement(create_node_elm, "port").text = port
+        ET.SubElement(create_node_elm, "port").text = str(port)
         ET.SubElement(create_node_elm, "type").text = listener_type
-        ET.SubElement(create_node_elm, "connectionLimit").text = connection_limit
-        ET.SubElement(create_node_elm, "connectionRateLimit").text = connection_rate_limit
-        ET.SubElement(create_node_elm, "sourcePortPreservation").text = source_port_preservation
+        ET.SubElement(create_node_elm, "connectionLimit") \
+            .text = str(connection_limit)
+        ET.SubElement(create_node_elm, "connectionRateLimit") \
+            .text = str(connection_rate_limit)
+        ET.SubElement(create_node_elm, "sourcePortPreservation") \
+            .text = source_port_preservation
+
+        if protocol != 'ANY':
+            ET.SubElement(create_node_elm, "protocol") \
+                .text = protocol
 
         response = self.connection.request_with_orgId_api_2(
             'networkDomainVip/createVirtualListener',
             method='POST',
             data=ET.tostring(create_node_elm)).object
-        
+
+        virtual_listener_id = None
+        virtual_listener_ip = None
         for info in findall(response, 'info', TYPES_URN):
-            if info.name == 'poolId':
-                return info.value
-        
-        return False
+            if info.get('name') == 'virtualListenerId':
+                virtual_listener_id = info.get('value')
+            if info.get('name') == 'listenerIpAddress':
+                virtual_listener_ip = info.get('value')
+
+        return DimensionDataVirtualListener(
+            id=virtual_listener_id,
+            name=name,
+            ip=virtual_listener_ip,
+            status=State.RUNNING
+        )
 
     def ex_get_pools(self):
         pools = self.connection \
@@ -446,20 +569,20 @@ class DimensionDataLBDriver(Driver):
             .request_with_orgId_api_2('networkDomainVip/pool/%s'
                                       % pool_id).object
         return self._to_pool(pool)
-    
+
     def ex_get_pool_members(self, pool_id):
         members = self.connection \
             .request_with_orgId_api_2('networkDomainVip/poolMember?poolId=%s'
                                       % pool_id).object
         return self._to_members(members)
-    
+
     def ex_get_pool_member(self, pool_member_id):
         member = self.connection \
             .request_with_orgId_api_2('networkDomainVip/poolMember/%s'
                                       % pool_member_id).object
         return self._to_member(member)
 
-    def _to_balancers(self, object ):
+    def _to_balancers(self, object):
         loadbalancers = []
         for element in object.findall(fixxpath("virtualListener", TYPES_URN)):
             loadbalancers.append(self._to_balancer(element))
@@ -471,19 +594,19 @@ class DimensionDataLBDriver(Driver):
         name = findtext(element, 'name', TYPES_URN)
         port = findtext(element, 'port', TYPES_URN)
         extra = {}
-        
+
         extra['pool_id'] = element.find(fixxpath(
-                'pool',
-                TYPES_URN)).get('id')
+            'pool',
+            TYPES_URN)).get('id')
         extra['network_domain_id'] = findtext(element, 'networkDomainId',
                                               TYPES_URN)
-        
+
         balancer = LoadBalancer(
             id=element.get('id'),
             name=name,
             state=self._VALUE_TO_STATE_MAP.get(
-                              findtext(element, 'state', TYPES_URN),
-                              State.UNKNOWN),
+                findtext(element, 'state', TYPES_URN),
+                State.UNKNOWN),
             ip=ipaddress,
             port=port,
             driver=self.connection.driver,
@@ -491,14 +614,14 @@ class DimensionDataLBDriver(Driver):
         )
 
         return balancer
-    
-    def _to_members(self, object ):
+
+    def _to_members(self, object):
         members = []
         for element in object.findall(fixxpath("poolMember", TYPES_URN)):
             members.append(self._to_member(element))
 
         return members
-    
+
     def _to_member(self, element):
         pool = DimensionDataPoolMember(
             id=element.get('id'),
@@ -506,25 +629,25 @@ class DimensionDataLBDriver(Driver):
                 'node',
                 TYPES_URN)).get('name'),
             status=findtext(element, 'state', TYPES_URN),
-            ip_address=element.find(fixxpath(
+            ip=element.find(fixxpath(
                 'node',
                 TYPES_URN)).get('ipAddress'),
             port=int(findtext(element, 'port', TYPES_URN))
         )
         return pool
-    
-    def _to_pools(self, object ):
+
+    def _to_pools(self, object):
         pools = []
         for element in object.findall(fixxpath("pool", TYPES_URN)):
             pools.append(self._to_pool(element))
 
         return pools
-    
+
     def _to_pool(self, element):
         pool = DimensionDataPool(
             id=element.get('id'),
             name=findtext(element, 'name', TYPES_URN),
-            status=findtext(element,'state', TYPES_URN),
+            status=findtext(element, 'state', TYPES_URN),
             description=findtext(element, 'description', TYPES_URN)
         )
         return pool

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/loadbalancer/types.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/types.py b/libcloud/loadbalancer/types.py
index 9a34293..c7e390b 100644
--- a/libcloud/loadbalancer/types.py
+++ b/libcloud/loadbalancer/types.py
@@ -41,7 +41,7 @@ class Provider(object):
     GCE = 'gce'
     SOFTLAYER = 'softlayer'
     DIMENSIONDATA = 'dimensiondata'
-    
+
     # Deprecated
     RACKSPACE_US = 'rackspace_us'
     RACKSPACE_UK = 'rackspace_uk'

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_addPoolMember.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_addPoolMember.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_addPoolMember.xml
new file mode 100644
index 0000000..e4cba7a
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_addPoolMember.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response
+xmlns="urn:didata.com:api:cloud:types" requestId="na9/2015-06-09T07:02:49.563-04:00/40653bb1-cf55-4ba8-ba00-121c19c50a54">
+<operation>ADD_POOL_MEMBER</operation>
+<responseCode>OK</responseCode>
+<message>Pool Member '10.0.3.13:9888' has been added.</message>
+<info name="poolMemberId" value="3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0"/>
+<info name="nodeName" value="10.0.3.13"/>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createNode.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createNode.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createNode.xml
new file mode 100644
index 0000000..696525c
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createNode.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<response requestId="na/2015-04-14T13:37:20/62f06368-c3fb-11e3-b29c-001517c4643e" xmlns="urn:didata.com:api:cloud:types">
+<operation>CREATE_NODE</operation>
+<responseCode>OK</responseCode>
+<message>Node 'myProductionNode.1' has been created.</message>
+<info name="nodeId" value="9e6b496d-5261-4542-91aa-b50c7f569c54"/>
+<info name="name" value="myProductionNode.1"/>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createPool.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createPool.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createPool.xml
new file mode 100644
index 0000000..28302d5
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createPool.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<response requestId="na/2015-04-14T13:37:20/62f06368-c3fb-11e3-b29c-
+001517c4643e" xmlns="urn:didata.com:api:cloud:types">
+<operation>CREATE_POOL</operation>
+<responseCode>OK</responseCode>
+<message>Pool 'myProductionPool.1' has been created.</message>
+<info name="poolId" value="9e6b496d-5261-4542-91aa-b50c7f569c54"/>
+<info name="name" value="myProductionPool.1"/>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createVirtualListener.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createVirtualListener.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createVirtualListener.xml
new file mode 100644
index 0000000..5cf1f5a
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createVirtualListener.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response
+xmlns="urn:didata.com:api:cloud:types" requestId="na9/2015-06-11T05:45:22.833-04:00/0dc58e64-6e05-4de2-98d6-70bee28cba97">
+<operation>CREATE_VIRTUAL_LISTENER</operation>
+<responseCode>OK</responseCode>
+<message>Virtual Listener 'Production.Load.Balancer' has been created on
+IP 165.180.12.22.</message>
+<info name="virtualListenerId" value="8334f461-0df0-42d5-97eb-f4678eb26bea"/>
+<info name="name" value="Production.Load.Balancer"/>
+<info name="listenerIpAddress" value="165.180.12.22"/>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteVirtualListener.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteVirtualListener.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteVirtualListener.xml
new file mode 100644
index 0000000..3504ce9
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteVirtualListener.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response requestId="na9/2015-05-14T13:37:20/62f06368-c3fb-11e3-b29c-
+001517c4643e"
+xmlns="urn:didata.com:api:cloud:types">
+<operation>DELETE_VIRTUAL_LISTENER</operation>
+<responseCode>OK</responseCode>
+<message>Virtual Listener (id:6115469d-a8bb-445b-bb23-d23b5283f2b9) has been
+deleted.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_removePoolMember.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_removePoolMember.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_removePoolMember.xml
new file mode 100644
index 0000000..bfe47bc
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_removePoolMember.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response requestId="na9/2015-05-14T13:37:20/62f06368-c3fb-11e3-b29c-001517c4643e" xmlns="urn:didata.com:api:cloud:types">
+<operation>REMOVE_POOL_MEMBER</operation>
+<responseCode>OK</responseCode>
+<message>Pool Member (id:34de6ed6-46a4-4dae-a753-2f8d3840c6f9) has been
+removed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/84938fa5/libcloud/test/loadbalancer/test_dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/test_dimensiondata.py b/libcloud/test/loadbalancer/test_dimensiondata.py
index 0c62087..d9529f3 100644
--- a/libcloud/test/loadbalancer/test_dimensiondata.py
+++ b/libcloud/test/loadbalancer/test_dimensiondata.py
@@ -17,10 +17,11 @@ import unittest
 from libcloud.utils.py3 import httplib
 
 from libcloud.common.types import InvalidCredsError
-from libcloud.loadbalancer.base import LoadBalancer
-from libcloud.loadbalancer.drivers.dimensiondata import DimensionDataLBDriver as DimensionData
+from libcloud.common.dimensiondata import DimensionDataVIPNode, DimensionDataPool
+from libcloud.loadbalancer.base import LoadBalancer, Member, Algorithm
+from libcloud.loadbalancer.drivers.dimensiondata \
+    import DimensionDataLBDriver as DimensionData
 from libcloud.loadbalancer.types import State
-from libcloud.common.dimensiondata import DimensionDataAPIException
 
 from libcloud.test import MockHttp
 from libcloud.test.file_fixtures import LoadBalancerFileFixtures
@@ -39,11 +40,32 @@ class DimensionDataTests(unittest.TestCase):
         DimensionDataMockHttp.type = 'UNAUTHORIZED'
         try:
             self.driver.list_balancers()
-            self.assertTrue(
-                False)  # Above command should have thrown an InvalidCredsException
+            self.assertTrue(False)
+            # Above command should have thrown an InvalidCredsException
         except InvalidCredsError:
             pass
 
+    def test_create_balancer(self):
+        self.driver.ex_set_current_network_domain('1234')
+        members = []
+        members.append(Member(
+            id=None,
+            ip='1.2.3.4',
+            port=80))
+
+        balancer = self.driver.create_balancer(
+            name='test',
+            port=80,
+            protocol='http',
+            algorithm=Algorithm.ROUND_ROBIN,
+            members=members)
+        self.assertEqual(balancer.name, 'test')
+        self.assertEqual(balancer.id, '8334f461-0df0-42d5-97eb-f4678eb26bea')
+        self.assertEqual(balancer.ip, '165.180.12.22')
+        self.assertEqual(balancer.port, 80)
+        self.assertEqual(balancer.extra['pool_id'], '9e6b496d-5261-4542-91aa-b50c7f569c54')
+        self.assertEqual(balancer.extra['network_domain_id'], '1234')
+
     def test_list_balancers(self):
         bal = self.driver.list_balancers()
         self.assertEqual(bal[0].name, 'myProduction.Virtual.Listener')
@@ -53,8 +75,8 @@ class DimensionDataTests(unittest.TestCase):
         self.assertEqual(bal[0].state, State.RUNNING)
 
     def test_balancer_list_members(self):
-        extra={}
-        extra['pool_id']='4d360b1f-bc2c-4ab7-9884-1f03ba2768f7'
+        extra = {'pool_id': '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7',
+                 'network_domain_id': '1234'}
         balancer = LoadBalancer(
             id='234',
             name='test',
@@ -70,6 +92,122 @@ class DimensionDataTests(unittest.TestCase):
         self.assertEqual(members[0].id, '3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
         self.assertEqual(members[0].port, 9889)
 
+    def test_balancer_attach_member(self):
+        extra = {'pool_id': '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7',
+                 'network_domain_id': '1234'}
+        balancer = LoadBalancer(
+            id='234',
+            name='test',
+            state=State.RUNNING,
+            ip='1.2.3.4',
+            port=1234,
+            driver=self.driver,
+            extra=extra
+        )
+        member = Member(
+            id=None,
+            ip='112.12.2.2',
+            port=80,
+            balancer=balancer,
+            extra=None)
+        member = self.driver.balancer_attach_member(balancer, member)
+        self.assertEqual(member.id, '3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
+
+    def test_balancer_detach_member(self):
+        extra = {'pool_id': '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7',
+                 'network_domain_id': '1234'}
+        balancer = LoadBalancer(
+            id='234',
+            name='test',
+            state=State.RUNNING,
+            ip='1.2.3.4',
+            port=1234,
+            driver=self.driver,
+            extra=extra
+        )
+        member = Member(
+            id='3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0',
+            ip='112.12.2.2',
+            port=80,
+            balancer=balancer,
+            extra=None)
+        result = self.driver.balancer_detach_member(balancer, member)
+        self.assertEqual(result, True)
+
+    def test_destroy_balancer(self):
+        extra = {'pool_id': '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7',
+                 'network_domain_id': '1234'}
+        balancer = LoadBalancer(
+            id='234',
+            name='test',
+            state=State.RUNNING,
+            ip='1.2.3.4',
+            port=1234,
+            driver=self.driver,
+            extra=extra
+        )
+        response = self.driver.destroy_balancer(balancer)
+        self.assertEqual(response, True)
+
+    def test_set_get_network_domain_id(self):
+        self.driver.ex_set_current_network_domain('1234')
+        nwd = self.driver.ex_get_current_network_domain()
+        self.assertEqual(nwd, '1234')
+
+    def test_ex_create_pool_member(self):
+        pool = DimensionDataPool(
+            id='4d360b1f-bc2c-4ab7-9884-1f03ba2768f7',
+            name='test',
+            description='test',
+            status=State.RUNNING
+        )
+        node = DimensionDataVIPNode(
+            id='2344',
+            name='test',
+            status=State.RUNNING,
+            ip='123.23.3.2'
+        )
+        member = self.driver.ex_create_pool_member(
+            pool=pool,
+            node=node,
+            port=80
+        )
+        self.assertEqual(member.id, '3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
+        self.assertEqual(member.name, '10.0.3.13')
+        self.assertEqual(member.ip, '123.23.3.2')
+
+    def test_ex_create_node(self):
+        node = self.driver.ex_create_node(
+            network_domain_id='12345',
+            name='test',
+            ip='123.12.32.2',
+            ex_description='',
+            connection_limit=25000,
+            connection_rate_limit=2000)
+        self.assertEqual(node.name, 'myProductionNode.1')
+        self.assertEqual(node.id, '9e6b496d-5261-4542-91aa-b50c7f569c54')
+
+    def test_ex_create_pool(self, ):
+        pool = self.driver.ex_create_pool(
+            network_domain_id='1234',
+            name='test',
+            balancer_method='ROUND_ROBIN',
+            ex_description='test',
+            service_down_action='NONE',
+            slow_ramp_time=30)
+        self.assertEqual(pool.id, '9e6b496d-5261-4542-91aa-b50c7f569c54')
+        self.assertEqual(pool.name, 'test')
+        self.assertEqual(pool.status, State.RUNNING)
+
+    def test_ex_create_virtual_listener(self):
+        listener = self.driver.ex_create_virtual_listener(
+            network_domain_id='12345',
+            name='test',
+            ex_description='test',
+            port=80)
+        self.assertEqual(listener.id, '8334f461-0df0-42d5-97eb-f4678eb26bea')
+        self.assertEqual(listener.name, 'test')
+
     def test_get_balancer(self):
         bal = self.driver.get_balancer('6115469d-a8bb-445b-bb23-d23b5283f2b9')
         self.assertEqual(bal.name, 'myProduction.Virtual.Listener')
@@ -81,14 +219,14 @@ class DimensionDataTests(unittest.TestCase):
     def test_list_protocols(self):
         protocols = self.driver.list_protocols()
         self.assertNotEqual(0, len(protocols))
-    
-    def test_get_pools(self):
+
+    def test_ex_get_pools(self):
         pools = self.driver.ex_get_pools()
         self.assertNotEqual(0, len(pools))
         self.assertEqual(pools[0].name, 'myDevelopmentPool.1')
         self.assertEqual(pools[0].id, '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
-        
-    def test_get_pool(self):
+
+    def test_ex_get_pool(self):
         pool = self.driver.ex_get_pool('4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
         self.assertEqual(pool.name, 'myDevelopmentPool.1')
         self.assertEqual(pool.id, '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
@@ -99,17 +237,18 @@ class DimensionDataTests(unittest.TestCase):
         self.assertEqual(members[0].id, '3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
         self.assertEqual(members[0].name, '10.0.3.13')
         self.assertEqual(members[0].status, 'NORMAL')
-        self.assertEqual(members[0].ip_address, '10.0.3.13')
+        self.assertEqual(members[0].ip, '10.0.3.13')
         self.assertEqual(members[0].port, 9889)
-    
+
     def test_get_pool_member(self):
         member = self.driver.ex_get_pool_member('3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
         self.assertEqual(member.id, '3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
         self.assertEqual(member.name, '10.0.3.13')
         self.assertEqual(member.status, 'NORMAL')
-        self.assertEqual(member.ip_address, '10.0.3.13')
+        self.assertEqual(member.ip, '10.0.3.13')
         self.assertEqual(member.port, 9889)
 
+
 class DimensionDataMockHttp(MockHttp):
 
     fixtures = LoadBalancerFileFixtures('dimensiondata')
@@ -144,7 +283,7 @@ class DimensionDataMockHttp(MockHttp):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool_4d360b1f_bc2c_4ab7_9884_1f03ba2768f7.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
-    
+
     def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember(self, method, url, body, headers):
         body = self.fixtures.load(
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember.xml')
@@ -155,6 +294,36 @@ class DimensionDataMockHttp(MockHttp):
             'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember_3dd806a2_c2c8_4c0c_9a4f_5219ea9266c0.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createPool(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createPool.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createNode(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createNode.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_addPoolMember(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_addPoolMember.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createVirtualListener(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_createVirtualListener.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_removePoolMember(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_removePoolMember.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteVirtualListener(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_deleteVirtualListener.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
 
 if __name__ == '__main__':
     sys.exit(unittest.main())


[05/21] libcloud git commit: [LIBCLOUD-736] Updated missing errors from flake

Posted by to...@apache.org.
[LIBCLOUD-736] Updated missing errors from flake


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

Branch: refs/heads/trunk
Commit: 8e062c0b4515b507e41a676dd3ad502aaa91b2f9
Parents: 02ee35a
Author: Anthony Shaw <an...@gmail.com>
Authored: Tue Aug 25 16:58:33 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Tue Aug 25 16:58:33 2015 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/dimensiondata.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/8e062c0b/libcloud/compute/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py
index 50166e2..8f0f71d 100644
--- a/libcloud/compute/drivers/dimensiondata.py
+++ b/libcloud/compute/drivers/dimensiondata.py
@@ -30,7 +30,7 @@ from libcloud.compute.base import NodeDriver, Node
 from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
 from libcloud.common.types import LibcloudError, InvalidCredsError
 from libcloud.common.base import ConnectionUserAndKey, XmlResponse
-from libcloud.utils.xml import fixxpath, findtext, findall, findattr
+from libcloud.utils.xml import fixxpath, findtext, findall
 from libcloud.compute.types import NodeState, Provider
 
 # Roadmap / TODO:
@@ -660,8 +660,8 @@ class DimensionDataNodeDriver(NodeDriver):
         :return: a list of DimensionDataNetwork objects
         :rtype: ``list`` of :class:`DimensionDataNetwork`
         """
-        response = self.connection.request_with_orgId_api_2('network/networkDomain') \
-                                  .object
+        response = self.connection \
+            .request_with_orgId_api_2('network/networkDomain').object
         return self._to_network_domains(response)
 
     def ex_list_vlans(self):


[16/21] libcloud git commit: Merge branch 'trunk' into LIBCLOUD-737_Create_Dimension_Data_Load_Balancing_driver

Posted by to...@apache.org.
Merge branch 'trunk' into LIBCLOUD-737_Create_Dimension_Data_Load_Balancing_driver

Conflicts:
	libcloud/compute/drivers/dimensiondata.py


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

Branch: refs/heads/trunk
Commit: 19ccf589aca2e527c18595558ff07bf13209bbf5
Parents: ed798ea 18d280f
Author: Anthony Shaw <an...@gmail.com>
Authored: Sun Aug 30 21:58:20 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Sun Aug 30 21:58:20 2015 +1000

----------------------------------------------------------------------
 CHANGES.rst                                     |  36 +++
 contrib/trigger_rtd_build.py                    |   2 +-
 .../_supported_methods_block_storage.rst        |   2 +-
 docs/dns/_supported_methods.rst                 |   2 +
 docs/dns/_supported_providers.rst               |   2 +
 docs/dns/drivers/auroradns.rst                  |  63 +++++
 .../dns/auroradns/enable_disable_record.py      |  13 +
 .../dns/auroradns/instantiate_driver.py         |   6 +
 docs/storage/_supported_methods_cdn.rst         |   2 +
 docs/storage/_supported_methods_main.rst        |   2 +
 docs/storage/_supported_providers.rst           |   2 +
 libcloud/common/rackspace.py                    |   2 +-
 libcloud/compute/drivers/azure.py               |  19 +-
 libcloud/dns/drivers/auroradns.py               | 256 +++++++++++++++++++
 libcloud/dns/providers.py                       |   4 +-
 libcloud/dns/types.py                           |   1 +
 libcloud/storage/drivers/local.py               |  21 +-
 libcloud/storage/drivers/s3.py                  |  11 +
 libcloud/storage/providers.py                   |   2 +
 libcloud/storage/types.py                       |   1 +
 libcloud/test/storage/test_local.py             |  16 +-
 tox.ini                                         |   1 +
 22 files changed, 434 insertions(+), 32 deletions(-)
----------------------------------------------------------------------



[03/21] libcloud git commit: [LIBCLOUD-736] Updated fixtures to match deploy and list tests.

Posted by to...@apache.org.
[LIBCLOUD-736] Updated fixtures to match deploy and list tests.


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

Branch: refs/heads/trunk
Commit: fd43de26b423ab9c59622dfc8f7d2cbedc923459
Parents: 0ba9ae4
Author: Anthony Shaw <an...@gmail.com>
Authored: Tue Aug 25 16:42:37 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Tue Aug 25 16:42:37 2015 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/dimensiondata.py       | 20 ++++++++++----------
 ...745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml |  9 +++++++--
 2 files changed, 17 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/fd43de26/libcloud/compute/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py
index 9819111..8ccfc8f 100644
--- a/libcloud/compute/drivers/dimensiondata.py
+++ b/libcloud/compute/drivers/dimensiondata.py
@@ -755,7 +755,7 @@ class DimensionDataNodeDriver(NodeDriver):
         else:
             state = NodeState.TERMINATED
 
-        status = self._to_status(element.find(fixxpath('state', TYPES_URN)))
+        status = self._to_status(element.find(fixxpath('progress', TYPES_URN)))
 
         extra = {
             'description': findtext(element, 'description', TYPES_URN),
@@ -775,7 +775,7 @@ class DimensionDataNodeDriver(NodeDriver):
                                       .get('family'),
             'OS_displayName': element.find(fixxpath('operatingSystem', TYPES_URN))
                                       .get('displayName'),
-            'status': status,
+            'status': status
         }
 
         public_ip = findtext(element, 'publicIpAddress', TYPES_URN)
@@ -795,33 +795,33 @@ class DimensionDataNodeDriver(NodeDriver):
     def _to_status(self, element):
         if element is None:
             return DimensionDataStatus()
-        s = DimensionDataStatus(action=findtext(element, 'action', SERVER_NS),
+        s = DimensionDataStatus(action=findtext(element, 'action', TYPES_URN),
                                 request_time=findtext(
                                     element,
                                     'requestTime',
-                                    SERVER_NS),
+                                    TYPES_URN),
                                 user_name=findtext(
                                     element,
                                     'userName',
-                                    SERVER_NS),
+                                    TYPES_URN),
                                 number_of_steps=findtext(
                                     element,
                                     'numberOfSteps',
-                                    SERVER_NS),
+                                    TYPES_URN),
                                 step_name=findtext(
                                     element,
                                     'step/name',
-                                    SERVER_NS),
+                                    TYPES_URN),
                                 step_number=findtext(
                                     element,
                                     'step_number',
-                                    SERVER_NS),
+                                    TYPES_URN),
                                 step_percent_complete=findtext(
                                     element,
                                     'step/percentComplete',
-                                    SERVER_NS),
+                                    TYPES_URN),
                                 failure_reason=findtext(
                                     element,
                                     'failureReason',
-                                    SERVER_NS))
+                                    TYPES_URN))
         return s

http://git-wip-us.apache.org/repos/asf/libcloud/blob/fd43de26/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml
index bc98272..64c691a 100644
--- a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml
@@ -2,8 +2,8 @@
 <servers
 xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="1"
 totalCount="2" pageSize="250">
-<Server id="d577a691-e116-4913-a440-022d2729fc84" datacenterId="NA9">
-<name>Test Server</name>
+<Server id="e75ead52-692f-4314-8725-c8a4f4d13a87" datacenterId="NA9">
+<name>test2</name>
 <description>Test Description</description>
 <operatingSystem id="REDHAT664" displayName="REDHAT6/64"
 family="UNIX"/>
@@ -22,6 +22,11 @@ state="NORMAL"/>
 <deployed>true</deployed>
 <started>true</started>
 <state>NORMAL</state>
+<progress>
+<action>DEPLOY_SERVER</action>
+<requestTime>2015-03-06T18:05:33.000Z</requestTime>
+<userName>myuser</userName>
+</progress>
 <machineStatus name="vmwareToolsVersionStatus" value="CURRENT"/>
 <machineStatus name="vmwareToolsRunningStatus" value="RUNNING"/>
 <machineStatus name="vmwareToolsApiVersion" value="9354"/>


[15/21] libcloud git commit: Merge remote-tracking branch 'libcloud/trunk' into trunk

Posted by to...@apache.org.
Merge remote-tracking branch 'libcloud/trunk' into trunk


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

Branch: refs/heads/trunk
Commit: 18d280f38632018552fe4c98c2afd4ad79d698d0
Parents: 9a9fafe f625732
Author: Anthony Shaw <an...@gmail.com>
Authored: Sun Aug 30 21:55:58 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Sun Aug 30 21:55:58 2015 +1000

----------------------------------------------------------------------
 CHANGES.rst                                     |  36 ++
 contrib/trigger_rtd_build.py                    |   2 +-
 .../_supported_methods_block_storage.rst        |   2 +-
 docs/dns/_supported_methods.rst                 |   2 +
 docs/dns/_supported_providers.rst               |   2 +
 docs/dns/drivers/auroradns.rst                  |  63 +++
 .../dns/auroradns/enable_disable_record.py      |  13 +
 .../dns/auroradns/instantiate_driver.py         |   6 +
 docs/storage/_supported_methods_cdn.rst         |   2 +
 docs/storage/_supported_methods_main.rst        |   2 +
 docs/storage/_supported_providers.rst           |   2 +
 libcloud/common/rackspace.py                    |   2 +-
 libcloud/compute/drivers/azure.py               |  19 +-
 libcloud/compute/drivers/dimensiondata.py       | 379 ++++++++++++++-----
 libcloud/dns/drivers/auroradns.py               | 256 +++++++++++++
 libcloud/dns/providers.py                       |   4 +-
 libcloud/dns/types.py                           |   1 +
 libcloud/storage/drivers/local.py               |  21 +-
 libcloud/storage/drivers/s3.py                  |  11 +
 libcloud/storage/providers.py                   |   2 +
 libcloud/storage/types.py                       |   1 +
 ...c_8dabe5a7d0e4_infrastructure_datacenter.xml |  44 +++
 ..._9cbc_8dabe5a7d0e4_network_networkDomain.xml |  13 +
 ...2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan.xml |  17 +
 ...8a_9cbc_8dabe5a7d0e4_server_deleteServer.xml |   9 +
 ...5a7d0e4_server_deleteServer_RESOURCEBUSY.xml |   8 +
 ..._9cbc_8dabe5a7d0e4_server_powerOffServer.xml |   8 +
 ...5a7d0e4_server_powerOffServer_INPROGRESS.xml |   8 +
 ...8a_9cbc_8dabe5a7d0e4_server_rebootServer.xml |   8 +
 ...5a7d0e4_server_rebootServer_RESOURCEBUSY.xml |   7 +
 ...d8a_9cbc_8dabe5a7d0e4_server_resetServer.xml |   8 +
 ...745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml |  64 ++++
 ..._9cbc_8dabe5a7d0e4_server_shutdownServer.xml |   8 +
 ...5a7d0e4_server_shutdownServer_INPROGRESS.xml |   8 +
 ...d8a_9cbc_8dabe5a7d0e4_server_startServer.xml |   8 +
 ...abe5a7d0e4_server_startServer_INPROGRESS.xml |   8 +
 ...8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml |   2 +-
 .../dimensiondata/oec_0_9_base_image.xml        | 140 +------
 libcloud/test/compute/test_dimensiondata.py     | 114 +++++-
 libcloud/test/storage/test_local.py             |  16 +-
 tox.ini                                         |   1 +
 41 files changed, 1070 insertions(+), 257 deletions(-)
----------------------------------------------------------------------



[02/21] libcloud git commit: [LIBCLOUD-736] Updated driver to use 2.0 for all new API calls, start/stop/restart server. list servers using new API, updated extra calls for VLAN and network domain. Fixed up unit tests and added new fixtures

Posted by to...@apache.org.
[LIBCLOUD-736] Updated driver to use 2.0 for all new API calls, start/stop/restart server. list servers using new API, updated extra calls for VLAN and network domain. Fixed up unit tests and added new fixtures


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

Branch: refs/heads/trunk
Commit: 0ba9ae48c6aed9d94a0cf1b0e57c995e6ca71f37
Parents: 9a9fafe
Author: Anthony Shaw <an...@gmail.com>
Authored: Tue Aug 25 16:42:13 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Tue Aug 25 16:42:13 2015 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/dimensiondata.py       | 312 ++++++++++++++-----
 ...c_8dabe5a7d0e4_infrastructure_datacenter.xml |  44 +++
 ..._9cbc_8dabe5a7d0e4_network_networkDomain.xml |  13 +
 ...2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan.xml |  17 +
 ...8a_9cbc_8dabe5a7d0e4_server_deleteServer.xml |   9 +
 ...5a7d0e4_server_deleteServer_RESOURCEBUSY.xml |   8 +
 ..._9cbc_8dabe5a7d0e4_server_powerOffServer.xml |   8 +
 ...5a7d0e4_server_powerOffServer_INPROGRESS.xml |   8 +
 ...8a_9cbc_8dabe5a7d0e4_server_rebootServer.xml |   8 +
 ...5a7d0e4_server_rebootServer_RESOURCEBUSY.xml |   7 +
 ...d8a_9cbc_8dabe5a7d0e4_server_resetServer.xml |   8 +
 ...745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml |  59 ++++
 ..._9cbc_8dabe5a7d0e4_server_shutdownServer.xml |   8 +
 ...5a7d0e4_server_shutdownServer_INPROGRESS.xml |   8 +
 ...d8a_9cbc_8dabe5a7d0e4_server_startServer.xml |   8 +
 ...abe5a7d0e4_server_startServer_INPROGRESS.xml |   8 +
 ...8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml |   2 +-
 .../dimensiondata/oec_0_9_base_image.xml        | 140 +--------
 libcloud/test/compute/test_dimensiondata.py     | 120 ++++++-
 19 files changed, 583 insertions(+), 212 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/compute/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py
index 0a95255..9819111 100644
--- a/libcloud/compute/drivers/dimensiondata.py
+++ b/libcloud/compute/drivers/dimensiondata.py
@@ -30,7 +30,7 @@ from libcloud.compute.base import NodeDriver, Node
 from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
 from libcloud.common.types import LibcloudError, InvalidCredsError
 from libcloud.common.base import ConnectionUserAndKey, XmlResponse
-from libcloud.utils.xml import fixxpath, findtext, findall
+from libcloud.utils.xml import fixxpath, findtext, findall, findattr
 from libcloud.compute.types import NodeState, Provider
 
 # Roadmap / TODO:
@@ -52,6 +52,9 @@ GENERAL_NS = NAMESPACE_BASE + "/general"
 IPPLAN_NS = NAMESPACE_BASE + "/ipplan"
 WHITELABEL_NS = NAMESPACE_BASE + "/whitelabel"
 
+# API 2.0 Namespaces and URNs
+TYPES_URN = "urn:didata.com:api:cloud:types"
+
 # API end-points
 API_ENDPOINTS = {
     'dd-na': {
@@ -104,9 +107,10 @@ class DimensionDataResponse(XmlResponse):
 
         body = self.parse_body()
 
+        # TODO: The path is not fixed as server. 
         if self.status == httplib.BAD_REQUEST:
-            code = findtext(body, 'resultCode', SERVER_NS)
-            message = findtext(body, 'resultDetail', SERVER_NS)
+            code = findtext(body, 'responseCode', SERVER_NS)
+            message = findtext(body, 'message', SERVER_NS)
             raise DimensionDataAPIException(code,
                                             message,
                                             driver=DimensionDataNodeDriver)
@@ -133,8 +137,11 @@ class DimensionDataConnection(ConnectionUserAndKey):
     Connection class for the DimensionData driver
     """
 
-    api_path = '/oec'
-    api_version = '0.9'
+    api_path_version_1 = '/oec'
+    api_path_version_2 = '/caas'
+    api_version_1 = '0.9'
+    api_version_2 = '2.0'
+    
     _orgId = None
     responseCls = DimensionDataResponse
 
@@ -159,31 +166,58 @@ class DimensionDataConnection(ConnectionUserAndKey):
                                                  self.key))).decode('utf-8'))
         return headers
 
-    def request(self, action, params=None, data='',
+    def request_api_1(self, action, params=None, data='',
                 headers=None, method='GET'):
-        action = "%s/%s/%s" % (self.api_path, self.api_version, action)
+        action = "%s/%s/%s" % (self.api_path_version_1, self.api_version_1, action)
 
         return super(DimensionDataConnection, self).request(
             action=action,
             params=params, data=data,
             method=method, headers=headers)
+    
+    def request_api_2(self, path, action, params=None, data='',
+                headers=None, method='GET'):
+        action = "%s/%s/%s/%s" % (self.api_path_version_2, self.api_version_2, path, action)
 
-    def request_with_orgId(self, action, params=None, data='',
+        return super(DimensionDataConnection, self).request(
+            action=action,
+            params=params, data=data,
+            method=method, headers=headers)
+
+    def request_with_orgId_api_1(self, action, params=None, data='',
+                           headers=None, method='GET'):
+        action = "%s/%s" % (self.get_resource_path_api_1(), action)
+
+        return super(DimensionDataConnection, self).request(
+            action=action,
+            params=params, data=data,
+            method=method, headers=headers)
+    
+    def request_with_orgId_api_2(self, action, params=None, data='',
                            headers=None, method='GET'):
-        action = "%s/%s" % (self.get_resource_path(), action)
+        action = "%s/%s" % (self.get_resource_path_api_2(), action)
 
         return super(DimensionDataConnection, self).request(
             action=action,
             params=params, data=data,
             method=method, headers=headers)
 
-    def get_resource_path(self):
+    def get_resource_path_api_1(self):
         """
         This method returns a resource path which is necessary for referencing
         resources that require a full path instead of just an ID, such as
         networks, and customer snapshots.
         """
-        return ("%s/%s/%s" % (self.api_path, self.api_version,
+        return ("%s/%s/%s" % (self.api_path_version_1, self.api_version_1,
+                              self._get_orgId()))
+
+    def get_resource_path_api_2(self):
+        """
+        This method returns a resource path which is necessary for referencing
+        resources that require a full path instead of just an ID, such as
+        networks, and customer snapshots.
+        """
+        return ("%s/%s/%s" % (self.api_path_version_2, self.api_version_2,
                               self._get_orgId()))
 
     def _get_orgId(self):
@@ -193,7 +227,7 @@ class DimensionDataConnection(ConnectionUserAndKey):
         of the other API functions
         """
         if self._orgId is None:
-            body = self.request('myaccount').object
+            body = self.request_api_1('myaccount').object
             self._orgId = findtext(body, 'orgId', DIRECTORY_NS)
         return self._orgId
 
@@ -250,6 +284,39 @@ class DimensionDataNetwork(object):
                 % (self.id, self.name, self.description, self.location,
                    self.private_net, self.multicast))
 
+class DimensionDataNetworkDomain(object):
+    """
+    DimensionData network domain with location.
+    """
+
+    def __init__(self, id, name, description, location, status):
+        self.id = str(id)
+        self.name = name
+        self.description = description
+        self.location = location
+        self.status = status
+
+    def __repr__(self):
+        return (('<DimensionDataNetworkDomain: id=%s, name=%s, description=%s, '
+                 'location=%s, status=%s>')
+                % (self.id, self.name, self.description, self.location, self.status))
+
+class DimensionDataVlan(object):
+    """
+    DimensionData VLAN.
+    """
+
+    def __init__(self, id, name, description, location, status):
+        self.id = str(id)
+        self.name = name
+        self.location = location
+        self.description = description
+        self.status = status
+
+    def __repr__(self):
+        return (('<DimensionDataNetworkDomain: id=%s, name=%s, description=%s, '
+                 'location=%s, status=%s>')
+                % (self.id, self.name, self.description, self.location, self.status))
 
 class DimensionDataNodeDriver(NodeDriver):
     """
@@ -332,14 +399,14 @@ class DimensionDataNodeDriver(NodeDriver):
 
         if not isinstance(ex_network, DimensionDataNetwork):
             raise ValueError('ex_network must be of DimensionDataNetwork type')
-        vlanResourcePath = "%s/%s" % (self.connection.get_resource_path(),
+        vlanResourcePath = "%s/%s" % (self.connection.get_resource_path_api_1(),
                                       ex_network.id)
 
         imageResourcePath = None
         if 'resourcePath' in image.extra:
             imageResourcePath = image.extra['resourcePath']
         else:
-            imageResourcePath = "%s/%s" % (self.connection.get_resource_path(),
+            imageResourcePath = "%s/%s" % (self.connection.get_resource_path_api_1(),
                                            image.id)
 
         server_elm = ET.Element('Server', {'xmlns': SERVER_NS})
@@ -350,7 +417,7 @@ class DimensionDataNodeDriver(NodeDriver):
         ET.SubElement(server_elm, "administratorPassword").text = password
         ET.SubElement(server_elm, "isStarted").text = str(ex_is_started)
 
-        self.connection.request_with_orgId('server',
+        self.connection.request_with_orgId_api_1('server',
                                            method='POST',
                                            data=ET.tostring(server_elm)).object
 
@@ -366,23 +433,23 @@ class DimensionDataNodeDriver(NodeDriver):
         return node
 
     def destroy_node(self, node):
-        body = self.connection.request_with_orgId(
-            'server/%s?delete' % (node.id)).object
-
-        result = findtext(body, 'result', GENERAL_NS)
-        return result == 'SUCCESS'
+        request_elm = ET.Element('deleteServer', {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/deleteServer', method='POST', data=ET.tostring(request_elm) ).object
+        result = findtext(body, 'responseCode', TYPES_URN)
+        return result == 'IN_PROGRESS'
 
     def reboot_node(self, node):
-        body = self.connection.request_with_orgId(
-            'server/%s?restart' % (node.id)).object
-        result = findtext(body, 'result', GENERAL_NS)
-        return result == 'SUCCESS'
+        request_elm = ET.Element('rebootServer', {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/rebootServer', method='POST', data=ET.tostring(request_elm) ).object
+        result = findtext(body, 'responseCode', TYPES_URN)
+        return result == 'IN_PROGRESS'
 
     def list_nodes(self):
         nodes = self._to_nodes(
-            self.connection.request_with_orgId('server/deployed').object)
-        nodes.extend(self._to_nodes(
-            self.connection.request_with_orgId('server/pendingDeploy').object))
+            self.connection.request_with_orgId_api_2('server/server').object)
+      
         return nodes
 
     def list_images(self, location=None):
@@ -394,9 +461,16 @@ class DimensionDataNodeDriver(NodeDriver):
         @inherits: :class:`NodeDriver.list_images`
         """
         return self._to_base_images(
-            self.connection.request('base/image').object)
+            self.connection.request_api_1('base/image').object)
 
     def list_sizes(self, location=None):
+        """
+        return a list of available sizes
+            Currently, the size of the node is dictated by the chosen OS base
+            image, they cannot be set explicitly.
+
+        @inherits: :class:`NodeDriver.list_sizes`
+        """
         return [
             NodeSize(id=1,
                      name="default",
@@ -415,7 +489,7 @@ class DimensionDataNodeDriver(NodeDriver):
         @inherits: :class:`NodeDriver.list_locations`
         """
         return self._to_locations(
-            self.connection.request_with_orgId('datacenter').object)
+            self.connection.request_with_orgId_api_2('infrastructure/datacenter').object)
 
     def list_networks(self, location=None):
         """
@@ -430,7 +504,7 @@ class DimensionDataNodeDriver(NodeDriver):
         :rtype: ``list`` of :class:`DimensionDataNetwork`
         """
         return self._to_networks(
-            self.connection.request_with_orgId('networkWithLocation').object)
+            self.connection.request_with_orgId_api_1('networkWithLocation').object)
 
     def _to_base_images(self, object):
         images = []
@@ -476,10 +550,11 @@ class DimensionDataNodeDriver(NodeDriver):
 
         :rtype: ``bool``
         """
-        body = self.connection.request_with_orgId(
-            'server/%s?start' % node.id).object
-        result = findtext(body, 'result', GENERAL_NS)
-        return result == 'SUCCESS'
+        request_elm = ET.Element('startServer', {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/startServer', method='POST', data=ET.tostring(request_elm) ).object
+        result = findtext(body, 'responseCode', TYPES_URN)
+        return result == 'IN_PROGRESS'
 
     def ex_shutdown_graceful(self, node):
         """
@@ -493,10 +568,11 @@ class DimensionDataNodeDriver(NodeDriver):
 
         :rtype: ``bool``
         """
-        body = self.connection.request_with_orgId(
-            'server/%s?shutdown' % (node.id)).object
-        result = findtext(body, 'result', GENERAL_NS)
-        return result == 'SUCCESS'
+        request_elm = ET.Element('shutdownServer', {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/shutdownServer', method='POST', data=ET.tostring(request_elm) ).object
+        result = findtext(body, 'responseCode', TYPES_URN)
+        return result == 'IN_PROGRESS'
 
     def ex_power_off(self, node):
         """
@@ -510,10 +586,29 @@ class DimensionDataNodeDriver(NodeDriver):
 
         :rtype: ``bool``
         """
-        body = self.connection.request_with_orgId(
-            'server/%s?poweroff' % node.id).object
-        result = findtext(body, 'result', GENERAL_NS)
-        return result == 'SUCCESS'
+        request_elm = ET.Element('powerOffServer', {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/powerOffServer', method='POST', data=ET.tostring(request_elm) ).object
+        result = findtext(body, 'responseCode', TYPES_URN)
+        return result == 'IN_PROGRESS'
+
+    def ex_reset(self, node):
+        """
+        This function will abruptly reset a server.  Unlike
+        reboot_node, success ensures the node will restart but some OS
+        and application configurations may be adversely affected by the
+        equivalent of pulling the power plug out of the machine.
+
+        :param      node: Node which should be used
+        :type       node: :class:`Node`
+
+        :rtype: ``bool``
+        """
+        request_elm = ET.Element('resetServer', {'xmlns': TYPES_URN, 'id': node.id})
+        body = self.connection.request_with_orgId_api_2(
+            'server/resetServer', method='POST', data=ET.tostring(request_elm) ).object
+        result = findtext(body, 'responseCode', TYPES_URN)
+        return result == 'IN_PROGRESS'
 
     def ex_list_networks(self):
         """
@@ -523,10 +618,33 @@ class DimensionDataNodeDriver(NodeDriver):
         :return: a list of DimensionDataNetwork objects
         :rtype: ``list`` of :class:`DimensionDataNetwork`
         """
-        response = self.connection.request_with_orgId('networkWithLocation') \
+        response = self.connection.request_with_orgId_api_1('networkWithLocation') \
                                   .object
         return self._to_networks(response)
 
+    def ex_list_network_domains(self):
+        """
+        List networks deployed across all data center locations for your
+        organization.  The response includes the location of each network.
+
+        :return: a list of DimensionDataNetwork objects
+        :rtype: ``list`` of :class:`DimensionDataNetwork`
+        """
+        response = self.connection.request_with_orgId_api_2('network/networkDomain') \
+                                  .object
+        return self._to_network_domains(response)
+
+    def ex_list_vlans(self):
+        """
+        List VLANs available in a given networkDomain
+
+        :return: a list of DimensionDataVlan objects
+        :rtype: ``list`` of :class:`DimensionDataVlan`
+        """
+        response = self.connection.request_with_orgId_api_2('network/vlan') \
+                                  .object
+        return self._to_vlans(response)
+
     def ex_get_location_by_id(self, id):
         """
         Get location by ID.
@@ -569,67 +687,107 @@ class DimensionDataNodeDriver(NodeDriver):
                                  NETWORK_NS),
             multicast=multicast,
             status=status)
+    
+    def _to_network_domains(self, object):
+        network_domains = []
+        for element in findall(object, 'networkDomain', TYPES_URN):
+            network_domains.append(self._to_network_domain(element))
+
+        return network_domains
+
+    def _to_network_domain(self, element):
+        status = self._to_status(element.find(fixxpath('state', TYPES_URN)))
+
+        location_id = element.get('datacenter')
+        location = self.ex_get_location_by_id(location_id)
+
+        return DimensionDataNetworkDomain(
+            id=element.get('id'),
+            name=findtext(element, 'name', TYPES_URN),
+            description=findtext(element, 'description',
+                                 TYPES_URN),
+            location=location,
+            status=status)
+
+    def _to_vlans(self, object):
+        vlans = []
+        for element in findall(object, 'vlan', TYPES_URN):
+            vlans.append(self._to_vlan(element))
+
+        return vlans
+
+    def _to_vlan(self, element):
+        status = self._to_status(element.find(fixxpath('state', TYPES_URN)))
+        
+        location_id = element.get('location')
+        location = self.ex_get_location_by_id(location_id)
+        
+        return DimensionDataVlan(
+            id=element.get('id'),
+            name=findtext(element, 'name', TYPES_URN),
+            description=findtext(element, 'description',
+                                 TYPES_URN),
+            location=location,
+            status=status)
 
     def _to_locations(self, object):
         locations = []
-        for element in object.findall(fixxpath('datacenter', DATACENTER_NS)):
+        for element in object.findall(fixxpath('datacenter', TYPES_URN)):
             locations.append(self._to_location(element))
 
         return locations
 
     def _to_location(self, element):
-        l = NodeLocation(id=findtext(element, 'location', DATACENTER_NS),
-                         name=findtext(element, 'displayName', DATACENTER_NS),
-                         country=findtext(element, 'country', DATACENTER_NS),
+        l = NodeLocation(id=element.get('id'),
+                         name=findtext(element, 'displayName', TYPES_URN),
+                         country=findtext(element, 'country', TYPES_URN),
                          driver=self)
         return l
 
     def _to_nodes(self, object):
-        node_elements = object.findall(fixxpath('DeployedServer', SERVER_NS))
-        node_elements.extend(object.findall(
-            fixxpath('PendingDeployServer', SERVER_NS)))
+        node_elements = object.findall(fixxpath('Server', TYPES_URN))
+
         return [self._to_node(el) for el in node_elements]
 
     def _to_node(self, element):
-        if findtext(element, 'isStarted', SERVER_NS) == 'true':
+        if findtext(element, 'started', TYPES_URN) == 'true':
             state = NodeState.RUNNING
         else:
             state = NodeState.TERMINATED
 
-        status = self._to_status(element.find(fixxpath('status', SERVER_NS)))
+        status = self._to_status(element.find(fixxpath('state', TYPES_URN)))
 
         extra = {
-            'description': findtext(element, 'description', SERVER_NS),
-            'sourceImageId': findtext(element, 'sourceImageId', SERVER_NS),
-            'networkId': findtext(element, 'networkId', SERVER_NS),
-            'machineName': findtext(element, 'machineName', SERVER_NS),
-            'deployedTime': findtext(element, 'deployedTime', SERVER_NS),
-            'cpuCount': findtext(element, 'machineSpecification/cpuCount',
-                                 SERVER_NS),
-            'memoryMb': findtext(element, 'machineSpecification/memoryMb',
-                                 SERVER_NS),
-            'osStorageGb': findtext(element,
-                                    'machineSpecification/osStorageGb',
-                                    SERVER_NS),
-            'additionalLocalStorageGb': findtext(
-                element, 'machineSpecification/additionalLocalStorageGb',
-                SERVER_NS),
-            'OS_type': findtext(element,
-                                'machineSpecification/operatingSystem/type',
-                                SERVER_NS),
-            'OS_displayName': findtext(
-                element, 'machineSpecification/operatingSystem/displayName',
-                SERVER_NS),
+            'description': findtext(element, 'description', TYPES_URN),
+            'sourceImageId': findtext(element, 'sourceImageId', TYPES_URN),
+            'networkId': findtext(element, 'networkId', TYPES_URN),
+            'networkDomainId': element.find(fixxpath('networkInfo', TYPES_URN))
+                                      .get('networkDomainId'),
+            'datacenterId': element.get('datacenterId'),
+            'deployedTime': findtext(element, 'createTime', TYPES_URN),
+            'cpuCount': int(findtext(element, 'cpuCount',
+                                 TYPES_URN)),
+            'memoryMb': int(findtext(element, 'memoryGb',
+                                 TYPES_URN)) * 1024,
+            'OS_id': element.find(fixxpath('operatingSystem', TYPES_URN))
+                                      .get('id'),
+            'OS_type': element.find(fixxpath('operatingSystem', TYPES_URN))
+                                      .get('family'),
+            'OS_displayName': element.find(fixxpath('operatingSystem', TYPES_URN))
+                                      .get('displayName'),
             'status': status,
         }
 
-        public_ip = findtext(element, 'publicIpAddress', SERVER_NS)
+        public_ip = findtext(element, 'publicIpAddress', TYPES_URN)
+
+        private_ip = findtext(element, 'networkInfo/primaryNic/privateIpv4',
+                              TYPES_URN)
 
-        n = Node(id=findtext(element, 'id', SERVER_NS),
-                 name=findtext(element, 'name', SERVER_NS),
+        n = Node(id=element.get('id'),
+                 name=findtext(element, 'name', TYPES_URN),
                  state=state,
                  public_ips=[public_ip] if public_ip is not None else [],
-                 private_ips=findtext(element, 'privateIpAddress', SERVER_NS),
+                 private_ips=[private_ip] if private_ip is not None else [],
                  driver=self.connection.driver,
                  extra=extra)
         return n

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_infrastructure_datacenter.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_infrastructure_datacenter.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_infrastructure_datacenter.xml
new file mode 100644
index 0000000..66ae1db
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_infrastructure_datacenter.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<datacenters pageNumber="1" pageCount="1" totalCount="2" pageSize="50"
+xmlns="urn:didata.com:api:cloud:types">
+<datacenter id="NA10" type="MCP 2.0">
+<displayName>US - West</displayName>
+<city>Santa Clara</city>
+<state>California</state>
+<country>US</country>
+<vpnUrl>https://na10.cloud-vpn.net</vpnUrl>
+<ftpsHost>ftps-na.cloud-vpn.net</ftpsHost>
+<networking type="2" maintenanceStatus="NORMAL">
+<!-- 0-to-many optional property elements -->
+<property name="MAX_NODE_CONNECTION_LIMIT" value="100000"/>
+<property name="MAX_NODE_CONNECTION_RATE_LIMIT" value="4000"/>
+<property name="MAX_VIRTUAL_LISTENER_CONNECTION_LIMIT" value="100000"/>
+<property name="MAX_VIRTUAL_LISTENER_CONNECTION_RATE_LIMIT"
+value="4000"/>
+</networking>
+<hypervisor type="VMWARE" maintenanceStatus="PENDING_MAINTENANCE">
+<diskSpeed available="false" default="false" id="ARCHIVE">
+<displayName>Archive Speed</displayName>
+<abbreviation>ARCH</abbreviation>
+<description>Archive Disk Speed</description>
+<unavailableReason>Replaced with HPF and ECN</unavailableReason>
+</diskSpeed>
+<property name="MIN_DISK_SIZE_GB" value="10"/>
+<property name="MAX_DISK_SIZE_GB" value="1000"/>
+<property name="MAX_TOTAL_ADDITIONAL_STORAGE_GB" value="2500"/>
+<property name="MAX_CPU_COUNT" value="8"/>
+<property name="MIN_MEMORY_MB" value="1024"/>
+<property name="MAX_MEMORY_MB" value="65536"/>
+</hypervisor>
+<!-- Optional: if Cloud Backup is enabled at the Data Center it will be returned -->
+<backup type="COMMVAULT" maintenanceStatus="IN_MAINTENANCE">
+<!-- 0-to-many optional property elements -->
+</backup>
+<consoleAccess maintenanceStatus="IN_MAINTENANCE">
+<!-- 0-to-many optional property elements -->
+</consoleAccess>
+<monitoring maintenanceStatus="IN_MAINTENANCE">
+<!-- 0-to-many optional property elements -->
+</monitoring>
+</datacenter>
+</datacenters>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_networkDomain.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_networkDomain.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_networkDomain.xml
new file mode 100644
index 0000000..22680d1
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_networkDomain.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<networkDomains
+xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="1"
+totalCount="1" pageSize="250">
+<networkDomain id="484174a2-ae74-4658-9e56-50fc90e086cf" datacenter="NA10">
+<name>Production Network Domain</name>
+<description></description>
+<type>ESSENTIALS</type>
+<snatIpv4Address>165.180.8.8</snatIpv4Address>
+<createTime>2015-02-12T18:18:14.000Z</createTime>
+<state>NORMAL</state>
+</networkDomain>
+</networkDomains>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan.xml
new file mode 100644
index 0000000..b489284
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<vlans
+xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="1"
+totalCount="1" pageSize="250">
+<vlan id="0e56433f-d808-4669-821d-812769517ff8" location="NA10">
+<networkDomain id="484174a2-ae74-4658-9e56-50fc90e086cf"
+name="Production Network Domain"/>
+<name>Production VLAN</name>
+<description>For hosting our Production Cloud Servers</description>
+<privateIpv4Range address="10.0.3.0" prefixSize="24"/>
+<ipv4GatewayAddress>10.0.3.1</ipv4GatewayAddress>
+<ipv6Range address="2607:f480:1111:1153:0:0:0:0" prefixSize="64"/>
+<ipv6GatewayAddress>2607:f480:1111:1153:0:0:0:1</ipv6GatewayAddress>
+<createTime>2015-02-13T10:56:44.000Z</createTime>
+<state>NORMAL</state>
+</vlan>
+</vlans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer.xml
new file mode 100644
index 0000000..c8e70da
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<response
+xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-03-
+08T05:49:07.774-04:00/f0a53414-e991-4c9b-b52f-5770ff5b606b">
+<operation>DELETE_SERVER</operation>
+<responseCode>IN_PROGRESS</responseCode>
+<message>Request to Delete Server (Id:d577a691-e116-4913-a440-
+022d2729fc84) has been accepted and is being processed</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer_RESOURCEBUSY.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer_RESOURCEBUSY.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer_RESOURCEBUSY.xml
new file mode 100644
index 0000000..2df9e07
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer_RESOURCEBUSY.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<response
+xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-03-
+08T05:49:07.774-04:00/f0a53414-e991-4c9b-b52f-5770ff5b606b">
+<operation>DELETE_SERVER</operation>
+<responseCode>RESOURCE_BUSY</responseCode>
+<message>Server is already busy</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer.xml
new file mode 100644
index 0000000..549ea79
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T11:49:17.375-04:00/d5bb0975-1ade-4350-aaec-24807bdf7038">
+<operation>POWER_OFF_SERVER</operation>
+<responseCode>IN_PROGRESS</responseCode>
+<message>Request to power off Server 'Production Server' has been accepted
+and is being processed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer_INPROGRESS.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer_INPROGRESS.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer_INPROGRESS.xml
new file mode 100644
index 0000000..8ddcca9
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer_INPROGRESS.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T11:49:17.375-04:00/d5bb0975-1ade-4350-aaec-24807bdf7038">
+<operation>POWER_OFF_SERVER</operation>
+<responseCode>RESOURCE_BUSY</responseCode>
+<message>Request to power off Server 'Production Server' has been accepted
+and is being processed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer.xml
new file mode 100644
index 0000000..38f098a
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T09:52:43.365-04:00/5260a4e5-ea21-49f4-909a-22341d8c39cb">
+<operation>REBOOT_SERVER</operation>
+<responseCode>IN_PROGRESS</responseCode>
+<message>Request to reboot Server 'Production Server' has been accepted
+and is being processed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer_RESOURCEBUSY.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer_RESOURCEBUSY.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer_RESOURCEBUSY.xml
new file mode 100644
index 0000000..3defba4
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer_RESOURCEBUSY.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T09:52:43.365-04:00/5260a4e5-ea21-49f4-909a-22341d8c39cb">
+<operation>REBOOT_SERVER</operation>
+<responseCode>RESOURCE_BUSY</responseCode>
+<message>Request to reboot Server 'Production Server' did not work, server is busy.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_resetServer.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_resetServer.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_resetServer.xml
new file mode 100644
index 0000000..ece1a8b
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_resetServer.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T11:37:13.823-04:00/7b264a73-d73b-424c-bec8-5debba8b4626">
+<operation>RESET_SERVER</operation>
+<responseCode>IN_PROGRESS</responseCode>
+<message>Request to reset Server 'Production Server' has been accepted and
+is being processed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml
new file mode 100644
index 0000000..bc98272
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<servers
+xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="1"
+totalCount="2" pageSize="250">
+<Server id="d577a691-e116-4913-a440-022d2729fc84" datacenterId="NA9">
+<name>Test Server</name>
+<description>Test Description</description>
+<operatingSystem id="REDHAT664" displayName="REDHAT6/64"
+family="UNIX"/>
+<cpuCount>1</cpuCount>
+<memoryGb>2</memoryGb>
+<disk id="338c1163-5348-4572-962d-185c97bd0d65" scsiId="0" sizeGb="10"
+speed="STANDARD" state="NORMAL"/>
+<networkInfo networkDomainId="484174a2-ae74-4658-9e56-50fc90e086cf">
+<primaryNic id="4c8d5f67-c6df-421d-b8ac-45dd1b141334"
+privateIpv4="10.0.3.11" ipv6="2607:f480:1111:1153:dee:4666:1130:7484"
+vlanId="0e56433f-d808-4669-821d-812769517ff8" vlanName="Production VLAN"
+state="NORMAL"/>
+</networkInfo>
+<sourceImageId>02250336-de2b-4e99-ab96-78511b7f8f4b</sourceImageId>
+<createTime>2015-02-17T10:59:18.000Z</createTime>
+<deployed>true</deployed>
+<started>true</started>
+<state>NORMAL</state>
+<machineStatus name="vmwareToolsVersionStatus" value="CURRENT"/>
+<machineStatus name="vmwareToolsRunningStatus" value="RUNNING"/>
+<machineStatus name="vmwareToolsApiVersion" value="9354"/>
+</Server>
+<Server id="abadbc7e-9e10-46ca-9d4a-194bcc6b6c16" datacenterId="NA9">
+<name>Production Web Server 2</name>
+<description>This server hosts our production web
+applications.</description>
+<operatingSystem id="REDHAT664" displayName="REDHAT6/64"
+family="UNIX"/>
+<cpuCount>1</cpuCount>
+<memoryGb>2</memoryGb>
+<disk id="338c1163-5348-4572-962d-185c97bd0d65" scsiId="0" sizeGb="10"
+speed="STANDARD" state="NORMAL"/>
+<networkInfo networkDomainId="484174a2-ae74-4658-9e56-50fc90e086cf">
+<primaryNic id="4c8d5f67-c6df-421d-b8ac-45dd1b141334"
+privateIpv4="10.0.3.11" ipv6="2607:f480:1111:1153:dee:4666:1130:7484"
+vlanId="0e56433f-d808-4669-821d-812769517ff8" vlanName="Production VLAN"
+state="NORMAL"/>
+</networkInfo>
+<sourceImageId>02250336-de2b-4e99-ab96-78511b7f8f4b</sourceImageId>
+<createTime>2015-02-17T10:59:18.000Z</createTime>
+<deployed>true</deployed>
+<started>true</started>
+<state>PENDING_CHANGE</state>
+<progress>
+<action>SHUTDOWN_SERVER</action>
+<requestTime>2015-03-06T18:05:33.000Z</requestTime>
+<userName>myuser</userName>
+</progress>
+<machineStatus name="vmwareToolsVersionStatus" value="CURRENT"/>
+<machineStatus name="vmwareToolsRunningStatus" value="RUNNING"/>
+<machineStatus name="vmwareToolsApiVersion" value="9354"/>
+</Server>
+</servers>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer.xml
new file mode 100644
index 0000000..937cb0d
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T09:06:01.949-04:00/fd2650a9-3473-41eb-9c6e-1eef29c0bb27">
+<operation>SHUTDOWN_SERVER</operation>
+<responseCode>IN_PROGRESS</responseCode>
+<message>Request to shutdown Server 'Production Server' has been accepted
+and is being processed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer_INPROGRESS.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer_INPROGRESS.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer_INPROGRESS.xml
new file mode 100644
index 0000000..386489c
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer_INPROGRESS.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T09:06:01.949-04:00/fd2650a9-3473-41eb-9c6e-1eef29c0bb27">
+<operation>SHUTDOWN_SERVER</operation>
+<responseCode>RESOURCE_BUSY</responseCode>
+<message>Request to shutdown Server 'Production Server' has been accepted
+and is being processed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer.xml
new file mode 100644
index 0000000..4fb4589
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T08:27:00.176-04:00/14b0a61f-7e85-49c9-8e7e-146fa3e562b7">
+<operation>START_SERVER</operation>
+<responseCode>IN_PROGRESS</responseCode>
+<message>Request to start Server 'Production Server' has been accepted and
+is being processed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer_INPROGRESS.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer_INPROGRESS.xml b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer_INPROGRESS.xml
new file mode 100644
index 0000000..f5c3070
--- /dev/null
+++ b/libcloud/test/compute/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer_INPROGRESS.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<response xmlns="urn:didata.com:api:cloud:types" requestId="NA9/2015-08-
+12T08:27:00.176-04:00/14b0a61f-7e85-49c9-8e7e-146fa3e562b7">
+<operation>START_SERVER</operation>
+<responseCode>RESOURCE_BUSY</responseCode>
+<message>Request to start Server 'Production Server' has been accepted and
+is being processed.</message>
+</response>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml b/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml
index ca27554..88364b6 100644
--- a/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml
+++ b/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml
@@ -4,7 +4,7 @@
         <ns4:id>53b4c05b-341e-4ac3-b688-bdd74e53ca9b</ns4:id>
         <ns4:name>test-net1</ns4:name>
         <ns4:description>test-net1 description</ns4:description>
-        <ns4:location>NA1</ns4:location>
+        <ns4:location>NA10</ns4:location>
         <ns4:privateNet>10.162.1.0</ns4:privateNet>
         <ns4:multicast>false</ns4:multicast>
     </ns4:network>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_base_image.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_base_image.xml b/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_base_image.xml
index 3be14f0..d758343 100644
--- a/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_base_image.xml
+++ b/libcloud/test/compute/fixtures/dimensiondata/oec_0_9_base_image.xml
@@ -9,7 +9,7 @@
             <type>UNIX</type>
             <displayName>REDHAT5/64</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>1</cpuCount>
         <memory>2048</memory>
         <osStorage>10</osStorage>
@@ -25,7 +25,7 @@
             <type>UNIX</type>
             <displayName>REDHAT5/64</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>2</cpuCount>
         <memory>4096</memory>
         <osStorage>10</osStorage>
@@ -41,7 +41,7 @@
             <type>UNIX</type>
             <displayName>REDHAT5/64</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>4</cpuCount>
         <memory>6144</memory>
         <osStorage>10</osStorage>
@@ -57,7 +57,7 @@
             <type>UNIX</type>
             <displayName>REDHAT5/32</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>1</cpuCount>
         <memory>2048</memory>
         <osStorage>10</osStorage>
@@ -73,7 +73,7 @@
             <type>UNIX</type>
             <displayName>UBUNTU8/64</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>2</cpuCount>
         <memory>4096</memory>
         <osStorage>10</osStorage>
@@ -89,7 +89,7 @@
             <type>WINDOWS</type>
             <displayName>WIN2008R2E/64</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>2</cpuCount>
         <memory>4096</memory>
         <osStorage>50</osStorage>
@@ -105,7 +105,7 @@
             <type>WINDOWS</type>
             <displayName>WIN2008R2E/64</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>4</cpuCount>
         <memory>8192</memory>
         <osStorage>50</osStorage>
@@ -121,7 +121,7 @@
             <type>WINDOWS</type>
             <displayName>WIN2008R2S/64</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>2</cpuCount>
         <memory>4096</memory>
         <osStorage>50</osStorage>
@@ -137,7 +137,7 @@
             <type>WINDOWS</type>
             <displayName>WIN2008S/32</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>1</cpuCount>
         <memory>2048</memory>
         <osStorage>50</osStorage>
@@ -153,7 +153,7 @@
             <type>WINDOWS</type>
             <displayName>WIN2008S/32</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>2</cpuCount>
         <memory>4096</memory>
         <osStorage>50</osStorage>
@@ -169,7 +169,7 @@
             <type>WINDOWS</type>
             <displayName>WIN2008S/32</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>4</cpuCount>
         <memory>4096</memory>
         <osStorage>50</osStorage>
@@ -185,7 +185,7 @@
             <type>WINDOWS</type>
             <displayName>WIN2008E/32</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>2</cpuCount>
         <memory>4096</memory>
         <osStorage>50</osStorage>
@@ -201,7 +201,7 @@
             <type>UNIX</type>
             <displayName>REDHAT4/32</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>1</cpuCount>
         <memory>2048</memory>
         <osStorage>10</osStorage>
@@ -217,123 +217,11 @@
             <type>UNIX</type>
             <displayName>CENTOS5/32</displayName>
         </operatingSystem>
-        <location>NA1</location>
+        <location>NA10</location>
         <cpuCount>1</cpuCount>
         <memory>2048</memory>
         <osStorage>10</osStorage>
         <additionalLocalStorage>0</additionalLocalStorage>
         <created>1970-01-01T00:00:02.010Z</created>
     </ServerImage>
-    <ServerImage>
-        <id>52ed91da-ebea-11df-bdc1-001517c46384</id>
-        <resourcePath>/oec/base/image/52ed91da-ebea-11df-bdc1-001517c46384</resourcePath>
-        <name>CentOS 5.5 64-bit 1 CPU</name>
-        <description>CentOS release 5.5, 64-bit</description>
-        <operatingSystem>
-            <type>UNIX</type>
-            <displayName>CENTOS5/64</displayName>
-        </operatingSystem>
-        <location>NA1</location>
-        <cpuCount>1</cpuCount>
-        <memory>2048</memory>
-        <osStorage>10</osStorage>
-        <additionalLocalStorage>0</additionalLocalStorage>
-        <created>1970-01-01T00:00:02.010Z</created>
-    </ServerImage>
-    <ServerImage>
-        <id>52ed766e-ebea-11df-bdc1-001517c46384</id>
-        <resourcePath>/oec/base/image/52ed766e-ebea-11df-bdc1-001517c46384</resourcePath>
-        <name>Win2003 Ent 32-bit 1 CPU</name>
-        <description>Windows 2003 Enterprise SP2 32-bit</description>
-        <operatingSystem>
-            <type>WINDOWS</type>
-            <displayName>WIN2003E/32</displayName>
-        </operatingSystem>
-        <location>NA1</location>
-        <cpuCount>1</cpuCount>
-        <memory>2048</memory>
-        <osStorage>16</osStorage>
-        <additionalLocalStorage>0</additionalLocalStorage>
-        <created>1970-01-01T00:00:02.010Z</created>
-    </ServerImage>
-    <ServerImage>
-        <id>52ed7876-ebea-11df-bdc1-001517c46384</id>
-        <resourcePath>/oec/base/image/52ed7876-ebea-11df-bdc1-001517c46384</resourcePath>
-        <name>Win2003 Ent 32-bit 2 CPU</name>
-        <description>Windows 2003 Enterprise SP2 32-bit</description>
-        <operatingSystem>
-            <type>WINDOWS</type>
-            <displayName>WIN2003E/32</displayName>
-        </operatingSystem>
-        <location>NA1</location>
-        <cpuCount>2</cpuCount>
-        <memory>4096</memory>
-        <osStorage>16</osStorage>
-        <additionalLocalStorage>0</additionalLocalStorage>
-        <created>1970-01-01T00:00:02.010Z</created>
-    </ServerImage>
-    <ServerImage>
-        <id>52ed7984-ebea-11df-bdc1-001517c46384</id>
-        <resourcePath>/oec/base/image/52ed7984-ebea-11df-bdc1-001517c46384</resourcePath>
-        <name>Win2003 Ent 32-bit 4 CPU</name>
-        <description>Windows 2003 Enterprise SP2 32-bit</description>
-        <operatingSystem>
-            <type>WINDOWS</type>
-            <displayName>WIN2003E/32</displayName>
-        </operatingSystem>
-        <location>NA1</location>
-        <cpuCount>4</cpuCount>
-        <memory>4096</memory>
-        <osStorage>16</osStorage>
-        <additionalLocalStorage>0</additionalLocalStorage>
-        <created>1970-01-01T00:00:02.010Z</created>
-    </ServerImage>
-    <ServerImage>
-        <id>52ed7a88-ebea-11df-bdc1-001517c46384</id>
-        <resourcePath>/oec/base/image/52ed7a88-ebea-11df-bdc1-001517c46384</resourcePath>
-        <name>Win2003 Std 64-bit 2 CPU</name>
-        <description>Windows 2003 Standard x64 SP2, 64-bit</description>
-        <operatingSystem>
-            <type>WINDOWS</type>
-            <displayName>WIN2003S/64</displayName>
-        </operatingSystem>
-        <location>NA1</location>
-        <cpuCount>2</cpuCount>
-        <memory>4096</memory>
-        <osStorage>16</osStorage>
-        <additionalLocalStorage>0</additionalLocalStorage>
-        <created>1970-01-01T00:00:02.010Z</created>
-    </ServerImage>
-    <ServerImage>
-        <id>0c231ef0-2a42-11e0-bfb5-001517c46384</id>
-        <resourcePath>/oec/base/image/0c231ef0-2a42-11e0-bfb5-001517c46384</resourcePath>
-        <name>RedHat 64-bit 2 CPU with MySQL</name>
-        <description>RedHat 5.5 Enterprise with MySQL 5.5 installed</description>
-        <operatingSystem>
-            <type>UNIX</type>
-            <displayName>REDHAT5/64</displayName>
-        </operatingSystem>
-        <location>NA1</location>
-        <cpuCount>2</cpuCount>
-        <memory>8192</memory>
-        <osStorage>10</osStorage>
-        <additionalLocalStorage>0</additionalLocalStorage>
-        <created>2011-01-27T18:19:58.000Z</created>
-    </ServerImage>
-    <ServerImage>
-        <id>2fb5261a-2a42-11e0-bfb5-001517c46384</id>
-        <resourcePath>/oec/base/image/2fb5261a-2a42-11e0-bfb5-001517c46384</resourcePath>
-        <name>RedHat 64-bit 2 CPU with PostgreSQL</name>
-        <description>RedHat 5.5 Enterprise with PostgreSQL 9.0 installed</description>
-        <operatingSystem>
-            <type>UNIX</type>
-            <displayName>REDHAT5/64</displayName>
-        </operatingSystem>
-        <location>NA1</location>
-        <cpuCount>2</cpuCount>
-        <memory>8192</memory>
-        <osStorage>10</osStorage>
-        <additionalLocalStorage>0</additionalLocalStorage>
-        <created>2011-01-27T18:20:57.000Z</created>
-    </ServerImage>
 </ServerImages>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/0ba9ae48/libcloud/test/compute/test_dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_dimensiondata.py b/libcloud/test/compute/test_dimensiondata.py
index 47a8e16..d6c4dba 100644
--- a/libcloud/test/compute/test_dimensiondata.py
+++ b/libcloud/test/compute/test_dimensiondata.py
@@ -20,6 +20,7 @@ from libcloud.common.types import InvalidCredsError
 from libcloud.compute.drivers.dimensiondata import DimensionDataNodeDriver as DimensionData
 from libcloud.compute.drivers.dimensiondata import DimensionDataAPIException
 from libcloud.compute.base import Node, NodeAuthPassword, NodeLocation
+from libcloud.compute.types import NodeState
 
 from libcloud.test import MockHttp
 from libcloud.test.compute import TestCaseMixin
@@ -44,6 +45,21 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin):
         except InvalidCredsError:
             pass
 
+    def test_list_locations_response(self):
+        DimensionDataMockHttp.type = None
+        ret = self.driver.list_locations()
+        self.assertEqual(len(ret), 1)
+        first_node = ret[0]
+        self.assertEqual(first_node.id, 'NA10')
+        self.assertEqual(first_node.name, 'US - West')
+        self.assertEqual(first_node.country, 'US')
+        
+    def test_list_nodes_response(self):
+        DimensionDataMockHttp.type = None
+        ret = self.driver.list_nodes()
+        self.assertEqual(len(ret), 2)
+        first_node = ret[0]
+        
     def test_list_sizes_response(self):
         DimensionDataMockHttp.type = None
         ret = self.driver.list_sizes()
@@ -74,7 +90,7 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin):
         ret = node.destroy()
         self.assertTrue(ret is True)
 
-    def test_destroy_node_response_INPROGRESS(self):
+    def test_destroy_node_response_RESOURCE_BUSY(self):
         DimensionDataMockHttp.type = 'INPROGRESS'
         node = Node(id='11', name=None, state=None,
                     public_ips=None, private_ips=None, driver=self.driver)
@@ -146,17 +162,26 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin):
         except DimensionDataAPIException:
             pass
 
+    def test_ex_reset(self):
+        node = Node(id='11', name=None, state=None,
+                    public_ips=None, private_ips=None, driver=self.driver)
+        ret = self.driver.ex_reset(node)
+        self.assertTrue(ret is True)
+
     def test_ex_list_networks(self):
         nets = self.driver.ex_list_networks()
         self.assertEqual(nets[0].name, 'test-net1')
         self.assertTrue(isinstance(nets[0].location, NodeLocation))
+        
+    def test_ex_list_network_domains(self):
+        nets = self.driver.ex_list_network_domains()
+        self.assertEqual(nets[0].name, 'Production Network Domain')
+        self.assertTrue(isinstance(nets[0].location, NodeLocation))
 
-    def test_node_public_ip(self):
-        nodes = self.driver.list_nodes()
-        node = [n for n in nodes if n.id ==
-                'abadbc7e-9e10-46ca-9d4a-194bcc6b6c16'][0]
-        self.assertEqual(node.public_ips[0], '200.16.132.7')
-
+    def test_ex_list_vlans(self):
+        vlans = self.driver.ex_list_vlans()
+        self.assertEqual(vlans[0].name, "Production VLAN")
+            
 
 class DimensionDataMockHttp(MockHttp):
 
@@ -245,7 +270,86 @@ class DimensionDataMockHttp(MockHttp):
         body = self.fixtures.load(
             'oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkWithLocation.xml')
         return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
 
-
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer_INPROGRESS(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_deleteServer_RESOURCEBUSY.xml')
+        return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer_INPROGRESS(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_rebootServer_RESOURCEBUSY.xml')
+        return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_server.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_infrastructure_datacenter(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_infrastructure_datacenter.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer_INPROGRESS(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_startServer_INPROGRESS.xml')
+        return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer_INPROGRESS(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_shutdownServer_INPROGRESS.xml')
+        return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_resetServer(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_resetServer.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer_INPROGRESS(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_server_powerOffServer_INPROGRESS.xml')
+        return (httplib.BAD_REQUEST, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_networkDomain(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_networkDomain.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_vlan.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
 if __name__ == '__main__':
     sys.exit(unittest.main())


[19/21] libcloud git commit: Fix broken import in the test file.

Posted by to...@apache.org.
Fix broken import in the test file.


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

Branch: refs/heads/trunk
Commit: 8c31ebdd175fa928e0507fc3b07373506afcc96d
Parents: 46626cb
Author: Tomaz Muraus <to...@apache.org>
Authored: Sun Aug 30 14:23:55 2015 +0200
Committer: Tomaz Muraus <to...@apache.org>
Committed: Sun Aug 30 14:23:55 2015 +0200

----------------------------------------------------------------------
 libcloud/test/compute/test_dimensiondata.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/8c31ebdd/libcloud/test/compute/test_dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_dimensiondata.py b/libcloud/test/compute/test_dimensiondata.py
index c37ab44..942cada 100644
--- a/libcloud/test/compute/test_dimensiondata.py
+++ b/libcloud/test/compute/test_dimensiondata.py
@@ -17,8 +17,8 @@ import unittest
 from libcloud.utils.py3 import httplib
 
 from libcloud.common.types import InvalidCredsError
+from libcloud.common.dimensiondata import DimensionDataAPIException
 from libcloud.compute.drivers.dimensiondata import DimensionDataNodeDriver as DimensionData
-from libcloud.compute.drivers.dimensiondata import DimensionDataAPIException
 from libcloud.compute.base import Node, NodeAuthPassword, NodeLocation
 
 from libcloud.test import MockHttp


[04/21] libcloud git commit: [LIBCLOUD-736] updated code in line with pep8 style req's

Posted by to...@apache.org.
[LIBCLOUD-736] updated code in line with pep8 style req's


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

Branch: refs/heads/trunk
Commit: 02ee35aca1726074ed647b5dab438a0a4e73b690
Parents: fd43de2
Author: Anthony Shaw <an...@gmail.com>
Authored: Tue Aug 25 16:53:56 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Tue Aug 25 16:53:56 2015 +1000

----------------------------------------------------------------------
 libcloud/compute/drivers/dimensiondata.py | 143 ++++++++++++++++---------
 1 file changed, 90 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/02ee35ac/libcloud/compute/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py
index 8ccfc8f..50166e2 100644
--- a/libcloud/compute/drivers/dimensiondata.py
+++ b/libcloud/compute/drivers/dimensiondata.py
@@ -107,7 +107,7 @@ class DimensionDataResponse(XmlResponse):
 
         body = self.parse_body()
 
-        # TODO: The path is not fixed as server. 
+        # TODO: The path is not fixed as server.
         if self.status == httplib.BAD_REQUEST:
             code = findtext(body, 'responseCode', SERVER_NS)
             message = findtext(body, 'message', SERVER_NS)
@@ -141,7 +141,7 @@ class DimensionDataConnection(ConnectionUserAndKey):
     api_path_version_2 = '/caas'
     api_version_1 = '0.9'
     api_version_2 = '2.0'
-    
+
     _orgId = None
     responseCls = DimensionDataResponse
 
@@ -167,17 +167,19 @@ class DimensionDataConnection(ConnectionUserAndKey):
         return headers
 
     def request_api_1(self, action, params=None, data='',
-                headers=None, method='GET'):
-        action = "%s/%s/%s" % (self.api_path_version_1, self.api_version_1, action)
+                      headers=None, method='GET'):
+        action = "%s/%s/%s" % (self.api_path_version_1,
+                               self.api_version_1, action)
 
         return super(DimensionDataConnection, self).request(
             action=action,
             params=params, data=data,
             method=method, headers=headers)
-    
+
     def request_api_2(self, path, action, params=None, data='',
-                headers=None, method='GET'):
-        action = "%s/%s/%s/%s" % (self.api_path_version_2, self.api_version_2, path, action)
+                      headers=None, method='GET'):
+        action = "%s/%s/%s/%s" % (self.api_path_version_2,
+                                  self.api_version_2, path, action)
 
         return super(DimensionDataConnection, self).request(
             action=action,
@@ -185,16 +187,16 @@ class DimensionDataConnection(ConnectionUserAndKey):
             method=method, headers=headers)
 
     def request_with_orgId_api_1(self, action, params=None, data='',
-                           headers=None, method='GET'):
+                                 headers=None, method='GET'):
         action = "%s/%s" % (self.get_resource_path_api_1(), action)
 
         return super(DimensionDataConnection, self).request(
             action=action,
             params=params, data=data,
             method=method, headers=headers)
-    
+
     def request_with_orgId_api_2(self, action, params=None, data='',
-                           headers=None, method='GET'):
+                                 headers=None, method='GET'):
         action = "%s/%s" % (self.get_resource_path_api_2(), action)
 
         return super(DimensionDataConnection, self).request(
@@ -284,6 +286,7 @@ class DimensionDataNetwork(object):
                 % (self.id, self.name, self.description, self.location,
                    self.private_net, self.multicast))
 
+
 class DimensionDataNetworkDomain(object):
     """
     DimensionData network domain with location.
@@ -297,9 +300,11 @@ class DimensionDataNetworkDomain(object):
         self.status = status
 
     def __repr__(self):
-        return (('<DimensionDataNetworkDomain: id=%s, name=%s, description=%s, '
-                 'location=%s, status=%s>')
-                % (self.id, self.name, self.description, self.location, self.status))
+        return (('<DimensionDataNetworkDomain: id=%s, name=%s,'
+                 'description=%s, location=%s, status=%s>')
+                % (self.id, self.name, self.description, self.location,
+                   self.status))
+
 
 class DimensionDataVlan(object):
     """
@@ -314,9 +319,11 @@ class DimensionDataVlan(object):
         self.status = status
 
     def __repr__(self):
-        return (('<DimensionDataNetworkDomain: id=%s, name=%s, description=%s, '
-                 'location=%s, status=%s>')
-                % (self.id, self.name, self.description, self.location, self.status))
+        return (('<DimensionDataNetworkDomain: id=%s, name=%s, '
+                 'description=%s, location=%s, status=%s>')
+                % (self.id, self.name, self.description,
+                   self.location, self.status))
+
 
 class DimensionDataNodeDriver(NodeDriver):
     """
@@ -399,15 +406,17 @@ class DimensionDataNodeDriver(NodeDriver):
 
         if not isinstance(ex_network, DimensionDataNetwork):
             raise ValueError('ex_network must be of DimensionDataNetwork type')
-        vlanResourcePath = "%s/%s" % (self.connection.get_resource_path_api_1(),
-                                      ex_network.id)
+        vlanResourcePath = "%s/%s" % (
+            self.connection.get_resource_path_api_1(),
+            ex_network.id)
 
         imageResourcePath = None
         if 'resourcePath' in image.extra:
             imageResourcePath = image.extra['resourcePath']
         else:
-            imageResourcePath = "%s/%s" % (self.connection.get_resource_path_api_1(),
-                                           image.id)
+            imageResourcePath = "%s/%s" % (
+                self.connection.get_resource_path_api_1(),
+                image.id)
 
         server_elm = ET.Element('Server', {'xmlns': SERVER_NS})
         ET.SubElement(server_elm, "name").text = name
@@ -417,9 +426,10 @@ class DimensionDataNodeDriver(NodeDriver):
         ET.SubElement(server_elm, "administratorPassword").text = password
         ET.SubElement(server_elm, "isStarted").text = str(ex_is_started)
 
-        self.connection.request_with_orgId_api_1('server',
-                                           method='POST',
-                                           data=ET.tostring(server_elm)).object
+        self.connection.request_with_orgId_api_1(
+            'server',
+            method='POST',
+            data=ET.tostring(server_elm)).object
 
         # XXX: return the last node in the list that has a matching name.  this
         #      is likely but not guaranteed to be the node we just created
@@ -433,23 +443,29 @@ class DimensionDataNodeDriver(NodeDriver):
         return node
 
     def destroy_node(self, node):
-        request_elm = ET.Element('deleteServer', {'xmlns': TYPES_URN, 'id': node.id})
+        request_elm = ET.Element('deleteServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
         body = self.connection.request_with_orgId_api_2(
-            'server/deleteServer', method='POST', data=ET.tostring(request_elm) ).object
+            'server/deleteServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
         result = findtext(body, 'responseCode', TYPES_URN)
         return result == 'IN_PROGRESS'
 
     def reboot_node(self, node):
-        request_elm = ET.Element('rebootServer', {'xmlns': TYPES_URN, 'id': node.id})
+        request_elm = ET.Element('rebootServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
         body = self.connection.request_with_orgId_api_2(
-            'server/rebootServer', method='POST', data=ET.tostring(request_elm) ).object
+            'server/rebootServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
         result = findtext(body, 'responseCode', TYPES_URN)
         return result == 'IN_PROGRESS'
 
     def list_nodes(self):
         nodes = self._to_nodes(
             self.connection.request_with_orgId_api_2('server/server').object)
-      
+
         return nodes
 
     def list_images(self, location=None):
@@ -489,7 +505,8 @@ class DimensionDataNodeDriver(NodeDriver):
         @inherits: :class:`NodeDriver.list_locations`
         """
         return self._to_locations(
-            self.connection.request_with_orgId_api_2('infrastructure/datacenter').object)
+            self.connection
+            .request_with_orgId_api_2('infrastructure/datacenter').object)
 
     def list_networks(self, location=None):
         """
@@ -504,7 +521,8 @@ class DimensionDataNodeDriver(NodeDriver):
         :rtype: ``list`` of :class:`DimensionDataNetwork`
         """
         return self._to_networks(
-            self.connection.request_with_orgId_api_1('networkWithLocation').object)
+            self.connection
+            .request_with_orgId_api_1('networkWithLocation').object)
 
     def _to_base_images(self, object):
         images = []
@@ -550,9 +568,12 @@ class DimensionDataNodeDriver(NodeDriver):
 
         :rtype: ``bool``
         """
-        request_elm = ET.Element('startServer', {'xmlns': TYPES_URN, 'id': node.id})
+        request_elm = ET.Element('startServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
         body = self.connection.request_with_orgId_api_2(
-            'server/startServer', method='POST', data=ET.tostring(request_elm) ).object
+            'server/startServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
         result = findtext(body, 'responseCode', TYPES_URN)
         return result == 'IN_PROGRESS'
 
@@ -568,9 +589,12 @@ class DimensionDataNodeDriver(NodeDriver):
 
         :rtype: ``bool``
         """
-        request_elm = ET.Element('shutdownServer', {'xmlns': TYPES_URN, 'id': node.id})
+        request_elm = ET.Element('shutdownServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
         body = self.connection.request_with_orgId_api_2(
-            'server/shutdownServer', method='POST', data=ET.tostring(request_elm) ).object
+            'server/shutdownServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
         result = findtext(body, 'responseCode', TYPES_URN)
         return result == 'IN_PROGRESS'
 
@@ -586,9 +610,12 @@ class DimensionDataNodeDriver(NodeDriver):
 
         :rtype: ``bool``
         """
-        request_elm = ET.Element('powerOffServer', {'xmlns': TYPES_URN, 'id': node.id})
+        request_elm = ET.Element('powerOffServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
         body = self.connection.request_with_orgId_api_2(
-            'server/powerOffServer', method='POST', data=ET.tostring(request_elm) ).object
+            'server/powerOffServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
         result = findtext(body, 'responseCode', TYPES_URN)
         return result == 'IN_PROGRESS'
 
@@ -604,9 +631,12 @@ class DimensionDataNodeDriver(NodeDriver):
 
         :rtype: ``bool``
         """
-        request_elm = ET.Element('resetServer', {'xmlns': TYPES_URN, 'id': node.id})
+        request_elm = ET.Element('resetServer',
+                                 {'xmlns': TYPES_URN, 'id': node.id})
         body = self.connection.request_with_orgId_api_2(
-            'server/resetServer', method='POST', data=ET.tostring(request_elm) ).object
+            'server/resetServer',
+            method='POST',
+            data=ET.tostring(request_elm)).object
         result = findtext(body, 'responseCode', TYPES_URN)
         return result == 'IN_PROGRESS'
 
@@ -618,8 +648,8 @@ class DimensionDataNodeDriver(NodeDriver):
         :return: a list of DimensionDataNetwork objects
         :rtype: ``list`` of :class:`DimensionDataNetwork`
         """
-        response = self.connection.request_with_orgId_api_1('networkWithLocation') \
-                                  .object
+        response = self.connection \
+            .request_with_orgId_api_1('networkWithLocation').object
         return self._to_networks(response)
 
     def ex_list_network_domains(self):
@@ -687,7 +717,7 @@ class DimensionDataNodeDriver(NodeDriver):
                                  NETWORK_NS),
             multicast=multicast,
             status=status)
-    
+
     def _to_network_domains(self, object):
         network_domains = []
         for element in findall(object, 'networkDomain', TYPES_URN):
@@ -718,10 +748,10 @@ class DimensionDataNodeDriver(NodeDriver):
 
     def _to_vlan(self, element):
         status = self._to_status(element.find(fixxpath('state', TYPES_URN)))
-        
+
         location_id = element.get('location')
         location = self.ex_get_location_by_id(location_id)
-        
+
         return DimensionDataVlan(
             id=element.get('id'),
             name=findtext(element, 'name', TYPES_URN),
@@ -765,16 +795,23 @@ class DimensionDataNodeDriver(NodeDriver):
                                       .get('networkDomainId'),
             'datacenterId': element.get('datacenterId'),
             'deployedTime': findtext(element, 'createTime', TYPES_URN),
-            'cpuCount': int(findtext(element, 'cpuCount',
-                                 TYPES_URN)),
-            'memoryMb': int(findtext(element, 'memoryGb',
-                                 TYPES_URN)) * 1024,
-            'OS_id': element.find(fixxpath('operatingSystem', TYPES_URN))
-                                      .get('id'),
-            'OS_type': element.find(fixxpath('operatingSystem', TYPES_URN))
-                                      .get('family'),
-            'OS_displayName': element.find(fixxpath('operatingSystem', TYPES_URN))
-                                      .get('displayName'),
+            'cpuCount': int(findtext(
+                element,
+                'cpuCount',
+                TYPES_URN)),
+            'memoryMb': int(findtext(
+                element,
+                'memoryGb',
+                TYPES_URN)) * 1024,
+            'OS_id': element.find(fixxpath(
+                'operatingSystem',
+                TYPES_URN)).get('id'),
+            'OS_type': element.find(fixxpath(
+                'operatingSystem',
+                TYPES_URN)).get('family'),
+            'OS_displayName': element.find(fixxpath(
+                'operatingSystem',
+                TYPES_URN)).get('displayName'),
             'status': status
         }
 


[07/21] libcloud git commit: [LIBCLOUD-737] Started a load balancer driver for the Dimension Data VIP functionality.

Posted by to...@apache.org.
[LIBCLOUD-737] Started a load balancer driver for the Dimension Data VIP functionality.


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

Branch: refs/heads/trunk
Commit: b90c56106930dedbe526ffb18fb34661c0fcb0de
Parents: fbd02da
Author: Anthony Shaw <an...@gmail.com>
Authored: Wed Aug 26 17:24:10 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Wed Aug 26 17:24:10 2015 +1000

----------------------------------------------------------------------
 libcloud/common/dimensiondata.py                | 342 +++++++++++++++++++
 libcloud/compute/drivers/dimensiondata.py       | 308 +----------------
 libcloud/loadbalancer/drivers/dimensiondata.py  | 248 ++++++++++++++
 libcloud/loadbalancer/providers.py              |   3 +-
 libcloud/loadbalancer/types.py                  |   3 +-
 ..._9cbc_8dabe5a7d0e4_networkDomainVip_pool.xml |  37 ++
 ...8dabe5a7d0e4_networkDomainVip_poolMember.xml |  29 ++
 ...ber_3dd806a2_c2c8_4c0c_9a4f_5219ea9266c0.xml |  13 +
 ...ool_4d360b1f_bc2c_4ab7_9884_1f03ba2768f7.xml |  17 +
 ...5a7d0e4_networkDomainVip_virtualListener.xml |  51 +++
 ...ner_6115469d_a8bb_445b_bb23_d23b5283f2b9.xml |  44 +++
 .../dimensiondata/oec_0_9_myaccount.xml         |  26 ++
 .../test/loadbalancer/test_dimensiondata.py     | 160 +++++++++
 13 files changed, 981 insertions(+), 300 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/common/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/common/dimensiondata.py b/libcloud/common/dimensiondata.py
new file mode 100644
index 0000000..f5cdf05
--- /dev/null
+++ b/libcloud/common/dimensiondata.py
@@ -0,0 +1,342 @@
+# 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.
+"""
+Dimension Data Common Components
+"""
+from base64 import b64encode
+from libcloud.utils.py3 import httplib
+from libcloud.utils.py3 import b
+
+from libcloud.common.base import ConnectionUserAndKey, XmlResponse
+from libcloud.common.types import LibcloudError, InvalidCredsError
+from libcloud.utils.xml import findtext
+
+# Roadmap / TODO:
+#
+# 1.0 - Copied from OpSource API, named provider details.
+
+# setup a few variables to represent all of the DimensionData cloud namespaces
+NAMESPACE_BASE = "http://oec.api.opsource.net/schemas"
+ORGANIZATION_NS = NAMESPACE_BASE + "/organization"
+SERVER_NS = NAMESPACE_BASE + "/server"
+NETWORK_NS = NAMESPACE_BASE + "/network"
+DIRECTORY_NS = NAMESPACE_BASE + "/directory"
+
+# API 2.0 Namespaces and URNs
+TYPES_URN = "urn:didata.com:api:cloud:types"
+
+# API end-points
+API_ENDPOINTS = {
+    'dd-na': {
+        'name': 'North America (NA)',
+        'host': 'api-na.dimensiondata.com',
+        'vendor': 'DimensionData'
+    },
+    'dd-eu': {
+        'name': 'Europe (EU)',
+        'host': 'api-eu.dimensiondata.com',
+        'vendor': 'DimensionData'
+    },
+    'dd-au': {
+        'name': 'Australia (AU)',
+        'host': 'api-au.dimensiondata.com',
+        'vendor': 'DimensionData'
+    },
+    'dd-af': {
+        'name': 'Africa (AF)',
+        'host': 'api-af.dimensiondata.com',
+        'vendor': 'DimensionData'
+    },
+    'dd-ap': {
+        'name': 'Asia Pacific (AP)',
+        'host': 'api-na.dimensiondata.com',
+        'vendor': 'DimensionData'
+    },
+    'dd-latam': {
+        'name': 'South America (LATAM)',
+        'host': 'api-latam.dimensiondata.com',
+        'vendor': 'DimensionData'
+    },
+    'dd-canada': {
+        'name': 'Canada (CA)',
+        'host': 'api-canada.dimensiondata.com',
+        'vendor': 'DimensionData'
+    }
+}
+
+# Default API end-point for the base connection class.
+DEFAULT_REGION = 'dd-na'
+
+
+class DimensionDataResponse(XmlResponse):
+    def parse_error(self):
+        if self.status == httplib.UNAUTHORIZED:
+            raise InvalidCredsError(self.body)
+        elif self.status == httplib.FORBIDDEN:
+            raise InvalidCredsError(self.body)
+
+        body = self.parse_body()
+
+        # TODO: The path is not fixed as server.
+        if self.status == httplib.BAD_REQUEST:
+            code = findtext(body, 'responseCode', SERVER_NS)
+            message = findtext(body, 'message', SERVER_NS)
+            raise DimensionDataAPIException(code,
+                                            message,
+                                            driver=self.connection.driver)
+
+        return self.body
+
+
+class DimensionDataAPIException(LibcloudError):
+    def __init__(self, code, msg, driver):
+        self.code = code
+        self.msg = msg
+        self.driver = driver
+
+    def __str__(self):
+        return "%s: %s" % (self.code, self.msg)
+
+    def __repr__(self):
+        return ("<DimensionDataAPIException: code='%s', msg='%s'>" %
+                (self.code, self.msg))
+
+
+class DimensionDataConnection(ConnectionUserAndKey):
+    """
+    Connection class for the DimensionData driver
+    """
+
+    api_path_version_1 = '/oec'
+    api_path_version_2 = '/caas'
+    api_version_1 = '0.9'
+    api_version_2 = '2.0'
+
+    _orgId = None
+    responseCls = DimensionDataResponse
+
+    allow_insecure = False
+
+    def __init__(self, user_id, key, secure=True, host=None, port=None,
+                 url=None, timeout=None, proxy_url=None, **conn_kwargs):
+        super(DimensionDataConnection, self).__init__(
+            user_id=user_id,
+            key=key,
+            secure=secure,
+            host=host, port=port,
+            url=url, timeout=timeout,
+            proxy_url=proxy_url)
+
+        if conn_kwargs['region']:
+            self.host = conn_kwargs['region']['host']
+
+    def add_default_headers(self, headers):
+        headers['Authorization'] = \
+            ('Basic %s' % b64encode(b('%s:%s' % (self.user_id,
+                                                 self.key))).decode('utf-8'))
+        return headers
+
+    def request_api_1(self, action, params=None, data='',
+                      headers=None, method='GET'):
+        action = "%s/%s/%s" % (self.api_path_version_1,
+                               self.api_version_1, action)
+
+        return super(DimensionDataConnection, self).request(
+            action=action,
+            params=params, data=data,
+            method=method, headers=headers)
+
+    def request_api_2(self, path, action, params=None, data='',
+                      headers=None, method='GET'):
+        action = "%s/%s/%s/%s" % (self.api_path_version_2,
+                                  self.api_version_2, path, action)
+
+        return super(DimensionDataConnection, self).request(
+            action=action,
+            params=params, data=data,
+            method=method, headers=headers)
+
+    def request_with_orgId_api_1(self, action, params=None, data='',
+                                 headers=None, method='GET'):
+        action = "%s/%s" % (self.get_resource_path_api_1(), action)
+
+        return super(DimensionDataConnection, self).request(
+            action=action,
+            params=params, data=data,
+            method=method, headers=headers)
+
+    def request_with_orgId_api_2(self, action, params=None, data='',
+                                 headers=None, method='GET'):
+        action = "%s/%s" % (self.get_resource_path_api_2(), action)
+
+        return super(DimensionDataConnection, self).request(
+            action=action,
+            params=params, data=data,
+            method=method, headers=headers)
+
+    def get_resource_path_api_1(self):
+        """
+        This method returns a resource path which is necessary for referencing
+        resources that require a full path instead of just an ID, such as
+        networks, and customer snapshots.
+        """
+        return ("%s/%s/%s" % (self.api_path_version_1, self.api_version_1,
+                              self._get_orgId()))
+
+    def get_resource_path_api_2(self):
+        """
+        This method returns a resource path which is necessary for referencing
+        resources that require a full path instead of just an ID, such as
+        networks, and customer snapshots.
+        """
+        return ("%s/%s/%s" % (self.api_path_version_2, self.api_version_2,
+                              self._get_orgId()))
+
+    def _get_orgId(self):
+        """
+        Send the /myaccount API request to DimensionData cloud and parse the
+        'orgId' from the XML response object. We need the orgId to use most
+        of the other API functions
+        """
+        if self._orgId is None:
+            body = self.request_api_1('myaccount').object
+            self._orgId = findtext(body, 'orgId', DIRECTORY_NS)
+        return self._orgId
+
+
+class DimensionDataStatus(object):
+    """
+    DimensionData API pending operation status class
+        action, request_time, user_name, number_of_steps, update_time,
+        step.name, step.number, step.percent_complete, failure_reason,
+    """
+    def __init__(self, action=None, request_time=None, user_name=None,
+                 number_of_steps=None, update_time=None, step_name=None,
+                 step_number=None, step_percent_complete=None,
+                 failure_reason=None):
+        self.action = action
+        self.request_time = request_time
+        self.user_name = user_name
+        self.number_of_steps = number_of_steps
+        self.update_time = update_time
+        self.step_name = step_name
+        self.step_number = step_number
+        self.step_percent_complete = step_percent_complete
+        self.failure_reason = failure_reason
+
+    def __repr__(self):
+        return (('<DimensionDataStatus: action=%s, request_time=%s, '
+                 'user_name=%s, number_of_steps=%s, update_time=%s, '
+                 'step_name=%s, step_number=%s, '
+                 'step_percent_complete=%s, failure_reason=%s')
+                % (self.action, self.request_time, self.user_name,
+                   self.number_of_steps, self.update_time, self.step_name,
+                   self.step_number, self.step_percent_complete,
+                   self.failure_reason))
+
+
+class DimensionDataNetwork(object):
+    """
+    DimensionData network with location.
+    """
+
+    def __init__(self, id, name, description, location, private_net,
+                 multicast, status):
+        self.id = str(id)
+        self.name = name
+        self.description = description
+        self.location = location
+        self.private_net = private_net
+        self.multicast = multicast
+        self.status = status
+
+    def __repr__(self):
+        return (('<DimensionDataNetwork: id=%s, name=%s, description=%s, '
+                 'location=%s, private_net=%s, multicast=%s>')
+                % (self.id, self.name, self.description, self.location,
+                   self.private_net, self.multicast))
+
+
+class DimensionDataNetworkDomain(object):
+    """
+    DimensionData network domain with location.
+    """
+
+    def __init__(self, id, name, description, location, status):
+        self.id = str(id)
+        self.name = name
+        self.description = description
+        self.location = location
+        self.status = status
+
+    def __repr__(self):
+        return (('<DimensionDataNetworkDomain: id=%s, name=%s,'
+                 'description=%s, location=%s, status=%s>')
+                % (self.id, self.name, self.description, self.location,
+                   self.status))
+
+
+class DimensionDataVlan(object):
+    """
+    DimensionData VLAN.
+    """
+
+    def __init__(self, id, name, description, location, status):
+        self.id = str(id)
+        self.name = name
+        self.location = location
+        self.description = description
+        self.status = status
+
+    def __repr__(self):
+        return (('<DimensionDataNetworkDomain: id=%s, name=%s, '
+                 'description=%s, location=%s, status=%s>')
+                % (self.id, self.name, self.description,
+                   self.location, self.status))
+
+class DimensionDataPool(object):
+    """
+    DimensionData VIP Pool.
+    """
+
+    def __init__(self, id, name, description, status):
+        self.id = str(id)
+        self.name = name
+        self.description = description
+        self.status = status
+
+    def __repr__(self):
+        return (('<DimensionDataPool: id=%s, name=%s, '
+                 'description=%s, status=%s>')
+                % (self.id, self.name, self.description,
+                   self.status))
+    
+class DimensionDataPoolMember(object):
+    """
+    DimensionData VIP Pool Member.
+    """
+
+    def __init__(self, id, name, status, ip_address, port):
+        self.id = str(id)
+        self.name = name
+        self.status = status
+        self.ip_address = ip_address
+        self.port = port
+
+    def __repr__(self):
+        return (('<DimensionDataPool: id=%s, name=%s, '
+                 'ip_address=%s, status=%s, port=%s>')
+                % (self.id, self.name,
+                   self.ip_address, self.status, self.port))
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/compute/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py
index 8f0f71d..dcfe4b5 100644
--- a/libcloud/compute/drivers/dimensiondata.py
+++ b/libcloud/compute/drivers/dimensiondata.py
@@ -21,309 +21,21 @@ try:
 except ImportError:
     from xml.etree import ElementTree as ET
 
-from base64 import b64encode
-
-from libcloud.utils.py3 import httplib
-from libcloud.utils.py3 import b
-
 from libcloud.compute.base import NodeDriver, Node
 from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
-from libcloud.common.types import LibcloudError, InvalidCredsError
-from libcloud.common.base import ConnectionUserAndKey, XmlResponse
+from libcloud.common.dimensiondata import (DimensionDataConnection,
+                                           DimensionDataStatus)
+from libcloud.common.dimensiondata import DimensionDataNetwork
+from libcloud.common.dimensiondata import DimensionDataNetworkDomain
+from libcloud.common.dimensiondata import DimensionDataVlan
+from libcloud.common.dimensiondata import API_ENDPOINTS
+from libcloud.common.dimensiondata import DEFAULT_REGION
+from libcloud.common.dimensiondata import TYPES_URN
+from libcloud.common.dimensiondata import SERVER_NS
+from libcloud.common.dimensiondata import NETWORK_NS
 from libcloud.utils.xml import fixxpath, findtext, findall
 from libcloud.compute.types import NodeState, Provider
 
-# Roadmap / TODO:
-#
-# 1.0 - Copied from OpSource API, named provider details.
-
-# setup a few variables to represent all of the DimensionData cloud namespaces
-NAMESPACE_BASE = "http://oec.api.opsource.net/schemas"
-ORGANIZATION_NS = NAMESPACE_BASE + "/organization"
-SERVER_NS = NAMESPACE_BASE + "/server"
-NETWORK_NS = NAMESPACE_BASE + "/network"
-DIRECTORY_NS = NAMESPACE_BASE + "/directory"
-RESET_NS = NAMESPACE_BASE + "/reset"
-VIP_NS = NAMESPACE_BASE + "/vip"
-IMAGEIMPORTEXPORT_NS = NAMESPACE_BASE + "/imageimportexport"
-DATACENTER_NS = NAMESPACE_BASE + "/datacenter"
-SUPPORT_NS = NAMESPACE_BASE + "/support"
-GENERAL_NS = NAMESPACE_BASE + "/general"
-IPPLAN_NS = NAMESPACE_BASE + "/ipplan"
-WHITELABEL_NS = NAMESPACE_BASE + "/whitelabel"
-
-# API 2.0 Namespaces and URNs
-TYPES_URN = "urn:didata.com:api:cloud:types"
-
-# API end-points
-API_ENDPOINTS = {
-    'dd-na': {
-        'name': 'North America (NA)',
-        'host': 'api-na.dimensiondata.com',
-        'vendor': 'DimensionData'
-    },
-    'dd-eu': {
-        'name': 'Europe (EU)',
-        'host': 'api-eu.dimensiondata.com',
-        'vendor': 'DimensionData'
-    },
-    'dd-au': {
-        'name': 'Australia (AU)',
-        'host': 'api-au.dimensiondata.com',
-        'vendor': 'DimensionData'
-    },
-    'dd-af': {
-        'name': 'Africa (AF)',
-        'host': 'api-af.dimensiondata.com',
-        'vendor': 'DimensionData'
-    },
-    'dd-ap': {
-        'name': 'Asia Pacific (AP)',
-        'host': 'api-na.dimensiondata.com',
-        'vendor': 'DimensionData'
-    },
-    'dd-latam': {
-        'name': 'South America (LATAM)',
-        'host': 'api-latam.dimensiondata.com',
-        'vendor': 'DimensionData'
-    },
-    'dd-canada': {
-        'name': 'Canada (CA)',
-        'host': 'api-canada.dimensiondata.com',
-        'vendor': 'DimensionData'
-    }
-}
-
-# Default API end-point for the base connection class.
-DEFAULT_REGION = 'dd-na'
-
-
-class DimensionDataResponse(XmlResponse):
-    def parse_error(self):
-        if self.status == httplib.UNAUTHORIZED:
-            raise InvalidCredsError(self.body)
-        elif self.status == httplib.FORBIDDEN:
-            raise InvalidCredsError(self.body)
-
-        body = self.parse_body()
-
-        # TODO: The path is not fixed as server.
-        if self.status == httplib.BAD_REQUEST:
-            code = findtext(body, 'responseCode', SERVER_NS)
-            message = findtext(body, 'message', SERVER_NS)
-            raise DimensionDataAPIException(code,
-                                            message,
-                                            driver=DimensionDataNodeDriver)
-
-        return self.body
-
-
-class DimensionDataAPIException(LibcloudError):
-    def __init__(self, code, msg, driver):
-        self.code = code
-        self.msg = msg
-        self.driver = driver
-
-    def __str__(self):
-        return "%s: %s" % (self.code, self.msg)
-
-    def __repr__(self):
-        return ("<DimensionDataAPIException: code='%s', msg='%s'>" %
-                (self.code, self.msg))
-
-
-class DimensionDataConnection(ConnectionUserAndKey):
-    """
-    Connection class for the DimensionData driver
-    """
-
-    api_path_version_1 = '/oec'
-    api_path_version_2 = '/caas'
-    api_version_1 = '0.9'
-    api_version_2 = '2.0'
-
-    _orgId = None
-    responseCls = DimensionDataResponse
-
-    allow_insecure = False
-
-    def __init__(self, user_id, key, secure=True, host=None, port=None,
-                 url=None, timeout=None, proxy_url=None, **conn_kwargs):
-        super(DimensionDataConnection, self).__init__(
-            user_id=user_id,
-            key=key,
-            secure=secure,
-            host=host, port=port,
-            url=url, timeout=timeout,
-            proxy_url=proxy_url)
-
-        if conn_kwargs['region']:
-            self.host = conn_kwargs['region']['host']
-
-    def add_default_headers(self, headers):
-        headers['Authorization'] = \
-            ('Basic %s' % b64encode(b('%s:%s' % (self.user_id,
-                                                 self.key))).decode('utf-8'))
-        return headers
-
-    def request_api_1(self, action, params=None, data='',
-                      headers=None, method='GET'):
-        action = "%s/%s/%s" % (self.api_path_version_1,
-                               self.api_version_1, action)
-
-        return super(DimensionDataConnection, self).request(
-            action=action,
-            params=params, data=data,
-            method=method, headers=headers)
-
-    def request_api_2(self, path, action, params=None, data='',
-                      headers=None, method='GET'):
-        action = "%s/%s/%s/%s" % (self.api_path_version_2,
-                                  self.api_version_2, path, action)
-
-        return super(DimensionDataConnection, self).request(
-            action=action,
-            params=params, data=data,
-            method=method, headers=headers)
-
-    def request_with_orgId_api_1(self, action, params=None, data='',
-                                 headers=None, method='GET'):
-        action = "%s/%s" % (self.get_resource_path_api_1(), action)
-
-        return super(DimensionDataConnection, self).request(
-            action=action,
-            params=params, data=data,
-            method=method, headers=headers)
-
-    def request_with_orgId_api_2(self, action, params=None, data='',
-                                 headers=None, method='GET'):
-        action = "%s/%s" % (self.get_resource_path_api_2(), action)
-
-        return super(DimensionDataConnection, self).request(
-            action=action,
-            params=params, data=data,
-            method=method, headers=headers)
-
-    def get_resource_path_api_1(self):
-        """
-        This method returns a resource path which is necessary for referencing
-        resources that require a full path instead of just an ID, such as
-        networks, and customer snapshots.
-        """
-        return ("%s/%s/%s" % (self.api_path_version_1, self.api_version_1,
-                              self._get_orgId()))
-
-    def get_resource_path_api_2(self):
-        """
-        This method returns a resource path which is necessary for referencing
-        resources that require a full path instead of just an ID, such as
-        networks, and customer snapshots.
-        """
-        return ("%s/%s/%s" % (self.api_path_version_2, self.api_version_2,
-                              self._get_orgId()))
-
-    def _get_orgId(self):
-        """
-        Send the /myaccount API request to DimensionData cloud and parse the
-        'orgId' from the XML response object. We need the orgId to use most
-        of the other API functions
-        """
-        if self._orgId is None:
-            body = self.request_api_1('myaccount').object
-            self._orgId = findtext(body, 'orgId', DIRECTORY_NS)
-        return self._orgId
-
-
-class DimensionDataStatus(object):
-    """
-    DimensionData API pending operation status class
-        action, request_time, user_name, number_of_steps, update_time,
-        step.name, step.number, step.percent_complete, failure_reason,
-    """
-    def __init__(self, action=None, request_time=None, user_name=None,
-                 number_of_steps=None, update_time=None, step_name=None,
-                 step_number=None, step_percent_complete=None,
-                 failure_reason=None):
-        self.action = action
-        self.request_time = request_time
-        self.user_name = user_name
-        self.number_of_steps = number_of_steps
-        self.update_time = update_time
-        self.step_name = step_name
-        self.step_number = step_number
-        self.step_percent_complete = step_percent_complete
-        self.failure_reason = failure_reason
-
-    def __repr__(self):
-        return (('<DimensionDataStatus: action=%s, request_time=%s, '
-                 'user_name=%s, number_of_steps=%s, update_time=%s, '
-                 'step_name=%s, step_number=%s, '
-                 'step_percent_complete=%s, failure_reason=%s')
-                % (self.action, self.request_time, self.user_name,
-                   self.number_of_steps, self.update_time, self.step_name,
-                   self.step_number, self.step_percent_complete,
-                   self.failure_reason))
-
-
-class DimensionDataNetwork(object):
-    """
-    DimensionData network with location.
-    """
-
-    def __init__(self, id, name, description, location, private_net,
-                 multicast, status):
-        self.id = str(id)
-        self.name = name
-        self.description = description
-        self.location = location
-        self.private_net = private_net
-        self.multicast = multicast
-        self.status = status
-
-    def __repr__(self):
-        return (('<DimensionDataNetwork: id=%s, name=%s, description=%s, '
-                 'location=%s, private_net=%s, multicast=%s>')
-                % (self.id, self.name, self.description, self.location,
-                   self.private_net, self.multicast))
-
-
-class DimensionDataNetworkDomain(object):
-    """
-    DimensionData network domain with location.
-    """
-
-    def __init__(self, id, name, description, location, status):
-        self.id = str(id)
-        self.name = name
-        self.description = description
-        self.location = location
-        self.status = status
-
-    def __repr__(self):
-        return (('<DimensionDataNetworkDomain: id=%s, name=%s,'
-                 'description=%s, location=%s, status=%s>')
-                % (self.id, self.name, self.description, self.location,
-                   self.status))
-
-
-class DimensionDataVlan(object):
-    """
-    DimensionData VLAN.
-    """
-
-    def __init__(self, id, name, description, location, status):
-        self.id = str(id)
-        self.name = name
-        self.location = location
-        self.description = description
-        self.status = status
-
-    def __repr__(self):
-        return (('<DimensionDataNetworkDomain: id=%s, name=%s, '
-                 'description=%s, location=%s, status=%s>')
-                % (self.id, self.name, self.description,
-                   self.location, self.status))
-
 
 class DimensionDataNodeDriver(NodeDriver):
     """

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
new file mode 100644
index 0000000..d294a9a
--- /dev/null
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -0,0 +1,248 @@
+# 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 withv
+# 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.
+
+from libcloud.common.dimensiondata import DimensionDataConnection
+from libcloud.common.dimensiondata import DimensionDataPool
+from libcloud.common.dimensiondata import DimensionDataPoolMember
+from libcloud.common.dimensiondata import API_ENDPOINTS
+from libcloud.common.dimensiondata import DEFAULT_REGION
+from libcloud.common.dimensiondata import TYPES_URN
+from libcloud.common.dimensiondata import SERVER_NS
+from libcloud.utils.misc import find, reverse_dict
+from libcloud.utils.xml import fixxpath, findtext, findall
+from libcloud.loadbalancer.types import State
+from libcloud.loadbalancer.base import Algorithm, Driver, LoadBalancer
+from libcloud.loadbalancer.base import DEFAULT_ALGORITHM, Member
+from libcloud.loadbalancer.types import Provider
+
+class DimensionDataLBDriver(Driver):
+    """
+    DimensionData node driver.
+    """
+
+    selected_region = None
+    connectionCls = DimensionDataConnection
+    name = 'Dimension Data Load Balancer'
+    website = 'https://cloud.dimensiondata.com/'
+    type = Provider.DIMENSIONDATA
+    api_version = 1.0
+
+    _VALUE_TO_ALGORITHM_MAP = {
+        'ROUND_ROBIN': Algorithm.ROUND_ROBIN,
+        'LEAST_CONNECTIONS': Algorithm.LEAST_CONNECTIONS,
+        'SHORTEST_RESPONSE': Algorithm.SHORTEST_RESPONSE,
+        'PERSISTENT_IP': Algorithm.PERSISTENT_IP
+    }
+    _ALGORITHM_TO_VALUE_MAP = reverse_dict(_VALUE_TO_ALGORITHM_MAP)
+
+    _VALUE_TO_STATE_MAP = {
+        'NORMAL': State.RUNNING,
+        'PENDING_ADD': State.PENDING,
+        'PENDING_CHANGE': State.PENDING,
+        'PENDING_DELETE': State.PENDING,
+        'FAILED_ADD': State.ERROR,
+        'FAILED_CHANGE': State.ERROR,
+        'FAILED_DELETE': State.ERROR,
+        'REQUIRES_SUPPORT': State.ERROR
+    }
+
+    def __init__(self, key, secret=None, secure=True, host=None, port=None,
+                 api_version=None, region=DEFAULT_REGION, **kwargs):
+
+        if region not in API_ENDPOINTS:
+            raise ValueError('Invalid region: %s' % (region))
+
+        self.selected_region = API_ENDPOINTS[region]
+
+        super(DimensionDataLBDriver, self).__init__(key=key, secret=secret,
+                                                      secure=secure, host=host,
+                                                      port=port,
+                                                      api_version=api_version,
+                                                      region=region,
+                                                      **kwargs)
+
+    def _ex_connection_class_kwargs(self):
+        """
+            Add the region to the kwargs before the connection is instantiated
+        """
+
+        kwargs = super(DimensionDataLBDriver,
+                       self)._ex_connection_class_kwargs()
+        kwargs['region'] = self.selected_region
+        return kwargs
+
+    def list_balancers(self):
+        """
+        List all loadbalancers inside a gepgraphy.
+        
+        In Dimension Data terminology these are known as virtual listeners
+
+        :rtype: ``list`` of :class:`LoadBalancer`
+        """
+        
+        return self._to_balancers(
+            self.connection
+            .request_with_orgId_api_2('networkDomainVip/virtualListener').object)
+
+    def get_balancer(self, balancer_id):
+        """
+        Return a :class:`LoadBalancer` object.
+
+        :param balancer_id: id of a load balancer you want to fetch
+        :type  balancer_id: ``str``
+
+        :rtype: :class:`LoadBalancer`
+        """
+        
+        bal = self.connection \
+            .request_with_orgId_api_2('networkDomainVip/virtualListener/%s'
+                                      % balancer_id).object
+        return self._to_balancer(bal)
+
+    def list_protocols(self):
+        """
+        Return a list of supported protocols.
+
+        Since all protocols are support by Dimension Data, this is a list
+        of common protocols. 
+
+        :rtype: ``list`` of ``str``
+        """
+        return ['dns', 'ftp', 'http', 'https', 'tcp', 'udp']
+
+    def balancer_list_members(self, balancer):
+        """
+        Return list of members attached to balancer.
+        
+        In Dimension Data terminology these are the members of the pools
+        within a virtual listener.
+
+        :param balancer: LoadBalancer which should be used
+        :type  balancer: :class:`LoadBalancer`
+
+        :rtype: ``list`` of :class:`Member`
+        """
+        
+        pool_members = self.ex_get_pool_members(balancer.extra['pool_id'])
+        members = []
+        for pool_member in pool_members:
+            members.append(Member(
+                id=pool_member.id,
+                ip=pool_member.ip_address,
+                port=pool_member.port,
+                balancer=balancer,
+                extra=None
+            ))
+        return members
+
+    def balancer_attach_member(self, balancer, member):
+        return True
+
+    def balancer_detach_member(self, balancer, member):
+        return True
+
+    def destroy_balancer(self, balancer):
+        return True
+
+    def ex_get_pools(self):
+        pools = self.connection \
+            .request_with_orgId_api_2('networkDomainVip/pool').object
+        return self._to_pools(pools)
+
+    def ex_get_pool(self, pool_id):
+        pool = self.connection \
+            .request_with_orgId_api_2('networkDomainVip/pool/%s'
+                                      % pool_id).object
+        return self._to_pool(pool)
+    
+    def ex_get_pool_members(self, pool_id):
+        members = self.connection \
+            .request_with_orgId_api_2('networkDomainVip/poolMember?poolId=%s'
+                                      % pool_id).object
+        return self._to_members(members)
+    
+    def ex_get_pool_member(self, pool_member_id):
+        member = self.connection \
+            .request_with_orgId_api_2('networkDomainVip/poolMember/%s'
+                                      % pool_member_id).object
+        return self._to_member(member)
+
+    def _to_balancers(self, object ):
+        loadbalancers = []
+        for element in object.findall(fixxpath("virtualListener", TYPES_URN)):
+            loadbalancers.append(self._to_balancer(element))
+
+        return loadbalancers
+
+    def _to_balancer(self, element):
+        ipaddress = findtext(element, 'listenerIpAddress', TYPES_URN)
+        name = findtext(element, 'name', TYPES_URN)
+        port = findtext(element, 'port', TYPES_URN)
+        extra = {}
+        
+        extra['pool_id'] = element.find(fixxpath(
+                'pool',
+                TYPES_URN)).get('id')
+        
+        balancer = LoadBalancer(
+            id=element.get('id'),
+            name=name,
+            state=self._VALUE_TO_STATE_MAP.get(
+                              findtext(element, 'state', TYPES_URN),
+                              State.UNKNOWN),
+            ip=ipaddress,
+            port=port,
+            driver=self.connection.driver,
+            extra=extra
+        )
+
+        return balancer
+    
+    def _to_members(self, object ):
+        members = []
+        for element in object.findall(fixxpath("poolMember", TYPES_URN)):
+            members.append(self._to_member(element))
+
+        return members
+    
+    def _to_member(self, element):
+        pool = DimensionDataPoolMember(
+            id=element.get('id'),
+            name=element.find(fixxpath(
+                'node',
+                TYPES_URN)).get('name'),
+            status=findtext(element, 'state', TYPES_URN),
+            ip_address=element.find(fixxpath(
+                'node',
+                TYPES_URN)).get('ipAddress'),
+            port=int(findtext(element, 'port', TYPES_URN))
+        )
+        return pool
+    
+    def _to_pools(self, object ):
+        pools = []
+        for element in object.findall(fixxpath("pool", TYPES_URN)):
+            pools.append(self._to_pool(element))
+
+        return pools
+    
+    def _to_pool(self, element):
+        pool = DimensionDataPool(
+            id=element.get('id'),
+            name=findtext(element, 'name', TYPES_URN),
+            status=findtext(element,'state', TYPES_URN),
+            description=findtext(element, 'description', TYPES_URN)
+        )
+        return pool

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/loadbalancer/providers.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/providers.py b/libcloud/loadbalancer/providers.py
index 5a65402..a4ff090 100644
--- a/libcloud/loadbalancer/providers.py
+++ b/libcloud/loadbalancer/providers.py
@@ -40,7 +40,8 @@ DRIVERS = {
     ('libcloud.loadbalancer.drivers.gce', 'GCELBDriver'),
     Provider.SOFTLAYER:
     ('libcloud.loadbalancer.drivers.softlayer', 'SoftlayerLBDriver'),
-
+    Provider.DIMENSIONDATA:
+    ('libcloud.loadbalancer.drivers.dimensiondata', 'DimensionDataLBDriver'),
     # Deprecated
     Provider.RACKSPACE_US:
     ('libcloud.loadbalancer.drivers.rackspace', 'RackspaceLBDriver'),

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/loadbalancer/types.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/types.py b/libcloud/loadbalancer/types.py
index 8ae82e9..9a34293 100644
--- a/libcloud/loadbalancer/types.py
+++ b/libcloud/loadbalancer/types.py
@@ -40,7 +40,8 @@ class Provider(object):
     CLOUDSTACK = 'cloudstack'
     GCE = 'gce'
     SOFTLAYER = 'softlayer'
-
+    DIMENSIONDATA = 'dimensiondata'
+    
     # Deprecated
     RACKSPACE_US = 'rackspace_us'
     RACKSPACE_UK = 'rackspace_uk'

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool.xml
new file mode 100644
index 0000000..239fe52
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<pools
+xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="2"
+totalCount="2" pageSize="250">
+<pool id="4d360b1f-bc2c-4ab7-9884-1f03ba2768f7" datacenterId="NA9">
+<networkDomainId>553f26b6-2a73-42c3-a78b-
+6116f11291d0</networkDomainId>
+<name>myDevelopmentPool.1</name>
+<description>Pool for load balancing development application
+servers.</description>
+<loadBalanceMethod>ROUND_ROBIN</loadBalanceMethod>
+<healthMonitor id="01683574-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Http"/>
+<healthMonitor id="0168546c-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Https"/>
+<serviceDownAction>RESELECT</serviceDownAction>
+<slowRampTime>10</slowRampTime>
+<state>NORMAL</state>
+<createTime>2015-06-04T09:15:07.000Z</createTime>
+</pool>
+<pool id="afb1fb1a-eab9-43f4-95c2-36a4cdda6cb8" datacenterId="NA9">
+<networkDomainId>553f26b6-2a73-42c3-a78b-
+6116f11291d0</networkDomainId>
+<name>myProductionPool.1</name>
+<description>Pool for load balancing production application
+servers.</description>
+<loadBalanceMethod>ROUND_ROBIN</loadBalanceMethod>
+<healthMonitor id="01683574-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Http"/>
+<healthMonitor id="0168546c-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Https"/>
+<serviceDownAction>NONE</serviceDownAction>
+<slowRampTime>10</slowRampTime>
+<state>NORMAL</state>
+<createTime>2015-06-03T14:11:17.000Z</createTime>
+</pool>
+</pools>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember.xml
new file mode 100644
index 0000000..b36f75e
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<poolMembers
+xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="2"
+totalCount="2" pageSize="250">
+<poolMember id="3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0" datacenterId="NA9">
+<networkDomainId>553f26b6-2a73-42c3-a78b-
+6116f11291d0</networkDomainId>
+<pool id="4d360b1f-bc2c-4ab7-9884-1f03ba2768f7"
+name="myDevelopmentPool.1"/>
+<node id="3c207269-e75e-11e4-811f-005056806999" name="10.0.3.13"
+ipAddress="10.0.3.13" status="ENABLED"/>
+<port>9889</port>
+<status>ENABLED</status>
+<state>NORMAL</state>
+<createTime>2015-06-09T11:02:50.000Z</createTime>
+</poolMember>
+<poolMember id="b977578b-a827-4172-b285-030c3ba15daa" datacenterId="NA9">
+<networkDomainId>553f26b6-2a73-42c3-a78b-
+6116f11291d0</networkDomainId>
+<pool id="4d360b1f-bc2c-4ab7-9884-1f03ba2768f7"
+name="myDevelopmentPool.1"/>
+<node id="3c207269-e75e-11e4-811f-005056806999" name="10.0.3.13"
+ipAddress="10.0.3.13" status="ENABLED"/>
+<port>9888</port>
+<status>ENABLED</status>
+<state>NORMAL</state>
+<createTime>2015-06-09T10:43:29.000Z</createTime>
+</poolMember>
+</poolMembers>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember_3dd806a2_c2c8_4c0c_9a4f_5219ea9266c0.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember_3dd806a2_c2c8_4c0c_9a4f_5219ea9266c0.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember_3dd806a2_c2c8_4c0c_9a4f_5219ea9266c0.xml
new file mode 100644
index 0000000..7c86d4a
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember_3dd806a2_c2c8_4c0c_9a4f_5219ea9266c0.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<poolMember
+xmlns="urn:didata.com:api:cloud:types" id="3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0" datacenterId="NA9">
+<networkDomainId>553f26b6-2a73-42c3-a78b-6116f11291d0</networkDomainId>
+<pool id="6f2f5d7b-cdd9-4d84-8ad7-999b64a87978"
+name="myDevelopmentPool.1"/>
+<node id="3c207269-e75e-11e4-811f-005056806999" name="10.0.3.13"
+ipAddress="10.0.3.13" status="ENABLED"/>
+<port>9889</port>
+<status>ENABLED</status>
+<state>NORMAL</state>
+<createTime>2015-06-09T11:02:50.000Z</createTime>
+</poolMember>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool_4d360b1f_bc2c_4ab7_9884_1f03ba2768f7.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool_4d360b1f_bc2c_4ab7_9884_1f03ba2768f7.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool_4d360b1f_bc2c_4ab7_9884_1f03ba2768f7.xml
new file mode 100644
index 0000000..89d3400
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool_4d360b1f_bc2c_4ab7_9884_1f03ba2768f7.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<pool
+xmlns="urn:didata.com:api:cloud:types" id="4d360b1f-bc2c-4ab7-9884-1f03ba2768f7" datacenterId="NA9">
+<networkDomainId>553f26b6-2a73-42c3-a78b-6116f11291d0</networkDomainId>
+<name>myDevelopmentPool.1</name>
+<description>Pool for load balancing development application
+servers.</description>
+<loadBalanceMethod>ROUND_ROBIN</loadBalanceMethod>
+<healthMonitor id="01683574-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Http"/>
+<healthMonitor id="0168546c-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Https"/>
+<serviceDownAction>RESELECT</serviceDownAction>
+<slowRampTime>10</slowRampTime>
+<state>NORMAL</state>
+<createTime>2015-06-04T09:15:07.000Z</createTime>
+</pool>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener.xml
new file mode 100644
index 0000000..88a94fa
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<virtualListeners
+xmlns="urn:didata.com:api:cloud:types" pageNumber="1" pageCount="5"
+totalCount="5" pageSize="250">
+<virtualListener id="6115469d-a8bb-445b-bb23-d23b5283f2b9"
+datacenterId="NA9">
+<networkDomainId>553f26b6-2a73-42c3-a78b-
+6116f11291d0</networkDomainId>
+<name>myProduction.Virtual.Listener</name>
+<state>NORMAL</state>
+<description>Virtual Listener for load balancing our test
+systems.</description>
+<createTime>2015-05-28T15:59:49.000Z</createTime>
+<type>PERFORMANCE_LAYER_4</type>
+<protocol>HTTP</protocol>
+<listenerIpAddress>165.180.12.22</listenerIpAddress>
+<port>8899</port>
+<enabled>true</enabled>
+<connectionLimit>10000</connectionLimit>
+<connectionRateLimit>400</connectionRateLimit>
+<sourcePortPreservation>PRESERVE</sourcePortPreservation>
+<pool id="afb1fb1a-eab9-43f4-95c2-36a4cdda6cb8"
+name="myProductionPool.1">
+<loadBalanceMethod>ROUND_ROBIN</loadBalanceMethod>
+<serviceDownAction>NONE</serviceDownAction>
+<slowRampTime>10</slowRampTime>
+<healthMonitor id="01683574-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Http"/>
+<healthMonitor id="0168546c-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Https"/>
+</pool>
+<clientClonePool id="6f2f5d7b-cdd9-4d84-8ad7-999b64a87978"
+name="myDevelopmentPool.1">
+<loadBalanceMethod>ROUND_ROBIN</loadBalanceMethod>
+<serviceDownAction>RESELECT</serviceDownAction>
+<slowRampTime>10</slowRampTime>
+<healthMonitor id="01683574-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Http"/>
+<healthMonitor id="0168546c-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Https"/>
+</clientClonePool>
+<persistenceProfile id="a34ca25c-f3db-11e4-b010-005056806999"
+name="CCDEFAULT.DestinationAddress"/>
+<fallbackPersistenceProfile id="a34ca3f6-f3db-11e4-b010-005056806999"
+name="CCDEFAULT.SourceAddress"/>
+<irule id="2b20abd9-ffdc-11e4-b010-005056806999"
+name="CCDEFAULT.IpProtocolTimers"/>
+<irule id="2b20e790-ffdc-11e4-b010-005056806999"
+name="CCDEFAULT.Ips"/>
+</virtualListener>
+</virtualListeners>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener_6115469d_a8bb_445b_bb23_d23b5283f2b9.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener_6115469d_a8bb_445b_bb23_d23b5283f2b9.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener_6115469d_a8bb_445b_bb23_d23b5283f2b9.xml
new file mode 100644
index 0000000..aea2f6f
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener_6115469d_a8bb_445b_bb23_d23b5283f2b9.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<virtualListener
+xmlns="urn:didata.com:api:cloud:types" id="6115469d-a8bb-445b-bb23-d23b5283f2b9" datacenterId="NA9">
+<networkDomainId>553f26b6-2a73-42c3-a78b-6116f11291d0</networkDomainId>
+<name>myProduction.Virtual.Listener</name>
+<state>NORMAL</state>
+<description>Virtual Listener for load balancing our test
+systems.</description>
+<createTime>2015-05-28T15:59:49.000Z</createTime>
+<type>PERFORMANCE_LAYER_4</type>
+<protocol>HTTP</protocol>
+<listenerIpAddress>165.180.12.22</listenerIpAddress>
+<port>8899</port>
+<enabled>true</enabled>
+<connectionLimit>10000</connectionLimit>
+<connectionRateLimit>400</connectionRateLimit>
+<sourcePortPreservation>PRESERVE</sourcePortPreservation>
+<pool id="afb1fb1a-eab9-43f4-95c2-36a4cdda6cb8" name="myProductionPool.1">
+<loadBalanceMethod>ROUND_ROBIN</loadBalanceMethod>
+<serviceDownAction>NONE</serviceDownAction>
+<slowRampTime>10</slowRampTime>
+<healthMonitor id="01683574-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Http"/>
+<healthMonitor id="0168546c-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Https"/>
+</pool>
+<clientClonePool id="6f2f5d7b-cdd9-4d84-8ad7-999b64a87978"
+name="myDevelopmentPool.1">
+<loadBalanceMethod>ROUND_ROBIN</loadBalanceMethod>
+<serviceDownAction>RESELECT</serviceDownAction>
+<slowRampTime>10</slowRampTime>
+<healthMonitor id="01683574-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Http"/>
+<healthMonitor id="0168546c-d487-11e4-811f-005056806999"
+name="CCDEFAULT.Https"/>
+</clientClonePool>
+<persistenceProfile id="a34ca25c-f3db-11e4-b010-005056806999"
+name="CCDEFAULT.DestinationAddress"/>
+<fallbackPersistenceProfile id="a34ca3f6-f3db-11e4-b010-005056806999"
+name="CCDEFAULT.SourceAddress"/>
+<irule id="2b20abd9-ffdc-11e4-b010-005056806999"
+name="CCDEFAULT.IpProtocolTimers"/>
+<irule id="2b20e790-ffdc-11e4-b010-005056806999" name="CCDEFAULT.Ips"/>
+</virtualListener>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/test/loadbalancer/fixtures/dimensiondata/oec_0_9_myaccount.xml
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/fixtures/dimensiondata/oec_0_9_myaccount.xml b/libcloud/test/loadbalancer/fixtures/dimensiondata/oec_0_9_myaccount.xml
new file mode 100644
index 0000000..4f3b132
--- /dev/null
+++ b/libcloud/test/loadbalancer/fixtures/dimensiondata/oec_0_9_myaccount.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<ns3:Account xmlns="http://oec.api.opsource.net/schemas/server" xmlns:ns9="http://oec.api.opsource.net/schemas/reset" xmlns:ns5="http://oec.api.opsource.net/schemas/vip" xmlns:ns12="http://oec.api.opsource.net/schemas/general" xmlns:ns6="http://oec.api.opsource.net/schemas/imageimportexport" xmlns:ns13="http://oec.api.opsource.net/schemas/support" xmlns:ns7="http://oec.api.opsource.net/schemas/whitelabel" xmlns:ns10="http://oec.api.opsource.net/schemas/ipplan" xmlns:ns8="http://oec.api.opsource.net/schemas/datacenter" xmlns:ns11="http://oec.api.opsource.net/schemas/storage" xmlns:ns2="http://oec.api.opsource.net/schemas/organization" xmlns:ns4="http://oec.api.opsource.net/schemas/network" xmlns:ns3="http://oec.api.opsource.net/schemas/directory">
+    <ns3:userName>testuser</ns3:userName>
+    <ns3:fullName>Test User</ns3:fullName>
+    <ns3:firstName>Test</ns3:firstName>
+    <ns3:lastName>User</ns3:lastName>
+    <ns3:emailAddress>test@example.com</ns3:emailAddress>
+    <ns3:orgId>8a8f6abc-2745-4d8a-9cbc-8dabe5a7d0e4</ns3:orgId>
+    <ns3:roles>
+        <ns3:role>
+            <ns3:name>create image</ns3:name>
+        </ns3:role>
+        <ns3:role>
+            <ns3:name>reports</ns3:name>
+        </ns3:role>
+        <ns3:role>
+            <ns3:name>server</ns3:name>
+        </ns3:role>
+        <ns3:role>
+            <ns3:name>primary administrator</ns3:name>
+        </ns3:role>
+        <ns3:role>
+            <ns3:name>network</ns3:name>
+        </ns3:role>
+    </ns3:roles>
+</ns3:Account>

http://git-wip-us.apache.org/repos/asf/libcloud/blob/b90c5610/libcloud/test/loadbalancer/test_dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/test/loadbalancer/test_dimensiondata.py b/libcloud/test/loadbalancer/test_dimensiondata.py
new file mode 100644
index 0000000..0c62087
--- /dev/null
+++ b/libcloud/test/loadbalancer/test_dimensiondata.py
@@ -0,0 +1,160 @@
+# 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
+import unittest
+from libcloud.utils.py3 import httplib
+
+from libcloud.common.types import InvalidCredsError
+from libcloud.loadbalancer.base import LoadBalancer
+from libcloud.loadbalancer.drivers.dimensiondata import DimensionDataLBDriver as DimensionData
+from libcloud.loadbalancer.types import State
+from libcloud.common.dimensiondata import DimensionDataAPIException
+
+from libcloud.test import MockHttp
+from libcloud.test.file_fixtures import LoadBalancerFileFixtures
+
+from libcloud.test.secrets import DIMENSIONDATA_PARAMS
+
+
+class DimensionDataTests(unittest.TestCase):
+
+    def setUp(self):
+        DimensionData.connectionCls.conn_classes = (None, DimensionDataMockHttp)
+        DimensionDataMockHttp.type = None
+        self.driver = DimensionData(*DIMENSIONDATA_PARAMS)
+
+    def test_invalid_creds(self):
+        DimensionDataMockHttp.type = 'UNAUTHORIZED'
+        try:
+            self.driver.list_balancers()
+            self.assertTrue(
+                False)  # Above command should have thrown an InvalidCredsException
+        except InvalidCredsError:
+            pass
+
+    def test_list_balancers(self):
+        bal = self.driver.list_balancers()
+        self.assertEqual(bal[0].name, 'myProduction.Virtual.Listener')
+        self.assertEqual(bal[0].id, '6115469d-a8bb-445b-bb23-d23b5283f2b9')
+        self.assertEqual(bal[0].port, '8899')
+        self.assertEqual(bal[0].ip, '165.180.12.22')
+        self.assertEqual(bal[0].state, State.RUNNING)
+
+    def test_balancer_list_members(self):
+        extra={}
+        extra['pool_id']='4d360b1f-bc2c-4ab7-9884-1f03ba2768f7'
+        balancer = LoadBalancer(
+            id='234',
+            name='test',
+            state=State.RUNNING,
+            ip='1.2.3.4',
+            port=1234,
+            driver=self.driver,
+            extra=extra
+        )
+        members = self.driver.balancer_list_members(balancer)
+        self.assertEqual(2, len(members))
+        self.assertEqual(members[0].ip, '10.0.3.13')
+        self.assertEqual(members[0].id, '3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
+        self.assertEqual(members[0].port, 9889)
+
+    def test_get_balancer(self):
+        bal = self.driver.get_balancer('6115469d-a8bb-445b-bb23-d23b5283f2b9')
+        self.assertEqual(bal.name, 'myProduction.Virtual.Listener')
+        self.assertEqual(bal.id, '6115469d-a8bb-445b-bb23-d23b5283f2b9')
+        self.assertEqual(bal.port, '8899')
+        self.assertEqual(bal.ip, '165.180.12.22')
+        self.assertEqual(bal.state, State.RUNNING)
+
+    def test_list_protocols(self):
+        protocols = self.driver.list_protocols()
+        self.assertNotEqual(0, len(protocols))
+    
+    def test_get_pools(self):
+        pools = self.driver.ex_get_pools()
+        self.assertNotEqual(0, len(pools))
+        self.assertEqual(pools[0].name, 'myDevelopmentPool.1')
+        self.assertEqual(pools[0].id, '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
+        
+    def test_get_pool(self):
+        pool = self.driver.ex_get_pool('4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
+        self.assertEqual(pool.name, 'myDevelopmentPool.1')
+        self.assertEqual(pool.id, '4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
+
+    def test_get_pool_members(self):
+        members = self.driver.ex_get_pool_members('4d360b1f-bc2c-4ab7-9884-1f03ba2768f7')
+        self.assertEqual(2, len(members))
+        self.assertEqual(members[0].id, '3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
+        self.assertEqual(members[0].name, '10.0.3.13')
+        self.assertEqual(members[0].status, 'NORMAL')
+        self.assertEqual(members[0].ip_address, '10.0.3.13')
+        self.assertEqual(members[0].port, 9889)
+    
+    def test_get_pool_member(self):
+        member = self.driver.ex_get_pool_member('3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
+        self.assertEqual(member.id, '3dd806a2-c2c8-4c0c-9a4f-5219ea9266c0')
+        self.assertEqual(member.name, '10.0.3.13')
+        self.assertEqual(member.status, 'NORMAL')
+        self.assertEqual(member.ip_address, '10.0.3.13')
+        self.assertEqual(member.port, 9889)
+
+class DimensionDataMockHttp(MockHttp):
+
+    fixtures = LoadBalancerFileFixtures('dimensiondata')
+
+    def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers):
+        return (httplib.UNAUTHORIZED, "", {}, httplib.responses[httplib.UNAUTHORIZED])
+
+    def _oec_0_9_myaccount(self, method, url, body, headers):
+        body = self.fixtures.load('oec_0_9_myaccount.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _oec_0_9_myaccount_INPROGRESS(self, method, url, body, headers):
+        body = self.fixtures.load('oec_0_9_myaccount.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener_6115469d_a8bb_445b_bb23_d23b5283f2b9(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_virtualListener_6115469d_a8bb_445b_bb23_d23b5283f2b9.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool_4d360b1f_bc2c_4ab7_9884_1f03ba2768f7(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_pool_4d360b1f_bc2c_4ab7_9884_1f03ba2768f7.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+    
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+    def _caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember_3dd806a2_c2c8_4c0c_9a4f_5219ea9266c0(self, method, url, body, headers):
+        body = self.fixtures.load(
+            'caas_2_0_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_poolMember_3dd806a2_c2c8_4c0c_9a4f_5219ea9266c0.xml')
+        return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())


[17/21] libcloud git commit: [LIBCLOUD-737] Pad it out.

Posted by to...@apache.org.
[LIBCLOUD-737] Pad it out.


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

Branch: refs/heads/trunk
Commit: 06b11e8a30515faa50af163697ba5a39de133445
Parents: 19ccf58
Author: Anthony Shaw <an...@gmail.com>
Authored: Sun Aug 30 22:02:06 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Sun Aug 30 22:02:06 2015 +1000

----------------------------------------------------------------------
 libcloud/loadbalancer/drivers/dimensiondata.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/06b11e8a/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index 401c6de..bd72e7f 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -240,7 +240,7 @@ class DimensionDataLBDriver(Driver):
         """
         node = self.ex_create_node(
             network_domain_id=balancer.extra['network_domain_id'],
-            name='Member.'+member.ip,
+            name='Member.' + member.ip,
             ip=member.ip,
             ex_description=''
         )


[09/21] libcloud git commit: [LIBCLOUD-737] Added create_listener to create the pool, add the nodes to the pool and create a virtual listener on the big-ip. Added docstrings to some of the methods. todo - complete unit tests for extended methods

Posted by to...@apache.org.
[LIBCLOUD-737] Added create_listener to create the pool, add the nodes to the pool and create a virtual listener on the big-ip. Added docstrings to some of the methods. todo - complete unit tests for extended methods


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

Branch: refs/heads/trunk
Commit: 2709109c7e015220f4871e93eb345f78241c31b3
Parents: b4ed5ea
Author: Anthony Shaw <an...@gmail.com>
Authored: Wed Aug 26 20:51:19 2015 +1000
Committer: Anthony Shaw <an...@gmail.com>
Committed: Wed Aug 26 20:51:19 2015 +1000

----------------------------------------------------------------------
 libcloud/loadbalancer/drivers/dimensiondata.py | 272 +++++++++++++++++++-
 1 file changed, 263 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/2709109c/libcloud/loadbalancer/drivers/dimensiondata.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index e44b77e..dc6d728 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -84,7 +84,56 @@ class DimensionDataLBDriver(Driver):
         return kwargs
 
     def create_balancer(self, name, port, protocol, algorithm, members):
+        """
+        Create a new load balancer instance
+
+        :param name: Name of the new load balancer (required)
+        :type  name: ``str``
+
+        :param port: Port the load balancer should listen on, defaults to 80
+        :type  port: ``str``
+
+        :param protocol: Loadbalancer protocol, defaults to http.
+        :type  protocol: ``str``
+
+        :param members: list of Members to attach to balancer
+        :type  members: ``list`` of :class:`Member`
+
+        :param algorithm: Load balancing algorithm, defaults to ROUND_ROBIN.
+        :type algorithm: :class:`.Algorithm`
+
+        :rtype: :class:`LoadBalancer`
+        """
+        # TODO: Figure out which location is used...
+        network_domain_id=None
+        
+        # Create a pool first 
+        pool_id=self.ex_create_pool(
+            network_domain_id=network_domain_id,
+            name=name,
+            ex_description=None,
+            balancer_method=_ALGORITHM_TO_VALUE_MAP.get(algorithm)
+            )
         
+        # Attach the members to the pool as nodes
+        for member in members:
+            node_id=self.ex_create_node(
+                network_domain_id=network_domain_id,
+                name=member.name,
+                ip=member.ip,
+                ex_description=None
+                )
+            self.ex_create_pool_member(
+                pool_id=pool_id,
+                node_id=node_id,
+                port=port)
+            
+        # Create the virtual listener (balancer)
+        self.ex_create_virtual_listener(
+                       network_domain_id=network_domain_id,
+                       name=name,
+                       ex_description=None,
+                       port=port)
         return True
 
     def list_balancers(self):
@@ -124,7 +173,7 @@ class DimensionDataLBDriver(Driver):
 
         :rtype: ``list`` of ``str``
         """
-        return ['dns', 'ftp', 'http', 'https', 'tcp', 'udp']
+        return ['http', 'https', 'tcp', 'udp']
 
     def balancer_list_members(self, balancer):
         """
@@ -152,37 +201,240 @@ class DimensionDataLBDriver(Driver):
         return members
 
     def balancer_attach_member(self, balancer, member):
-        return True
+        """
+        Attach a member to balancer
 
-    def balancer_attach_compute_node(self, balancer, node):
+        :param balancer: LoadBalancer which should be used
+        :type  balancer: :class:`LoadBalancer`
+
+        :param member: Member to join to the balancer
+        :type member: :class:`Member`
+
+        :return: Member after joining the balancer.
+        :rtype: :class:`Member`
+        """
+        
+        nodeId= self.ex_create_node(
+            network_domain_id=balancer.extra['network_domain_id'],
+            name=member.name,
+            ip=member.ip,
+            ex_description=member.description
+        )
+        if nodeId == false:
+            return False
+        
+        poolMemberId = self.ex_create_pool_member(balancer.extra['pool_id'],
+                                                  nodeId,
+                                                  member.port)
+        
         return True
 
     def balancer_detach_member(self, balancer, member):
+        """
+        Detach member from balancer
+
+        :param balancer: LoadBalancer which should be used
+        :type  balancer: :class:`LoadBalancer`
+
+        :param member: Member which should be used
+        :type member: :class:`Member`
+
+        :return: ``True`` if member detach was successful, otherwise ``False``.
+        :rtype: ``bool``
+        """
+        
+        create_pool_m = ET.Element('removePoolMember', {'xmlns': SERVER_NS,
+                                                        'id': member.id})
+
+        self.connection.request_with_orgId_api_2(
+            'networkDomainVip/removePoolMember',
+            method='POST',
+            data=ET.tostring(create_pool_m)).object
+        
         return True
 
     def destroy_balancer(self, balancer):
+        """
+        Destroy a load balancer (virtual listener)
+
+        :param balancer: LoadBalancer which should be used
+        :type  balancer: :class:`LoadBalancer`
+
+        :return: ``True`` if the destroy was successful, otherwise ``False``.
+        :rtype: ``bool``
+        """
+        
+        delete_listener = ET.Element('deleteVirtualListener', {'xmlns': SERVER_NS,
+                                                               'id': balancer.id})
+
+        self.connection.request_with_orgId_api_2(
+            'networkDomainVip/deleteVirtualListener',
+            method='POST',
+            data=ET.tostring(delete_listener)).object
         return True
 
+    def ex_create_pool_member(self, pool_id, node_id, port):
+        """
+        Create a new member in an existing pool from an existing node
+
+        :param pool_id: ID of the pool (required)
+        :type  name: ``str``
+
+        :param node_id: ID of the node (required)
+        :type  name: ``str``
+
+        :param port: Port the the service will listen on
+        :type  port: ``str``
+
+        :return: ID of the node member, ``False`` if failed to add. 
+        :rtype: ``str``
+        """
+        create_pool_m = ET.Element('addPoolMember', {'xmlns': SERVER_NS})
+        ET.SubElement(create_pool_m, "poolId").text = pool_id
+        ET.SubElement(create_pool_m, "nodeId").text = node_id
+        ET.SubElement(create_pool_m, "port").text = port
+
+        response = self.connection.request_with_orgId_api_2(
+            'networkDomainVip/addPoolMember',
+            method='POST',
+            data=ET.tostring(create_pool_m)).object
+        
+        for info in findall(response, 'info', TYPES_URN):
+            if info.name == 'poolMemberId':
+                return info.value
+        
+        return False
+
     def ex_create_node(self,
                        network_domain_id,
                        name,
                        ip,
                        ex_description,
-                       connectionLimit=25000,
-                       connectionRateLimit=2000):
+                       connection_limit=25000,
+                       connection_rate_limit=2000):
+        """
+        Create a new node
+
+        :param network_domain_id: Network Domain ID (required)
+        :type  name: ``str``
+
+        :param name: name of the node (required)
+        :type  name: ``str``
+
+        :param ip: IPv4 address of the node (required)
+        :type  ip: ``str``
+
+        :param ex_description: Description of the node
+        :type  ex_description: ``str``
+        
+        :param connection_limit: Maximum number of concurrent connections per sec
+        :type  connection_limit: ``int``
+        
+        :param connection_rate_limit: Maximum number of concurrent sessions
+        :type  connection_rate_limit: ``int``
+
+        :return: ID of the node, ``False`` if failed to add. 
+        :rtype: ``str``
+        """
         create_node_elm = ET.Element('createNode', {'xmlns': SERVER_NS})
         ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
         ET.SubElement(create_node_elm, "description").text = ex_description
         ET.SubElement(create_node_elm, "name").text = name
         ET.SubElement(create_node_elm, "ipv4Address").text = ip
-        ET.SubElement(create_node_elm, "connectionLimit").text = connectionLimit
-        ET.SubElement(create_node_elm, "connectionRateLimit").text = connectionRateLimit
+        ET.SubElement(create_node_elm, "connectionLimit").text = connection_limit
+        ET.SubElement(create_node_elm, "connectionRateLimit").text = connection_rate_limit
 
-        self.connection.request_with_orgId_api_2(
+        response = self.connection.request_with_orgId_api_2(
             'networkDomainVip/createNode',
             method='POST',
             data=ET.tostring(create_node_elm)).object
-        return True
+        
+        for info in findall(response, 'info', TYPES_URN):
+            if info.name == 'nodeId':
+                return info.value
+        
+        return None
+
+    def ex_create_pool(self,
+                       network_domain_id,
+                       name,
+                       balancer_method,
+                       ex_description,
+                       service_down_action='NONE',
+                       slow_ramp_time=30):
+        """
+        Create a new pool
+
+        :param network_domain_id: Network Domain ID (required)
+        :type  name: ``str``
+
+        :param name: name of the node (required)
+        :type  name: ``str``
+
+        :param balancer_method: The load balancer algorithm (required)
+        :type  balancer_method: ``str``
+
+        :param ex_description: Description of the node
+        :type  ex_description: ``str``
+        
+        :param service_down_action: What to do when node is unavailable NONE, DROP or RESELECT
+        :type  service_down_action: ``str``
+        
+        :param slow_ramp_time: Number of seconds to stagger ramp up of nodes
+        :type  slow_ramp_time: ``int``
+
+        :return: ID of the pool, ``False`` if failed to add. 
+        :rtype: ``str``
+        """
+        create_node_elm = ET.Element('createPool', {'xmlns': SERVER_NS})
+        ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
+        ET.SubElement(create_node_elm, "description").text = ex_description
+        ET.SubElement(create_node_elm, "name").text = name
+        ET.SubElement(create_node_elm, "loadBalancerMethod").text = balancer_method
+        ET.SubElement(create_node_elm, "serviceDownAction").text = service_down_action
+        ET.SubElement(create_node_elm, "slowRampTime").text = slow_ramp_time
+
+        response = self.connection.request_with_orgId_api_2(
+            'networkDomainVip/createPool',
+            method='POST',
+            data=ET.tostring(create_node_elm)).object
+        
+        for info in findall(response, 'info', TYPES_URN):
+            if info.name == 'poolId':
+                return info.value
+        
+        return False
+
+    def ex_create_virtual_listener(self,
+                       network_domain_id,
+                       name,
+                       ex_description,
+                       port,
+                       listener_type='STANDARD',
+                       protocol='ANY',
+                       connection_limit=25000,
+                       connection_rate_limit=2000,
+                       source_port_preservation='PRESERVE'):
+        create_node_elm = ET.Element('createVirtualListener', {'xmlns': SERVER_NS})
+        ET.SubElement(create_node_elm, "networkDomainId").text = network_domain_id
+        ET.SubElement(create_node_elm, "description").text = ex_description
+        ET.SubElement(create_node_elm, "name").text = name
+        ET.SubElement(create_node_elm, "port").text = port
+        ET.SubElement(create_node_elm, "type").text = listener_type
+        ET.SubElement(create_node_elm, "connectionLimit").text = connection_limit
+        ET.SubElement(create_node_elm, "connectionRateLimit").text = connection_rate_limit
+        ET.SubElement(create_node_elm, "sourcePortPreservation").text = source_port_preservation
+
+        response = self.connection.request_with_orgId_api_2(
+            'networkDomainVip/createVirtualListener',
+            method='POST',
+            data=ET.tostring(create_node_elm)).object
+        
+        for info in findall(response, 'info', TYPES_URN):
+            if info.name == 'poolId':
+                return info.value
+        
+        return False
 
     def ex_get_pools(self):
         pools = self.connection \
@@ -223,6 +475,8 @@ class DimensionDataLBDriver(Driver):
         extra['pool_id'] = element.find(fixxpath(
                 'pool',
                 TYPES_URN)).get('id')
+        extra['network_domain_id'] = findtext(element, 'networkDomainId',
+                                              TYPES_URN)
         
         balancer = LoadBalancer(
             id=element.get('id'),