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'),