Repository: libcloud
Updated Branches:
  refs/heads/trunk 93c38981d -> 33ca3b2e6


Add support for network creation on Cloudstack advanced zones

Closes #316

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


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

Branch: refs/heads/trunk
Commit: 33ca3b2e6209aa5347b3f820b35f06327a98ac5d
Parents: 93c3898
Author: Roeland Kuipers <rkuip...@schubergphilis.com>
Authored: Tue Jun 10 16:58:31 2014 +0200
Committer: Tomaz Muraus <to...@apache.org>
Committed: Thu Jun 12 20:31:44 2014 +0200

----------------------------------------------------------------------
 .gitignore                                      |   3 +
 CHANGES.rst                                     |   6 +
 libcloud/compute/drivers/cloudstack.py          | 175 +++++++++++++++++++
 .../cloudstack/createNetwork_default.json       |   1 +
 .../cloudstack/deleteNetwork_default.json       |   1 +
 .../listNetworkOfferings_default.json           |   1 +
 .../queryAsyncJobResult_deleteNetwork.json      |   1 +
 libcloud/test/compute/test_cloudstack.py        |  57 ++++++
 8 files changed, 245 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/33ca3b2e/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index ce19293..dc61a25 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,6 @@ dist/*apache-libcloud*
 dist/*apache_libcloud*
 _build/
 apache_libcloud.egg-info/
+.project
+.pydevproject
+.settings

http://git-wip-us.apache.org/repos/asf/libcloud/blob/33ca3b2e/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 250430d..8a4e152 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -217,6 +217,12 @@ Compute
   (GITHUB-312)
   [LIBCLOUD-575, Zak Estrada]
 
+- Add support for network management for advanced zones
+  (ex_list_network_offerings, ex_create_network, ex_delete_network) in the 
+  CloudStack driver.
+  (GITHUB-316)
+  [Roeland Kuipers]
+
 Storage
 ~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/33ca3b2e/libcloud/compute/drivers/cloudstack.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/cloudstack.py 
b/libcloud/compute/drivers/cloudstack.py
index 2b69d84..921b68e 100644
--- a/libcloud/compute/drivers/cloudstack.py
+++ b/libcloud/compute/drivers/cloudstack.py
@@ -99,6 +99,22 @@ RESOURCE_EXTRA_ATTRIBUTES_MAP = {
         'can_use_for_deploy': {
             'key_name': 'canusefordeploy',
             'transform_func': str
+        },
+        'gateway': {
+            'key_name': 'gateway',
+            'transform_func': str
+        },
+        'netmask': {
+            'key_name': 'netmask',
+            'transform_func': str
+        },
+        'vpc_id': {
+            'key_name': 'vpcid',
+            'transform_func': str
+        },
+        'project_id': {
+            'key_name': 'projectid',
+            'transform_func': str
         }
     },
     'node': {
@@ -453,6 +469,31 @@ class CloudStackNetwork(object):
                    self.networkofferingid, self.zoneid, self.driver.name))
 
 
+class CloudStackNetworkOffering(object):
+    """
+    Class representing a CloudStack Network Offering.
+    """
+
+    def __init__(self, name, display_text, guest_ip_type, id,
+                 service_offering_id, for_vpc, driver, extra=None):
+        self.display_text = display_text
+        self.name = name
+        self.guest_ip_type = guest_ip_type
+        self.id = id
+        self.service_offering_id = service_offering_id
+        self.for_vpc = for_vpc
+        self.driver = driver
+        self.extra = extra or {}
+
+    def __repr__(self):
+        return (('<CloudStackNetworkOffering: id=%s, name=%s, '
+                 'display_text=%s, guest_ip_type=%s, service_offering_id=%s, '
+                 'for_vpc=%s, driver%s>')
+                % (self.id, self.name, self.display_text,
+                   self.guest_ip_type, self.service_offering_id, self.for_vpc,
+                   self.driver.name))
+
+
 class CloudStackProject(object):
     """
     Class representing a CloudStack Project.
@@ -880,6 +921,140 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
 
         return networks
 
+    def ex_list_network_offerings(self):
+        """
+        List the available network offerings
+
+        :rtype ``list`` of :class:`CloudStackNetworkOffering`
+        """
+        res = self._sync_request(command='listNetworkOfferings',
+                                 method='GET')
+        netoffers = res.get('networkoffering', [])
+
+        networkofferings = []
+
+        for netoffer in netoffers:
+            networkofferings.append(CloudStackNetworkOffering(
+                                    netoffer['name'],
+                                    netoffer['displaytext'],
+                                    netoffer['guestiptype'],
+                                    netoffer['id'],
+                                    netoffer['serviceofferingid'],
+                                    netoffer['forvpc'],
+                                    self))
+
+        return networkofferings
+
+    def ex_create_network(self, display_text, name, network_offering,
+                          location, gateway=None, netmask=None,
+                          network_domain=None, vpc_id=None, project_id=None):
+        """
+
+        Creates a Network, only available in advanced zones.
+
+        :param  display_text: the display text of the network
+        :type   display_text: ``str``
+
+        :param  name: the name of the network
+        :type   name: ``str``
+
+        :param  network_offering: the network offering id
+        :type   network_offering: :class:'CloudStackNetworkOffering`
+
+        :param location: Zone
+        :type  location: :class:`NodeLocation`
+
+        :param  gateway: Optional, the Gateway of this network
+        :type   gateway: ``str``
+
+        :param  netmask: Optional, the netmask of this network
+        :type   netmask: ``str``
+
+        :param  network_domain: Optional, the DNS domain of the network
+        :type   network_domain: ``str``
+
+        :param  vpc_id: Optional, the VPC id the network belongs to
+        :type   vpc_id: ``str``
+
+        :param  project_id: Optional, the project id the networks belongs to
+        :type   project_id: ``str``
+
+        :rtype: :class:`CloudStackNetwork`
+
+        """
+
+        extra_map = RESOURCE_EXTRA_ATTRIBUTES_MAP['network']
+
+        args = {
+            'displaytext': display_text,
+            'name': name,
+            'networkofferingid': network_offering.id,
+            'zoneid': location.id,
+        }
+
+        if gateway is not None:
+            args['gateway'] = gateway
+
+        if netmask is not None:
+            args['netmask'] = netmask
+
+        if network_domain is not None:
+            args['networkdomain'] = network_domain
+
+        if vpc_id is not None:
+            args['vpcid'] = vpc_id
+
+        if project_id is not None:
+            args['projectid'] = project_id
+
+        """ Cloudstack allows for duplicate network names,
+        this should be handled in the code leveraging libcloud
+        As there could be use cases for duplicate names.
+        e.g. management from ROOT level"""
+
+        # for net in self.ex_list_networks():
+        #    if name == net.name:
+        #        raise LibcloudError('This network name already exists')
+
+        result = self._sync_request(command='createNetwork',
+                                    params=args,
+                                    method='GET')
+
+        result = result['network']
+        extra = self._get_extra_dict(result, extra_map)
+
+        network = CloudStackNetwork(display_text,
+                                    name,
+                                    network_offering.id,
+                                    result['id'],
+                                    location.id,
+                                    self,
+                                    extra=extra)
+
+        return network
+
+    def ex_delete_network(self, network, force=None):
+        """
+
+        Deletes a Network, only available in advanced zones.
+
+        :param  network: The network
+        :type   network: :class: 'CloudStackNetwork'
+
+        :param  force: Force deletion of the network?
+        :type   force: ``bool``
+
+        :rtype: ``bool``
+
+        """
+
+        args = {'id': network.id, 'forced': force}
+
+        self._async_request(command='deleteNetwork',
+                            params=args,
+                            method='GET')
+        return True
+
     def ex_list_projects(self):
         """
         List the available projects

http://git-wip-us.apache.org/repos/asf/libcloud/blob/33ca3b2e/libcloud/test/compute/fixtures/cloudstack/createNetwork_default.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/createNetwork_default.json 
b/libcloud/test/compute/fixtures/cloudstack/createNetwork_default.json
new file mode 100644
index 0000000..9b2d904
--- /dev/null
+++ b/libcloud/test/compute/fixtures/cloudstack/createNetwork_default.json
@@ -0,0 +1 @@
+{ "createnetworkresponse" :  { "network" : 
{"id":"a804d341-996e-4d9a-b2b0-226c648dc6e3","name":"test","displaytext":"test","broadcastdomaintype":"Lswitch","traffictype":"Guest","gateway":"10.1.1.1","netmask":"255.255.255.0","cidr":"10.1.1.0/24","zoneid":"2","zonename":"BETA-SBP-DC-1","networkofferingid":"c348cabe-0208-49e0-91ad-32b88c55fd8c","networkofferingname":"SourceNatNiciraNvpNetwork","networkofferingdisplaytext":"Offering
 for a Nicira Nvp isolated network with 
SourceNat","networkofferingconservemode":true,"networkofferingavailability":"Optional","issystem":false,"state":"Allocated","related":"a804d341-996e-4d9a-b2b0-226c648dc6e3","dns1":"8.8.8.8","dns2":"8.8.8.4","type":"Isolated","acltype":"Account","account":"rkuipers_admin","projectid":"d5f1209d-3a28-4dfb-8cc1-884e5d5e1d56","domainid":"4b6e626c-9d50-4480-bf77-daae632c7ffd","domain":"rkuipers","service":[{"name":"Firewall","capability":[{"name":"SupportedProtocols","value":"tcp,udp,icmp","canchooseservicecapability":false},
 {"name":"SupportedTrafficDirection","value":"ingress, 
egress","canchooseservicecapability":false},{"name":"MultipleIps","value":"true","canchooseservicecapability":false},{"name":"SupportedEgressProtocols","value":"tcp,udp,icmp,
 
all","canchooseservicecapability":false},{"name":"TrafficStatistics","value":"per
 public 
ip","canchooseservicecapability":false}]},{"name":"StaticNat"},{"name":"Lb","capability":[{"name":"LbSchemes","value":"Public","canchooseservicecapability":false},{"name":"SupportedStickinessMethods","value":"[{\"methodname\":\"LbCookie\",\"paramlist\":[{\"paramname\":\"cookie-name\",\"required\":false,\"isflag\":false,\"description\":\"
 
\"},{\"paramname\":\"mode\",\"required\":false,\"isflag\":false,\"description\":\"
 
\"},{\"paramname\":\"nocache\",\"required\":false,\"isflag\":true,\"description\":\"
 
\"},{\"paramname\":\"indirect\",\"required\":false,\"isflag\":true,\"description\":\"
 
\"},{\"paramname\":\"postonly\",\"required\":false,\"isflag\":true,\"description\":\"
  
\"},{\"paramname\":\"domain\",\"required\":false,\"isflag\":false,\"description\":\"
 \"}],\"description\":\"This is loadbalancer cookie based stickiness 
method.\"},{\"methodname\":\"AppCookie\",\"paramlist\":[{\"paramname\":\"cookie-name\",\"required\":false,\"isflag\":false,\"description\":\"
 
\"},{\"paramname\":\"length\",\"required\":false,\"isflag\":false,\"description\":\"
 
\"},{\"paramname\":\"holdtime\",\"required\":false,\"isflag\":false,\"description\":\"
 
\"},{\"paramname\":\"request-learn\",\"required\":false,\"isflag\":true,\"description\":\"
 
\"},{\"paramname\":\"prefix\",\"required\":false,\"isflag\":true,\"description\":\"
 
\"},{\"paramname\":\"mode\",\"required\":false,\"isflag\":false,\"description\":\"
 \"}],\"description\":\"This is App session based sticky method. Define session 
stickiness on an existing application cookie. It can be used only for a 
specific http 
traffic\"},{\"methodname\":\"SourceBased\",\"paramlist\":[{\"paramname\":\"tablesize\",\"required\":false,
 \"isflag\":false,\"description\":\" 
\"},{\"paramname\":\"expire\",\"required\":false,\"isflag\":false,\"description\":\"
 \"}],\"description\":\"This is source based Stickiness method, it can be used 
for any type of 
protocol.\"}]","canchooseservicecapability":false},{"name":"SupportedLBIsolation","value":"dedicated","canchooseservicecapability":false},{"name":"SupportedLbAlgorithms","value":"roundrobin,leastconn,source","canchooseservicecapability":false},{"name":"SupportedProtocols","value":"tcp,
 
udp","canchooseservicecapability":false}]},{"name":"SourceNat","capability":[{"name":"RedundantRouter","value":"true","canchooseservicecapability":false},{"name":"SupportedSourceNatTypes","value":"peraccount","canchooseservicecapability":false}]},{"name":"Dns","capability":[{"name":"AllowDnsSuffixModification","value":"true","canchooseservicecapability":false}]},{"name":"Connectivity"},{"name":"Vpn","capability":[{"name":"SupportedVpnTypes","value":"pptp,l2tp,ipsec","canchooseservicecapabil
 
ity":false},{"name":"VpnTypes","value":"removeaccessvpn","canchooseservicecapability":false}]},{"name":"Dhcp","capability":[{"name":"DhcpAccrossMultipleSubnets","value":"true","canchooseservicecapability":false}]},{"name":"UserData"},{"name":"PortForwarding"}],"networkdomain":"rkuipers.local","physicalnetworkid":"e48527a6-6882-4c5f-bce9-c02ecd5ef8c1","restartrequired":false,"specifyipranges":false,"vpcid":"22e8388c-21bf-4b84-8f20-e92a7f550898","canusefordeploy":true,"ispersistent":false,"tags":[],"displaynetwork":true}
 }  }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/33ca3b2e/libcloud/test/compute/fixtures/cloudstack/deleteNetwork_default.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/deleteNetwork_default.json 
b/libcloud/test/compute/fixtures/cloudstack/deleteNetwork_default.json
new file mode 100644
index 0000000..ad161b2
--- /dev/null
+++ b/libcloud/test/compute/fixtures/cloudstack/deleteNetwork_default.json
@@ -0,0 +1 @@
+{ "deletenetworkresponse" : {"jobid":"deleteNetwork"} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/33ca3b2e/libcloud/test/compute/fixtures/cloudstack/listNetworkOfferings_default.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/listNetworkOfferings_default.json 
b/libcloud/test/compute/fixtures/cloudstack/listNetworkOfferings_default.json
new file mode 100644
index 0000000..35d8bcc
--- /dev/null
+++ 
b/libcloud/test/compute/fixtures/cloudstack/listNetworkOfferings_default.json
@@ -0,0 +1 @@
+{ "listnetworkofferingsresponse" : { "count":2 ,"networkoffering" : [  
{"id":"c348cabe-0208-49e0-91ad-32b88c55fd8c","name":"SourceNatNiciraNvpNetwork","displaytext":"Offering
 for a Nicira Nvp isolated network with 
SourceNat","tags":"BETA-SBP-DC-1-pSTT","traffictype":"Guest","isdefault":true,"specifyvlan":false,"conservemode":true,"specifyipranges":false,"availability":"Optional","networkrate":-1,"state":"Enabled","guestiptype":"Isolated","serviceofferingid":"01f93707-3a35-44a6-84e9-ea767287a6b2","service":[{"name":"Firewall","provider":[{"name":"VirtualRouter"}]},{"name":"StaticNat","provider":[{"name":"VirtualRouter"}],"capability":[{"name":"ElasticIp","value":"false","canchooseservicecapability":false},{"name":"AssociatePublicIP","value":"false","canchooseservicecapability":false}]},{"name":"Lb","provider":[{"name":"VirtualRouter"}],"capability":[{"name":"SupportedLBIsolation","value":"dedicated","canchooseservicecapability":false},{"name":"ElasticLb","value":"false","canchooseser
 
vicecapability":false},{"name":"InlineMode","value":"false","canchooseservicecapability":false}]},{"name":"SourceNat","provider":[{"name":"VirtualRouter"}],"capability":[{"name":"SupportedSourceNatTypes","value":"peraccount","canchooseservicecapability":false},{"name":"RedundantRouter","value":"false","canchooseservicecapability":false}]},{"name":"Dns","provider":[{"name":"VirtualRouter"}]},{"name":"Connectivity","provider":[{"name":"NiciraNvp"}]},{"name":"Vpn","provider":[{"name":"VirtualRouter"}]},{"name":"Dhcp","provider":[{"name":"VirtualRouter"}]},{"name":"UserData","provider":[{"name":"VirtualRouter"}]},{"name":"PortForwarding","provider":[{"name":"VirtualRouter"}]}],"forvpc":false,"ispersistent":false,"egressdefaultpolicy":false},
 {"id":"7c09e208-2af5-43d6-9f0b-53868ef788ea","name":"OAT offering for OAT 
purposes","displaytext":"OAT offering for OAT 
purposes","tags":"BETA-SBP-DC-1-pSTT","traffictype":"Guest","isdefault":false,"specifyvlan":false,"conservemode":true,"specifyipr
 
anges":false,"availability":"Optional","networkrate":-1,"state":"Enabled","guestiptype":"Isolated","serviceofferingid":"01f93707-3a35-44a6-84e9-ea767287a6b2","service":[{"name":"Firewall","provider":[{"name":"VirtualRouter"}]},{"name":"StaticNat","provider":[{"name":"VirtualRouter"}],"capability":[{"name":"ElasticIp","value":"false","canchooseservicecapability":false},{"name":"AssociatePublicIP","value":"false","canchooseservicecapability":false}]},{"name":"Lb","provider":[{"name":"VirtualRouter"}],"capability":[{"name":"SupportedLBIsolation","value":"dedicated","canchooseservicecapability":false},{"name":"ElasticLb","value":"false","canchooseservicecapability":false},{"name":"InlineMode","value":"false","canchooseservicecapability":false}]},{"name":"SourceNat","provider":[{"name":"VirtualRouter"}],"capability":[{"name":"SupportedSourceNatTypes","value":"peraccount","canchooseservicecapability":false},{"name":"RedundantRouter","value":"false","canchooseservicecapability":false}]},{"
 
name":"Dns","provider":[{"name":"VirtualRouter"}]},{"name":"Connectivity","provider":[{"name":"NiciraNvp"}]},{"name":"Vpn","provider":[{"name":"VirtualRouter"}]},{"name":"Dhcp","provider":[{"name":"VirtualRouter"}]},{"name":"UserData","provider":[{"name":"VirtualRouter"}]},{"name":"PortForwarding","provider":[{"name":"VirtualRouter"}]}],"forvpc":false,"ispersistent":false,"egressdefaultpolicy":true,"maxconnections":4096}
 ] } }

http://git-wip-us.apache.org/repos/asf/libcloud/blob/33ca3b2e/libcloud/test/compute/fixtures/cloudstack/queryAsyncJobResult_deleteNetwork.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/queryAsyncJobResult_deleteNetwork.json
 
b/libcloud/test/compute/fixtures/cloudstack/queryAsyncJobResult_deleteNetwork.json
new file mode 100644
index 0000000..19494c3
--- /dev/null
+++ 
b/libcloud/test/compute/fixtures/cloudstack/queryAsyncJobResult_deleteNetwork.json
@@ -0,0 +1 @@
+{ "queryasyncjobresultresponse" : 
{"accountid":"02c9bf08-6f36-44b1-a57f-df0708f90de4","userid":"6ef2b921-4ecf-4651-8188-f9868db73e73","cmd":"org.apache.cloudstack.api.command.user.network.DeleteNetworkCmd","jobstatus":1,"jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object","jobresult":{"success":true},"created":"2014-06-11T10:09:00+0200","jobid":"65789636-d2c8-484c-9d13-47ad3de384ed"}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/33ca3b2e/libcloud/test/compute/test_cloudstack.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_cloudstack.py 
b/libcloud/test/compute/test_cloudstack.py
index b90c905..091d98b 100644
--- a/libcloud/test/compute/test_cloudstack.py
+++ b/libcloud/test/compute/test_cloudstack.py
@@ -196,6 +196,63 @@ class CloudStackCommonTestCase(TestCaseMixin):
                 fixture_networks[i]['networkofferingid'])
             self.assertEqual(network.zoneid, fixture_networks[i]['zoneid'])
 
+    def test_ex_list_network_offerings(self):
+        _, fixture = CloudStackMockHttp()._load_fixture(
+            'listNetworkOfferings_default.json')
+        fixture_networkoffers = \
+            fixture['listnetworkofferingsresponse']['networkoffering']
+
+        networkoffers = self.driver.ex_list_network_offerings()
+
+        for i, networkoffer in enumerate(networkoffers):
+            self.assertEqual(networkoffer.id, fixture_networkoffers[i]['id'])
+            self.assertEqual(networkoffer.name,
+                             fixture_networkoffers[i]['name'])
+            self.assertEqual(networkoffer.display_text,
+                             fixture_networkoffers[i]['displaytext'])
+            self.assertEqual(networkoffer.for_vpc,
+                             fixture_networkoffers[i]['forvpc'])
+            self.assertEqual(networkoffer.guest_ip_type,
+                             fixture_networkoffers[i]['guestiptype'])
+            self.assertEqual(networkoffer.service_offering_id,
+                             fixture_networkoffers[i]['serviceofferingid'])
+
+    def test_ex_create_network(self):
+        _, fixture = CloudStackMockHttp()._load_fixture(
+            'createNetwork_default.json')
+
+        fixture_network = fixture['createnetworkresponse']['network']
+
+        netoffer = self.driver.ex_list_network_offerings()[0]
+        location = self.driver.list_locations()[0]
+        network = self.driver.ex_create_network(display_text='test',
+                                                name='test',
+                                                network_offering=netoffer,
+                                                location=location,
+                                                gateway='10.1.1.1',
+                                                netmask='255.255.255.0',
+                                                network_domain='cloud.local',
+                                                vpc_id="2",
+                                                project_id="2")
+
+        self.assertEqual(network.name, fixture_network['name'])
+        self.assertEqual(network.displaytext, fixture_network['displaytext'])
+        self.assertEqual(network.id, fixture_network['id'])
+        self.assertEqual(network.extra['gateway'], fixture_network['gateway'])
+        self.assertEqual(network.extra['netmask'], fixture_network['netmask'])
+        self.assertEqual(network.networkofferingid,
+                         fixture_network['networkofferingid'])
+        self.assertEqual(network.extra['vpc_id'], fixture_network['vpcid'])
+        self.assertEqual(network.extra['project_id'],
+                         fixture_network['projectid'])
+
+    def test_ex_delete_network(self):
+
+        network = self.driver.ex_list_networks()[0]
+
+        result = self.driver.ex_delete_network(network=network)
+        self.assertTrue(result)
+
     def test_ex_list_projects(self):
         _, fixture = CloudStackMockHttp()._load_fixture(
             'listProjects_default.json')

Reply via email to