Repository: libcloud
Updated Branches:
  refs/heads/trunk 43d8cd680 -> 46b94aa47


Cloudstack: Implemented VPC network acls and tests

Signed-off-by: Sebastien Goasguen <[email protected]>

This closes #371


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

Branch: refs/heads/trunk
Commit: 46b94aa47d2ac6ca6d7b510a2ea72516d2755850
Parents: 43d8cd6
Author: Jeroen de Korte <[email protected]>
Authored: Sun Sep 28 18:32:32 2014 +0200
Committer: Sebastien Goasguen <[email protected]>
Committed: Wed Nov 5 17:11:46 2014 +0100

----------------------------------------------------------------------
 CHANGES.rst                                     |   4 +
 libcloud/compute/drivers/cloudstack.py          | 435 +++++++++++++++++--
 .../createNetworkACLList_default.json           |   1 +
 .../cloudstack/createNetworkACL_default.json    |   1 +
 .../cloudstack/listNetworkACLLists_default.json |   1 +
 .../cloudstack/listNetworkACLs_default.json     |   1 +
 .../cloudstack/listRouters_default.json         |   1 +
 .../cloudstack/queryAsyncJobResult_111112.json  |   1 +
 libcloud/test/compute/test_cloudstack.py        |  63 ++-
 9 files changed, 472 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 9026450..71dac63 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -175,6 +175,10 @@ Compute
   (GITHUB-369)
   [Roeland Kuipers]
 
+- Implements VPC network ACLs for CloudStack drive
+  (GITHUB-371)
+  [Jeroen de Korte]
+
 Storage
 ~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/libcloud/compute/drivers/cloudstack.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/cloudstack.py 
b/libcloud/compute/drivers/cloudstack.py
index 454f1e7..43617bd 100644
--- a/libcloud/compute/drivers/cloudstack.py
+++ b/libcloud/compute/drivers/cloudstack.py
@@ -397,13 +397,18 @@ class CloudStackAddress(object):
     :param      associated_network_id: The ID of the network where this address
                                         has been associated with
     :type       associated_network_id: ``str``
+
+    :param      vpc_id: VPC the ip belongs to
+    :type       vpc_id: ``str``
     """
 
-    def __init__(self, id, address, driver, associated_network_id=None):
+    def __init__(self, id, address, driver, associated_network_id=None,
+                 vpc_id=None):
         self.id = id
         self.address = address
         self.driver = driver
         self.associated_network_id = associated_network_id
+        self.vpc_id = vpc_id
 
     def release(self):
         self.driver.ex_release_public_ip(address=self)
@@ -552,7 +557,8 @@ class CloudStackPortForwardingRule(object):
     """
 
     def __init__(self, node, rule_id, address, protocol, public_port,
-                 private_port, public_end_port=None, private_end_port=None):
+                 private_port, public_end_port=None, private_end_port=None,
+                 network_id=None):
         """
         A Port forwarding rule for Source NAT.
 
@@ -584,6 +590,12 @@ class CloudStackPortForwardingRule(object):
         :param      private_end_port: End of internal port range
         :type       private_end_port: ``int``
 
+        :param      network_id: The network of the vm the Port Forwarding rule
+                                will be created for. Required when public Ip
+                                address is not associated with any Guest
+                                network yet (VPC case)
+        :type       network_id: ``str``
+
         :rtype: :class:`CloudStackPortForwardingRule`
         """
         self.node = node
@@ -602,6 +614,102 @@ class CloudStackPortForwardingRule(object):
         return self.__class__ is other.__class__ and self.id == other.id
 
 
