Updated Branches: refs/heads/0.12.x 0e7b2f46d -> 5c7b98d31 refs/heads/trunk e478d9102 -> 33d4f48eb
Issue LIBCLOUD-349: Implementation of list_images and list_network for Cloudstack driver. Signed-off-by: Tomaz Muraus <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/d285b9a0 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/d285b9a0 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/d285b9a0 Branch: refs/heads/trunk Commit: d285b9a003070a17e61caf6816c71923d14f09a4 Parents: e478d91 Author: Philipp Strube <[email protected]> Authored: Mon Jun 24 15:03:04 2013 -0700 Committer: Tomaz Muraus <[email protected]> Committed: Tue Jun 25 09:44:22 2013 +0200 ---------------------------------------------------------------------- libcloud/compute/drivers/cloudstack.py | 48 +++++++++++++++++--- .../cloudstack/listNetworks_default.json | 2 +- libcloud/test/compute/test_cloudstack.py | 42 +++++++++++++++-- 3 files changed, 81 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/d285b9a0/libcloud/compute/drivers/cloudstack.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/cloudstack.py b/libcloud/compute/drivers/cloudstack.py index 74799c6..d8f28de 100644 --- a/libcloud/compute/drivers/cloudstack.py +++ b/libcloud/compute/drivers/cloudstack.py @@ -99,6 +99,23 @@ class CloudStackDiskOffering(object): return self.__class__ is other.__class__ and self.id == other.id +class CloudStackNetwork(object): + """Class representing a CloudStack Network""" + + def __init__(self, displaytext, name, networkofferingid, id, zoneid): + self.displaytext = displaytext + self.name = name + self.networkofferingid = networkofferingid + self.id = id + self.zoneid = zoneid + + def __repr__(self): + return (('<CloudStackNetwork: id=%s, displaytext=%s, name=%s, ' + 'networkofferingid=%s, zoneid=%s, dirver=%s>') + % (self.id, self.displaytext, self.name, + self.networkofferingid, self.zoneid, self.driver.name)) + + class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver): """Driver for the CloudStack API. @@ -157,13 +174,14 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver): imgs = self._sync_request('listTemplates', **args) images = [] for img in imgs.get('template', []): - images.append(NodeImage(img['id'], img['name'], self, - {'hypervisor': img['hypervisor'], - 'format': img['format'], - 'os': img['ostypename'], - } - ) - ) + images.append(NodeImage( + id=img['id'], + name=img['name'], + driver=self.connection.driver, + extra={ + 'hypervisor': img['hypervisor'], + 'format': img['format'], + 'os': img['ostypename']})) return images def list_locations(self): @@ -365,6 +383,22 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver): return diskOfferings + def ex_list_networks(self): + """List the available networks""" + + nets = self._sync_request('listNetworks')['network'] + + networks = [] + for net in nets: + networks.append(CloudStackNetwork( + net['displaytext'], + net['name'], + net['networkofferingid'], + net['id'], + net['zoneid'])) + + return networks + def create_volume(self, size, name, location, snapshot=None): # TODO Add snapshot handling for diskOffering in self.ex_list_disk_offerings(): http://git-wip-us.apache.org/repos/asf/libcloud/blob/d285b9a0/libcloud/test/compute/fixtures/cloudstack/listNetworks_default.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/cloudstack/listNetworks_default.json b/libcloud/test/compute/fixtures/cloudstack/listNetworks_default.json index 2701347..7f696f0 100644 --- a/libcloud/test/compute/fixtures/cloudstack/listNetworks_default.json +++ b/libcloud/test/compute/fixtures/cloudstack/listNetworks_default.json @@ -1 +1 @@ -{ "listnetworksresponse" : { "network" : [ {"id":860,"name":"Virtual Network","displaytext":"A dedicated virtualized network for your account. The broadcast domain is contained within a VLAN and all public network access is routed out by a virtual router.","broadcastdomaintype":"Vlan","traffictype":"Guest","zoneid":1,"networkofferingid":6,"networkofferingname":"DefaultVirtualizedNetworkOffering","networkofferingdisplaytext":"Virtual Vlan","networkofferingavailability":"Required","isshared":false,"issystem":false,"state":"Implemented","related":860,"broadcasturi":"vlan://1459","dns1":"1.1.1.1","dns2":"1.1.1.2","type":"Virtual","account":"fakeaccount","domainid":801,"domain":"AA000062-libcloud-dev","isdefault":true,"service":[{"name":"Gateway"},{"name":"Firewall","capability":[{"name":"MultipleIps","value":"true"},{"name":"TrafficStatistics","value":"per public ip"},{"name":"StaticNat","value":"true"},{"name":"SupportedProtocols","value":"tcp,udp"},{"name":"SupportedSourceNatTypes", "value":"per account"}]},{"name":"UserData"},{"name":"Dns"},{"name":"Dhcp"},{"name":"Lb","capability":[{"name":"TrafficStatistics","value":"per public ip"},{"name":"SupportedProtocols","value":"tcp,udp"},{"name":"SupportedLbAlgorithms","value":"roundrobin,leastconn"}]}],"networkdomain":"cs363local","securitygroupenabled":false} ] } } +{ "listnetworksresponse" : {"count": 1, "network": [{"domain": "ROOT", "acltype": "Domain", "specifyipranges": true, "related": "00304a04-c7ea-4e77-a786-18bc64347bf7", "zoneid": "1128bd56-b4d9-4ac6-a7b9-c715b187ce11", "domainid": "4a8857b8-7235-4e31-a7ef-b8b44d180850", "displaytext": "guestNetworkForBasicZone", "id": "00304a04-c7ea-4e77-a786-18bc64347bf7", "canusefordeploy": true, "physicalnetworkid": "07f747f5-b445-487f-b2d7-81a5a512989e", "networkdomain": "cs1cloud.internal", "service": [{"name": "SecurityGroup"}, {"name": "UserData"}, {"name": "Dhcp"}], "state": "Setup", "type": "Shared", "zonename": "CH-GV2", "networkofferingavailability": "Optional", "networkofferingid": "45964a3a-8a1c-4438-a377-0ff1e264047a", "tags": [], "networkofferingdisplaytext": "Exoscale Offering for Shared Security group enabled networks", "subdomainaccess": true, "traffictype": "Guest", "restartrequired": false, "broadcastdomaintype": "Vlan", "name": "guestNetworkForBasicZone", "dns2": "80.245.17.230", "dns1": "80.245.17.229", "networkofferingname": "ExoscaleSharedNetworkOfferingWithSGService", "issystem": false}]} } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/d285b9a0/libcloud/test/compute/test_cloudstack.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_cloudstack.py b/libcloud/test/compute/test_cloudstack.py index 864cff4..31562ff 100644 --- a/libcloud/test/compute/test_cloudstack.py +++ b/libcloud/test/compute/test_cloudstack.py @@ -14,12 +14,13 @@ # limitations under the License. import sys -import unittest from libcloud.utils.py3 import httplib from libcloud.utils.py3 import urlparse from libcloud.utils.py3 import parse_qsl +from libcloud.compute.drivers.cloudstack import CloudStackNodeDriver + try: import simplejson as json except ImportError: @@ -29,6 +30,7 @@ from libcloud.compute.drivers.cloudstack import CloudStackNodeDriver from libcloud.compute.types import DeploymentError, LibcloudError from libcloud.compute.base import Node, NodeImage, NodeSize, NodeLocation +from libcloud.test import unittest from libcloud.test import MockHttpTestCase from libcloud.test.compute import TestCaseMixin from libcloud.test.file_fixtures import ComputeFileFixtures @@ -90,6 +92,21 @@ class CloudStackNodeDriverTest(unittest.TestCase, TestCaseMixin): images = self.driver.list_images() self.assertEquals(0, len(images)) + def test_list_images(self): + _, fixture = CloudStackMockHttp()._load_fixture( + 'listTemplates_default.json') + templates = fixture['listtemplatesresponse']['template'] + + images = self.driver.list_images() + for i, image in enumerate(images): + # NodeImage expects id to be a string, + # the CloudStack fixture has an int + tid = str(templates[i]['id']) + tname = templates[i]['name'] + self.assertIsInstance(image.driver, CloudStackNodeDriver) + self.assertEquals(image.id, tid) + self.assertEquals(image.name, tname) + def test_ex_list_disk_offerings(self): diskOfferings = self.driver.ex_list_disk_offerings() self.assertEquals(1, len(diskOfferings)) @@ -99,6 +116,23 @@ class CloudStackNodeDriverTest(unittest.TestCase, TestCaseMixin): self.assertEquals('Disk offer 1', diskOffering.name) self.assertEquals(10, diskOffering.size) + def test_ex_list_networks(self): + _, fixture = CloudStackMockHttp()._load_fixture( + 'listNetworks_default.json') + fixture_networks = fixture['listnetworksresponse']['network'] + + networks = self.driver.ex_list_networks() + + for i, network in enumerate(networks): + self.assertEquals(network.id, fixture_networks[i]['id']) + self.assertEquals( + network.displaytext, fixture_networks[i]['displaytext']) + self.assertEquals(network.name, fixture_networks[i]['name']) + self.assertEquals( + network.networkofferingid, + fixture_networks[i]['networkofferingid']) + self.assertEquals(network.zoneid, fixture_networks[i]['zoneid']) + def test_create_volume(self): volumeName = 'vol-0' location = self.driver.list_locations()[0] @@ -167,8 +201,10 @@ class CloudStackNodeDriverTest(unittest.TestCase, TestCaseMixin): self.assertEqual(keypairs[0]['fingerprint'], fingerprint) def test_create_keypair(self): - self.assertRaises(LibcloudError, self.driver.ex_create_keypair, - 'cs-keypair') + self.assertRaises( + LibcloudError, + self.driver.ex_create_keypair, + 'cs-keypair') def test_delete_keypair(self): res = self.driver.ex_delete_keypair('cs-keypair')
