LIBCLOUD-750 fixed bug where is_started must be lowercase otherwise live API throws error. Updated tests which weren't previously providing values. Added extra parameters to the list methods to filter by location. Optimised the way each of the calls gets the location by fetching it once for a collection instead of each iteration. Fixed the ID lookup of VLAN and Network Domain.
Closes #587 Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/ee1be173 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/ee1be173 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/ee1be173 Branch: refs/heads/trunk Commit: ee1be1737a797233e3ea836b4d5525a825a9c58c Parents: 09ec78d Author: Anthony Shaw <[email protected]> Authored: Thu Sep 24 09:01:44 2015 +1000 Committer: Tomaz Muraus <[email protected]> Committed: Sat Sep 26 22:37:13 2015 +0200 ---------------------------------------------------------------------- libcloud/compute/drivers/dimensiondata.py | 88 +++++++++++++++++------- libcloud/test/compute/test_dimensiondata.py | 4 +- 2 files changed, 64 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/ee1be173/libcloud/compute/drivers/dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py index a7de6d4..01bdae4 100644 --- a/libcloud/compute/drivers/dimensiondata.py +++ b/libcloud/compute/drivers/dimensiondata.py @@ -129,7 +129,7 @@ class DimensionDataNodeDriver(NodeDriver): ET.SubElement(server_elm, "name").text = name ET.SubElement(server_elm, "description").text = ex_description ET.SubElement(server_elm, "imageId").text = image.id - ET.SubElement(server_elm, "start").text = str(ex_is_started) + ET.SubElement(server_elm, "start").text = str(ex_is_started).lower() ET.SubElement(server_elm, "administratorPassword").text = password if ex_network is not None: @@ -193,8 +193,14 @@ class DimensionDataNodeDriver(NodeDriver): @inherits: :class:`NodeDriver.list_images` """ + params = {} + if location is not None: + params['location'] = location.id + return self._to_base_images( - self.connection.request_api_1('base/image').object) + self.connection.request_api_1('base/imageWithDiskSpeed', + params=params) + .object) def list_sizes(self, location=None): """ @@ -237,24 +243,32 @@ class DimensionDataNodeDriver(NodeDriver): :return: a list of DimensionDataNetwork objects :rtype: ``list`` of :class:`DimensionDataNetwork` """ + params = {} + if location is not None: + params['location'] = location.id + return self._to_networks( self.connection - .request_with_orgId_api_1('networkWithLocation').object) + .request_with_orgId_api_1('networkWithLocation', params=params) + .object) def _to_base_images(self, object): images = [] - for element in object.findall(fixxpath("ServerImage", SERVER_NS)): - images.append(self._to_base_image(element)) + locations = self.list_locations() + print(locations) + for element in object.findall(fixxpath("image", SERVER_NS)): + images.append(self._to_base_image(element, locations)) return images - def _to_base_image(self, element): + def _to_base_image(self, element, locations): # Eventually we will probably need multiple _to_image() functions # that parse <ServerImage> differently than <DeployedImage>. # DeployedImages are customer snapshot images, and ServerImages are # 'base' images provided by DimensionData - location_id = findtext(element, 'location', SERVER_NS) - location = self.ex_get_location_by_id(location_id) + location_id = element.get('location') + location = list(filter(lambda x: x.id == location_id, + locations))[0] extra = { 'description': findtext(element, 'description', SERVER_NS), @@ -271,7 +285,7 @@ class DimensionDataNodeDriver(NodeDriver): 'location': location, } - return NodeImage(id=str(findtext(element, 'id', SERVER_NS)), + return NodeImage(id=element.get('id'), name=str(findtext(element, 'name', SERVER_NS)), extra=extra, driver=self.connection.driver) @@ -357,7 +371,7 @@ class DimensionDataNodeDriver(NodeDriver): result = findtext(body, 'responseCode', TYPES_URN) return result == 'IN_PROGRESS' - def ex_list_networks(self): + def ex_list_networks(self, location=None): """ List networks deployed across all data center locations for your organization. The response includes the location of each network. @@ -365,11 +379,16 @@ class DimensionDataNodeDriver(NodeDriver): :return: a list of DimensionDataNetwork objects :rtype: ``list`` of :class:`DimensionDataNetwork` """ + params = {} + if location is not None: + params['location'] = location.id + response = self.connection \ - .request_with_orgId_api_1('networkWithLocation').object + .request_with_orgId_api_1('networkWithLocation', + params=params).object return self._to_networks(response) - def ex_list_network_domains(self): + def ex_list_network_domains(self, location=None): """ List networks deployed across all data center locations for your organization. The response includes the location of each network. @@ -377,18 +396,29 @@ class DimensionDataNodeDriver(NodeDriver): :return: a list of DimensionDataNetwork objects :rtype: ``list`` of :class:`DimensionDataNetwork` """ + params = {} + if location is not None: + params['datacenterId'] = location.id + response = self.connection \ - .request_with_orgId_api_2('network/networkDomain').object + .request_with_orgId_api_2('network/networkDomain', + params=params).object return self._to_network_domains(response) - def ex_list_vlans(self): + def ex_list_vlans(self, location=None, network_domain=None): """ 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') \ + params = {} + if location is not None: + params['datacenterId'] = location.id + if network_domain is not None: + params['networkDomainId'] = network_domain.id + response = self.connection.request_with_orgId_api_2('network/vlan', + params=params) \ .object return self._to_vlans(response) @@ -409,12 +439,13 @@ class DimensionDataNodeDriver(NodeDriver): def _to_networks(self, object): networks = [] + locations = self.list_locations() for element in findall(object, 'network', NETWORK_NS): - networks.append(self._to_network(element)) + networks.append(self._to_network(element, locations)) return networks - def _to_network(self, element): + def _to_network(self, element, locations): multicast = False if findtext(element, 'multicast', NETWORK_NS) == 'true': multicast = True @@ -422,7 +453,8 @@ class DimensionDataNodeDriver(NodeDriver): status = self._to_status(element.find(fixxpath('status', NETWORK_NS))) location_id = findtext(element, 'location', NETWORK_NS) - location = self.ex_get_location_by_id(location_id) + location = list(filter(lambda x: x.id == location_id, + locations))[0] return DimensionDataNetwork( id=findtext(element, 'id', NETWORK_NS), @@ -437,16 +469,18 @@ class DimensionDataNodeDriver(NodeDriver): def _to_network_domains(self, object): network_domains = [] + locations = self.list_locations() for element in findall(object, 'networkDomain', TYPES_URN): - network_domains.append(self._to_network_domain(element)) + network_domains.append(self._to_network_domain(element, locations)) return network_domains - def _to_network_domain(self, element): + def _to_network_domain(self, element, locations): status = self._to_status(element.find(fixxpath('state', TYPES_URN))) - location_id = element.get('datacenter') - location = self.ex_get_location_by_id(location_id) + location_id = element.get('datacenterId') + location = list(filter(lambda x: x.id == location_id, + locations))[0] return DimensionDataNetworkDomain( id=element.get('id'), @@ -458,16 +492,18 @@ class DimensionDataNodeDriver(NodeDriver): def _to_vlans(self, object): vlans = [] + locations = self.list_locations() for element in findall(object, 'vlan', TYPES_URN): - vlans.append(self._to_vlan(element)) + vlans.append(self._to_vlan(element, locations=locations)) return vlans - def _to_vlan(self, element): + def _to_vlan(self, element, locations): status = self._to_status(element.find(fixxpath('state', TYPES_URN))) - location_id = element.get('location') - location = self.ex_get_location_by_id(location_id) + location_id = element.get('datacenterId') + location = list(filter(lambda x: x.id == location_id, + locations))[0] return DimensionDataVlan( id=element.get('id'), http://git-wip-us.apache.org/repos/asf/libcloud/blob/ee1be173/libcloud/test/compute/test_dimensiondata.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_dimensiondata.py b/libcloud/test/compute/test_dimensiondata.py index 4051b9e..a301831 100644 --- a/libcloud/test/compute/test_dimensiondata.py +++ b/libcloud/test/compute/test_dimensiondata.py @@ -111,7 +111,7 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin): network = self.driver.ex_list_networks()[0] node = self.driver.create_node(name='test2', image=image, auth=rootPw, ex_description='test2 node', ex_network=network, - ex_isStarted=False) + ex_is_started=False) self.assertEqual(node.id, 'e75ead52-692f-4314-8725-c8a4f4d13a87') self.assertEqual(node.extra['status'].action, 'DEPLOY_SERVER') @@ -124,7 +124,7 @@ class DimensionDataTests(unittest.TestCase, TestCaseMixin): ex_description='test2 node', ex_network_domain=network_domain, ex_vlan=vlan, - ex_isStarted=False) + ex_is_started=False) self.assertEqual(node.id, 'e75ead52-692f-4314-8725-c8a4f4d13a87') self.assertEqual(node.extra['status'].action, 'DEPLOY_SERVER')