+class CloudStackNetworkACLList(object):
+    """
+    a Network ACL for the given VPC
+    """
+
+    def __init__(self, acl_id, name, vpc_id, driver, description=None):
+        """
+        a Network ACL for the given VPC
+
+        @note: This is a non-standard extension API, and only works for
+               Cloudstack.
+
+        :param      acl_id: ACL ID
+        :type       acl_id: ``int``
+
+        :param      name: Name of the network ACL List
+        :type       name: ``str``
+
+        :param      vpc_id: Id of the VPC associated with this network ACL List
+        :type       vpc_id: ``string``
+
+        :param      description: Description of the network ACL List
+        :type       description: ``str``
+
+        :rtype: :class:`CloudStackNetworkACLList`
+        """
+
+        self.id = acl_id
+        self.name = name
+        self.vpc_id = vpc_id
+        self.driver = driver
+        self.description = description
+
+    def __repr__(self):
+        return (('<CloudStackNetworkACLList: id=%s, name=%s, vpc_id=%s, '
+                 'driver=%s, description=%s>')
+                % (self.id, self.name, self.vpc_id,
+                   self.driver.name, self.description))
+
+
+class CloudStackNetworkACL(object):
+    """
+    a ACL rule in the given network (the network has to belong to VPC)
+    """
+
+    def __init__(self, id, protocol, acl_id, action, cidr_list,
+                 start_port, end_port, traffic_type=None):
+        """
+        a ACL rule in the given network (the network has to belong to
+        VPC)
+
+        @note: This is a non-standard extension API, and only works for
+               Cloudstack.
+
+        :param      id: the ID of the ACL Item
+        :type       id ``int``
+
+        :param      protocol: the protocol for the ACL rule. Valid values are
+                    TCP/UDP/ICMP/ALL or valid protocol number
+        :type       protocol: ``string``
+
+        :param      acl_id: Name of the network ACL List
+        :type       acl_id: ``str``
+
+        :param      action: scl entry action, allow or deny
+        :type       action: ``string``
+
+        :param      cidr_list: the cidr list to allow traffic from/to
+        :type       cidr_list: ``str``
+
+        :param      start_port: the starting port of ACL
+        :type       start_port: ``str``
+
+        :param      end_port: the ending port of ACL
+        :type       end_port: ``str``
+
+        :param      traffic_type: the traffic type for the ACL,can be Ingress
+                    or Egress, defaulted to Ingress if not specified
+        :type       traffic_type: ``str``
+
+        :rtype: :class:`CloudStackNetworkACL`
+        """
+
+        self.id = id
+        self.protocol = protocol
+        self.acl_id = acl_id
+        self.action = action
+        self.cidr_list = cidr_list
+        self.start_port = start_port
+        self.end_port = end_port
+        self.traffic_type = traffic_type
+
+    def __eq__(self, other):
+        return self.__class__ is other.__class__ and self.id == other.id
+
+
 class CloudStackDiskOffering(object):
     """
     A disk offering within CloudStack.
@@ -633,10 +741,11 @@ class CloudStackNetwork(object):
         self.extra = extra or {}
 
     def __repr__(self):
-        return (('<CloudStackNetwork: id=%s, displaytext=%s, name=%s, '
-                 'networkofferingid=%s, zoneid=%s, driver%s>')
-                % (self.id, self.displaytext, self.name,
-                   self.networkofferingid, self.zoneid, self.driver.name))
+        return (('<CloudStackNetwork: displaytext=%s, name=%s, '
+                 'networkofferingid=%s, '
+                 'id=%s, zoneid=%s, driver=%s>')
+                % (self.displaytext, self.name, self.networkofferingid,
+                   self.id, self.zoneid, self.driver.name))
 
 
 class CloudStackNetworkOffering(object):
@@ -658,7 +767,7 @@ class CloudStackNetworkOffering(object):
     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>')
+                 '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))
@@ -698,8 +807,8 @@ class CloudStackVPC(object):
     Class representing a CloudStack VPC.
     """
 
-    def __init__(self, display_text, name, vpc_offering_id, id, zone_id, cidr,
-                 driver, extra=None):
+    def __init__(self, name, vpc_offering_id, id, cidr, driver,
+                 zone_id=None, display_text=None, extra=None):
         self.display_text = display_text
         self.name = name
         self.vpc_offering_id = vpc_offering_id
@@ -710,11 +819,11 @@ class CloudStackVPC(object):
         self.extra = extra or {}
 
     def __repr__(self):
-        return (('<CloudStackVPC: id=%s, displaytext=%s, name=%s, '
-                 'vpc_offering_id=%s, zoneid=%s, cidr=%s, driver%s>')
-                % (self.id, self.displaytext, self.name,
-                   self.vpc_offering_id, self.zoneid, self.cidr,
-                   self.driver.name))
+        return (('<CloudStackVPC: name=%s, vpc_offering_id=%s, id=%s, '
+                 'cidr=%s, driver=%s, zone_id=%s, display_text=%s>')
+                % (self.name, self.vpc_offering_id, self.id,
+                   self.cidr, self.driver.name, self.zone_id,
+                   self.display_text))
 
 
 class CloudStackVPCOffering(object):
@@ -731,13 +840,33 @@ class CloudStackVPCOffering(object):
         self.extra = extra or {}
 
     def __repr__(self):
-        return (('<CloudStackVPCOffering: id=%s, name=%s, '
-                 'display_text=%s, '
-                 'driver%s>')
-                % (self.id, self.name, self.display_text,
+        return (('<CloudStackVPCOffering: name=%s, display_text=%s, '
+                 'id=%s, '
+                 'driver=%s>')
+                % (self.name, self.display_text, self.id,
                    self.driver.name))
 
 
+class CloudStackRouter(object):
+    """
+    Class representing a CloudStack Router.
+    """
+
+    def __init__(self, id, name, state, public_ip, vpc_id, driver):
+        self.id = id
+        self.name = name
+        self.state = state
+        self.public_ip = public_ip
+        self.vpc_id = vpc_id
+        self.driver = driver
+
+    def __repr__(self):
+        return (('<CloudStackRouter: id=%s, name=%s, state=%s, '
+                 'public_ip=%s, vpc_id=%s, driver=%s>')
+                % (self.id, self.name, self.state,
+                   self.public_ip, self.vpc_id, self.driver.name))
+
+
 class CloudStackProject(object):
     """
     Class representing a CloudStack Project.
@@ -751,7 +880,7 @@ class CloudStackProject(object):
         self.extra = extra or {}
 
     def __repr__(self):
-        return (('<CloudStackProject: id=%s, display_text=%s, name=%s, '
+        return (('<CloudStackProject: id=%s, name=%s, display_text=%s,'
                  'driver=%s>')
                 % (self.id, self.display_text, self.name,
                    self.driver.name))
@@ -1361,18 +1490,48 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
         for vpc in vpcs:
 
             networks.append(CloudStackVPC(
-                            vpc['displaytext'],
                             vpc['name'],
                             vpc['vpcofferingid'],
                             vpc['id'],
-                            vpc['zoneid'],
                             vpc['cidr'],
-                            self))
+                            self,
+                            vpc['zoneid'],
+                            vpc['displaytext']))
 
         return networks
 
+    def ex_list_routers(self, vpc_id=None):
+        """
+        List routers
+
+        :rtype ``list`` of :class:`CloudStackRouter`
+        """
+
+        args = {}
+
+        if vpc_id is not None:
+            args['vpcid'] = vpc_id
+
+        res = self._sync_request(command='listRouters',
+                                 params=args,
+                                 method='GET')
+        rts = res.get('router', [])
+
+        routers = []
+        for router in rts:
+
+            routers.append(CloudStackRouter(
+                router['id'],
+                router['name'],
+                router['state'],
+                router['publicip'],
+                router['vpcid'],
+                self))
+
+        return routers
+
     def ex_create_vpc(self, cidr, display_text, name, vpc_offering,
-                      zoneid):
+                      zone_id, network_domain=None):
         """
 
         Creates a VPC, only available in advanced zones.
@@ -1391,8 +1550,11 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
         :param  vpc_offering: the ID of the VPC offering
         :type   vpc_offering: :class:'CloudStackVPCOffering`
 
-        :param  zoneid: the ID of the availability zone
-        :type   zoneid: ``str``
+        :param  zone_id: the ID of the availability zone
+        :type   zone_id: ``str``
+
+        :param  network_domain: Optional, the DNS domain of the network
+        :type   network_domain: ``str``
 
         :rtype: :class:`CloudStackVPC`
 
@@ -1405,22 +1567,25 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
             'displaytext': display_text,
             'name': name,
             'vpcofferingid': vpc_offering.id,
-            'zoneid': zoneid,
+            'zoneid': zone_id,
         }
 
+        if network_domain is not None:
+            args['networkdomain'] = network_domain
+
         result = self._sync_request(command='createVPC',
                                     params=args,
                                     method='GET')
 
         extra = self._get_extra_dict(result, extra_map)
 
-        vpc = CloudStackVPC(display_text,
-                            name,
+        vpc = CloudStackVPC(name,
                             vpc_offering.id,
                             result['id'],
-                            zoneid,
                             cidr,
                             self,
+                            zone_id,
+                            display_text,
                             extra=extra)
 
         return vpc
@@ -1747,20 +1912,38 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
 
         return ips
 
-    def ex_allocate_public_ip(self, location=None):
+    def ex_allocate_public_ip(self, vpc_id=None, network_id=None,
+                              location=None):
         """
         Allocate a public IP.
 
+        :param vpc_id: VPC the ip belongs to
+        :type vpc_id: ``str``
+
+        :param network_id: Network where this IP is connected to.
+        :type network_id: ''str''
+
         :param location: Zone
         :type  location: :class:`NodeLocation`
 
         :rtype: :class:`CloudStackAddress`
         """
-        if location is None:
-            location = self.list_locations()[0]
+
+        args = {}
+
+        if location is not None:
+            args['zoneid'] = location.id
+        else:
+            args['zoneid'] = self.list_locations()[0].id
+
+        if vpc_id is not None:
+            args['vpcid'] = vpc_id
+
+        if network_id is not None:
+            args['networkid'] = network_id
 
         addr = self._async_request(command='associateIpAddress',
-                                   params={'zoneid': location.id},
+                                   params=args,
                                    method='GET')
         addr = addr['ipaddress']
         addr = CloudStackAddress(addr['id'], addr['ipaddress'], self)
@@ -2002,7 +2185,8 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
                                        protocol,
                                        public_end_port=None,
                                        private_end_port=None,
-                                       openfirewall=True):
+                                       openfirewall=True,
+                                       network_id=None):
         """
         Creates a Port Forwarding Rule, used for Source NAT
 
@@ -2021,6 +2205,12 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
         :param  node: The virtual machine
         :type   node: :class:`CloudStackNode`
 
+        :param  network_id: The network of the vm the Port Forwarding rule
+                            will be created for. Required when public Ip
+                            address is not associated with any Guest
+                            network yet (VPC case)
+        :type   network_id: ``string``
+
         :rtype: :class:`CloudStackPortForwardingRule`
         """
         args = {
@@ -2035,6 +2225,8 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
             args['publicendport'] = int(public_end_port)
         if private_end_port:
             args['privateendport'] = int(private_end_port)
+        if network_id:
+            args['networkid'] = network_id
 
         result = self._async_request(command='createPortForwardingRule',
                                      params=args,
@@ -2047,7 +2239,8 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
                                             public_port,
                                             private_port,
                                             public_end_port,
-                                            private_end_port)
+                                            private_end_port,
+                                            network_id)
         node.extra['port_forwarding_rules'].append(rule)
         node.public_ips.append(address.address)
         return rule
@@ -2135,6 +2328,178 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, 
NodeDriver):
                             method='GET')
         return True
 
+    def ex_create_network_acllist(self, name, vpc_id, description=None):
+        """
+        Create a ACL List for a network within a VPC.
+
+        :param name: Name of the network ACL List
+        :type  name: ``string``
+
+        :param vpc_id: Id of the VPC associated with this network ACL List
+        :type  vpc_id: ``string``
+
+        :param description: Description of the network ACL List
+        :type  description: ``string``
+
+        :rtype: :class:`CloudStackNetworkACLList`
+        """
+
+        args = {
+            'name': name,
+            'vpcid': vpc_id
+        }
+        if description:
+            args['description'] = description
+
+        result = self._sync_request(command='createNetworkACLList',
+                                    params=args,
+                                    method='GET')
+
+        acl_list = CloudStackNetworkACLList(result['id'],
+                                            name,
+                                            vpc_id,
+                                            self,
+                                            description)
+        return acl_list
+
+    def ex_create_network_acl(self, protocol, acl_id, cidr_list,
+                              start_port, end_port, action=None,
+                              traffic_type=None):
+        """
+        Creates a ACL rule in the given network (the network has to belong to
+        VPC)
+
+        :param      protocol: the protocol for the ACL rule. Valid values are
+                    TCP/UDP/ICMP/ALL or valid protocol number
+        :type       protocol: ``string``
+
+        :param      acl_id: Name of the network ACL List
+        :type       acl_id: ``str``
+
+        :param      cidr_list: the cidr list to allow traffic from/to
+        :type       cidr_list: ``str``
+
+        :param      start_port: the starting port of ACL
+        :type       start_port: ``str``
+
+        :param      end_port: the ending port of ACL
+        :type       end_port: ``str``
+
+        :param      action: scl entry action, allow or deny
+        :type       action: ``str``
+
+        :param      traffic_type: the traffic type for the ACL,can be Ingress
+                    or Egress, defaulted to Ingress if not specified
+        :type       traffic_type: ``str``
+
+        :rtype: :class:`CloudStackNetworkACL`
+        """
+
+        args = {
+            'protocol': protocol,
+            'aclid': acl_id,
+            'cidrlist': cidr_list,
+            'startport': start_port,
+            'endport': end_port
+        }
+
+        if action:
+            args['action'] = action
+        else:
+            action = "allow"
+
+        if traffic_type:
+            args['traffictype'] = traffic_type
+
+        result = self._async_request(command='createNetworkACL',
+                                     params=args,
+                                     method='GET')
+
+        acl = CloudStackNetworkACL(result['networkacl']['id'],
+                                   protocol,
+                                   acl_id,
+                                   action,
+                                   cidr_list,
+                                   start_port,
+                                   end_port,
+                                   traffic_type)
+
+        return acl
+
+    def ex_list_network_acllists(self):
+        """
+        Lists all network ACLs
+
+        :rtype: ``list`` of :class:`CloudStackNetworkACLList`
+        """
+        acllists = []
+
+        result = self._sync_request(command='listNetworkACLLists',
+                                    method='GET')
+
+        if not result:
+            return acllists
+
+        for acllist in result['networkacllist']:
+            acllists.append(CloudStackNetworkACLList(acllist['id'],
+                                                     acllist['name'],
+                                                     acllist.get('vpcid', []),
+                                                     self,
+                                                     acllist['description']))
+
+        return acllists
+
+    def ex_replace_network_acllist(self, acl_id, network_id):
+        """
+        Create a ACL List for a network within a VPC.Replaces ACL associated
+        with a Network or private gateway
+
+        :param acl_id: the ID of the network ACL
+        :type  acl_id: ``string``
+
+        :param network_id: the ID of the network
+        :type  network_id: ``string``
+
+        :rtype: :class:`CloudStackNetworkACLList`
+        """
+
+        args = {
+            'aclid': acl_id,
+            'networkid': network_id
+        }
+
+        self._async_request(command='replaceNetworkACLList',
+                            params=args,
+                            method='GET')
+
+        return True
+
+    def ex_list_network_acl(self):
+        """
+        Lists all network ACL items
+
+        :rtype: ``list`` of :class:`CloudStackNetworkACL`
+        """
+        acls = []
+
+        result = self._sync_request(command='listNetworkACLs',
+                                    method='GET')
+
+        if not result:
+            return acls
+
+        for acl in result['networkacl']:
+            acls.append(CloudStackNetworkACL(acl['id'],
+                                             acl['protocol'],
+                                             acl['aclid'],
+                                             acl['action'],
+                                             acl['cidrlist'],
+                                             acl.get('startport', []),
+                                             acl.get('endport', []),
+                                             acl['traffictype']))
+
+        return acls
+
     def ex_list_keypairs(self, **kwargs):
         """
         List Registered SSH Key Pairs

http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/libcloud/test/compute/fixtures/cloudstack/createNetworkACLList_default.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/createNetworkACLList_default.json 
b/libcloud/test/compute/fixtures/cloudstack/createNetworkACLList_default.json
new file mode 100644
index 0000000..e05e8f3
--- /dev/null
+++ 
b/libcloud/test/compute/fixtures/cloudstack/createNetworkACLList_default.json
@@ -0,0 +1 @@
+{ "createnetworkacllistresponse" : 
{"id":"5692ffdc-d98e-4c7e-a53e-817835e97694","jobid":"0e6707fa-15d9-4cd4-8e16-fd58232321e1"}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/libcloud/test/compute/fixtures/cloudstack/createNetworkACL_default.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/createNetworkACL_default.json 
b/libcloud/test/compute/fixtures/cloudstack/createNetworkACL_default.json
new file mode 100644
index 0000000..d7bd22d
--- /dev/null
+++ b/libcloud/test/compute/fixtures/cloudstack/createNetworkACL_default.json
@@ -0,0 +1 @@
+{ "createnetworkaclresponse" : 
{"id":"54bd8cc6-5db0-4f64-8495-a0dfaf3fb4d5","jobid":"111112"} }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/libcloud/test/compute/fixtures/cloudstack/listNetworkACLLists_default.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/listNetworkACLLists_default.json 
b/libcloud/test/compute/fixtures/cloudstack/listNetworkACLLists_default.json
new file mode 100644
index 0000000..98f8ad4
--- /dev/null
+++ b/libcloud/test/compute/fixtures/cloudstack/listNetworkACLLists_default.json
@@ -0,0 +1 @@
+{ "listnetworkacllistsresponse" : { "count":4 ,"networkacllist" : [  
{"id":"54bd8cc6-5db0-4f64-8495-a0dfaf3fb4d5","name":"test","description":"test","vpcid":"cf698ec3-edd0-466c-a8f6-f9096700b6ec"}
 ] } }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/libcloud/test/compute/fixtures/cloudstack/listNetworkACLs_default.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/listNetworkACLs_default.json 
b/libcloud/test/compute/fixtures/cloudstack/listNetworkACLs_default.json
new file mode 100644
index 0000000..f71c54c
--- /dev/null
+++ b/libcloud/test/compute/fixtures/cloudstack/listNetworkACLs_default.json
@@ -0,0 +1 @@
+{ "listnetworkaclsresponse" : { "count":1 ,"networkacl" : [  
{"id":"54bd8cc6-5db0-4f64-8495-a0dfaf3fb4d5","protocol":"tcp","startport":"80","endport":"80","traffictype":"Ingress","state":"Active","cidrlist":"0.0.0.0/0","tags":[],"aclid":"4b1a2ef9-b53a-4e1b-9a45-0408b3ce3494","number":1,"action":"Allow"}
 ] } }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/libcloud/test/compute/fixtures/cloudstack/listRouters_default.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/cloudstack/listRouters_default.json 
b/libcloud/test/compute/fixtures/cloudstack/listRouters_default.json
new file mode 100644
index 0000000..f8bf354
--- /dev/null
+++ b/libcloud/test/compute/fixtures/cloudstack/listRouters_default.json
@@ -0,0 +1 @@
+{ "listroutersresponse" : { "count":1 ,"router" : [  
{"id":"634c57f2-5ea2-487b-a5d3-5bb5550de691","zoneid":"2","zonename":"TEST-ZONE","dns1":"8.8.8.8","dns2":"8.8.8.4","networkdomain":"cloudify-mgmt.local","gateway":"178.237.34.1","name":"r-21786-VM","publicip":"178.237.34.110","publicmacaddress":"06:49:62:00:02:cf","publicnetmask":"255.255.255.0","publicnetworkid":"38204176-846f-4d24-bb3e-725e5756b62a","guestipaddress":"10.10.10.1","guestmacaddress":"02:00:57:2b:00:03","guestnetmask":"255.255.255.192","guestnetworkid":"3cfab464-d6b5-4944-bd77-24afae1190b2","templateid":"77f1ad92-4b83-4481-b7ca-5c6b1a9fa82f","created":"2014-09-30T11:29:46+0200","state":"Running","account":"test","domainid":"ee90435a-bba8-427f-90f9-02f9bf9e03aa","domain":"test","serviceofferingid":"01f93707-3a35-44a6-84e9-ea767287a6b2","serviceofferingname":"System
 Offering For Software 
Router","isredundantrouter":false,"redundantstate":"UNKNOWN","version":"4.3.0","vpcid":"3ec197ca-167f-40f0-b306-edf97a0490bf","role"
 
:"VIRTUAL_ROUTER","nic":[{"id":"b62719ae-c5dc-423d-928d-892aeee1798a","networkid":"38204176-846f-4d24-bb3e-725e5756b62a","netmask":"255.255.255.0","gateway":"178.237.34.1","ipaddress":"178.237.34.110","isolationuri":"vlan://50","broadcasturi":"vlan://50","traffictype":"Public","isdefault":true,"macaddress":"06:49:62:00:02:cf"},{"id":"cf9f148e-2e7b-4894-8071-50f35778e5f0","networkid":"3cfab464-d6b5-4944-bd77-24afae1190b2","netmask":"255.255.255.192","ipaddress":"10.10.10.1","isolationuri":"lswitch:3a682dc2-2c86-439a-97cf-e594957e9e72","broadcasturi":"lswitch:3a682dc2-2c86-439a-97cf-e594957e9e72","traffictype":"Guest","type":"Isolated","isdefault":false,"macaddress":"02:00:57:2b:00:03"}],"requiresupgrade":false}
 ] } }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/libcloud/test/compute/fixtures/cloudstack/queryAsyncJobResult_111112.json
----------------------------------------------------------------------
diff --git 
a/libcloud/test/compute/fixtures/cloudstack/queryAsyncJobResult_111112.json 
b/libcloud/test/compute/fixtures/cloudstack/queryAsyncJobResult_111112.json
new file mode 100644
index 0000000..ff981d8
--- /dev/null
+++ b/libcloud/test/compute/fixtures/cloudstack/queryAsyncJobResult_111112.json
@@ -0,0 +1 @@
+{ "queryasyncjobresultresponse" : 
{"accountid":"5d7d4c5e-7e0b-4ac2-8550-713180d8a342","userid":"5fb4b286-ac58-44a7-acae-d47dbbac78d1","cmd":"org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd","jobstatus":1,"jobprocstatus":0,"jobresultcode":0,"jobresulttype":"object","jobresult":{"networkacl":{"id":"54bd8cc6-5db0-4f64-8495-a0dfaf3fb4d5","protocol":"tcp","startport":"1","endport":"1","traffictype":"Egress","state":"Active","cidrlist":"0.0.0.0/0","tags":[],"aclid":"0420fe87-b781-4579-a083-4890fb718d7e","number":20,"action":"Allow"}},"created":"2014-10-09T11:05:50+0200","jobid":"111112"}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/libcloud/blob/46b94aa4/libcloud/test/compute/test_cloudstack.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_cloudstack.py 
b/libcloud/test/compute/test_cloudstack.py
index 2164323..d9fd434 100644
--- a/libcloud/test/compute/test_cloudstack.py
+++ b/libcloud/test/compute/test_cloudstack.py
@@ -388,6 +388,20 @@ class CloudStackCommonTestCase(TestCaseMixin):
                              fixture_vpcs[i]['vpcofferingid'])
             self.assertEqual(vpc.zone_id, fixture_vpcs[i]['zoneid'])
 
+    def test_ex_list_routers(self):
+        _, fixture = CloudStackMockHttp()._load_fixture(
+            'listRouters_default.json')
+        fixture_routers = fixture['listroutersresponse']['router']
+
+        routers = self.driver.ex_list_routers()
+
+        for i, router in enumerate(routers):
+            self.assertEqual(router.id, fixture_routers[i]['id'])
+            self.assertEqual(router.name, fixture_routers[i]['name'])
+            self.assertEqual(router.state, fixture_routers[i]['state'])
+            self.assertEqual(router.public_ip, fixture_routers[i]['publicip'])
+            self.assertEqual(router.vpc_id, fixture_routers[i]['vpcid'])
+
     def test_ex_create_vpc(self):
         _, fixture = CloudStackMockHttp()._load_fixture(
             'createVPC_default.json')
@@ -399,7 +413,7 @@ class CloudStackCommonTestCase(TestCaseMixin):
                                         display_text='cloud.local',
                                         name='cloud.local',
                                         vpc_offering=vpcoffer,
-                                        zoneid="2")
+                                        zone_id="2")
 
         self.assertEqual(vpc.id, fixture_vpc['id'])
 
@@ -410,6 +424,53 @@ class CloudStackCommonTestCase(TestCaseMixin):
         result = self.driver.ex_delete_vpc(vpc=vpc)
         self.assertTrue(result)
 
+    def test_ex_create_network_acllist(self):
+        _, fixture = CloudStackMockHttp()._load_fixture(
+            'createNetworkACLList_default.json')
+
+        fixture_network_acllist = fixture['createnetworkacllistresponse']
+
+        vpc = self.driver.ex_list_vpcs()[0]
+        network_acllist = self.driver.ex_create_network_acllist(
+            name='test_acllist',
+            vpc_id=vpc.id,
+            description='test description')
+
+        self.assertEqual(network_acllist.id, fixture_network_acllist['id'])
+
+    def test_ex_list_network_acllist(self):
+        _, fixture = CloudStackMockHttp()._load_fixture(
+            'listNetworkACLLists_default.json')
+        fixture_acllist = \
+            fixture['listnetworkacllistsresponse']['networkacllist']
+
+        acllist = self.driver.ex_list_network_acllists()
+
+        for i, acllist in enumerate(acllist):
+            self.assertEqual(acllist.id,
+                             fixture_acllist[i]['id'])
+            self.assertEqual(acllist.name,
+                             fixture_acllist[i]['name'])
+            self.assertEqual(acllist.description,
+                             fixture_acllist[i]['description'])
+
+    def test_ex_create_network_acl(self):
+        _, fixture = CloudStackMockHttp()._load_fixture(
+            'createNetworkACL_default.json')
+
+        fixture_network_acllist = fixture['createnetworkaclresponse']
+
+        acllist = self.driver.ex_list_network_acllists()[0]
+
+        network_acl = self.driver.ex_create_network_acl(
+            protocol='test_acllist',
+            acl_id=acllist.id,
+            cidr_list='',
+            start_port='80',
+            end_port='80')
+
+        self.assertEqual(network_acl.id, fixture_network_acllist['id'])
+
     def test_ex_list_projects(self):
         _, fixture = CloudStackMockHttp()._load_fixture(
             'listProjects_default.json')

Reply via email to