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 2013/11/20 15:41:32 UTC

[1/2] git commit: Fix CloudStack drivers _async_request and _sync_request calls

Updated Branches:
  refs/heads/trunk dd4df811c -> 16cc10e83


Fix CloudStack drivers _async_request and _sync_request calls

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/16cc10e8
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/16cc10e8
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/16cc10e8

Branch: refs/heads/trunk
Commit: 16cc10e837d8000acfeb8397c56b56753a81d1b0
Parents: b23d908
Author: Philipp Strube <ps...@cloudcontrol.de>
Authored: Wed Nov 20 14:52:26 2013 +0100
Committer: Tomaz Muraus <to...@apache.org>
Committed: Wed Nov 20 15:13:32 2013 +0100

----------------------------------------------------------------------
 libcloud/compute/drivers/cloudstack.py      | 167 ++++++++++++++++-------
 libcloud/compute/drivers/ktucloud.py        |  25 ++--
 libcloud/loadbalancer/drivers/cloudstack.py |  53 ++++---
 3 files changed, 160 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/16cc10e8/libcloud/compute/drivers/cloudstack.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/cloudstack.py b/libcloud/compute/drivers/cloudstack.py
index b5d14e4..f3cc884 100644
--- a/libcloud/compute/drivers/cloudstack.py
+++ b/libcloud/compute/drivers/cloudstack.py
@@ -263,7 +263,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         }
         if location is not None:
             args['zoneid'] = location.id
-        imgs = self._sync_request('listTemplates', **args)
+        imgs = self._sync_request(command='listTemplates',
+                                  params=args,
+                                  method='GET')
         images = []
         for img in imgs.get('template', []):
             images.append(NodeImage(
@@ -389,7 +391,8 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         """
         :rtype ``list`` of :class:`NodeSize`
         """
-        szs = self._sync_request('listServiceOfferings')
+        szs = self._sync_request(command='listServiceOfferings',
+                                 method='GET')
         sizes = []
         for sz in szs['serviceoffering']:
             sizes.append(NodeSize(sz['id'], sz['name'], sz['memory'], 0, 0,
@@ -420,8 +423,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         server_params = self._create_args_to_params(None, **kwargs)
 
-        node = self._async_request('deployVirtualMachine',
-                                   **server_params)['virtualmachine']
+        node = self._async_request(command='deployVirtualMachine',
+                                   params=server_params,
+                                   method='GET')['virtualmachine']
         public_ips = []
         private_ips = []
         for nic in node['nic']:
@@ -511,7 +515,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         :rtype: ``bool``
         """
-        self._async_request('destroyVirtualMachine', id=node.id)
+        self._async_request(command='destroyVirtualMachine',
+                            params={'id': node.id},
+                            method='GET')
         return True
 
     def reboot_node(self, node):
@@ -521,7 +527,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         :rtype: ``bool``
         """
-        self._async_request('rebootVirtualMachine', id=node.id)
+        self._async_request(command='rebootVirtualMachine',
+                            params={'id': node.id},
+                            method='GET')
         return True
 
     def ex_start(self, node):
@@ -539,7 +547,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         :rtype ``str``
         """
-        res = self._async_request('startVirtualMachine', id=node.id)
+        res = self._async_request(command='startVirtualMachine',
+                                  params={'id': node.id},
+                                  method='GET')
         return res['virtualmachine']['state']
 
     def ex_stop(self, node):
@@ -559,7 +569,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         :rtype ``str``
         """
-        res = self._async_request('stopVirtualMachine', id=node.id)
+        res = self._async_request(command='stopVirtualMachine',
+                                  params={'id': node.id},
+                                  method='GET')
         return res['virtualmachine']['state']
 
     def ex_list_disk_offerings(self):
@@ -571,7 +583,8 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         diskOfferings = []
 
-        diskOfferResponse = self._sync_request('listDiskOfferings')
+        diskOfferResponse = self._sync_request(command='listDiskOfferings',
+                                               method='GET')
         for diskOfferDict in diskOfferResponse.get('diskoffering', ()):
             diskOfferings.append(
                 CloudStackDiskOffering(
@@ -589,7 +602,8 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         :rtype ``list`` of :class:`CloudStackNetwork`
         """
 
-        nets = self._sync_request('listNetworks')['network']
+        nets = self._sync_request(command='listNetworks',
+                                  method='GET')['network']
 
         networks = []
         for net in nets:
@@ -615,18 +629,19 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
             raise LibcloudError(
                 'Disk offering with size=%s not found' % size)
 
-        extraParams = dict()
-        if diskOffering.customizable:
-            extraParams['size'] = size
-
         if location is None:
             location = self.list_locations()[0]
 
-        requestResult = self._async_request('createVolume',
-                                            name=name,
-                                            diskOfferingId=diskOffering.id,
-                                            zoneId=location.id,
-                                            **extraParams)
+        params = {'name': name,
+                  'diskOfferingId': diskOffering.id,
+                  'zoneId': location.id}
+
+        if diskOffering.customizable:
+            params['size'] = size
+
+        requestResult = self._async_request(command='createVolume',
+                                            params=params,
+                                            method='GET')
 
         volumeResponse = requestResult['volume']
 
@@ -640,7 +655,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         """
         :rtype: ``bool``
         """
-        self._sync_request('deleteVolume', id=volume.id)
+        self._sync_request(command='deleteVolume',
+                           params={'id': volume.id},
+                           method='GET')
         return True
 
     def attach_volume(self, node, volume, device=None):
@@ -651,15 +668,19 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         :rtype: ``bool``
         """
         # TODO Add handling for device name
-        self._async_request('attachVolume', id=volume.id,
-                            virtualMachineId=node.id)
+        self._async_request(command='attachVolume',
+                            params={'id': volume.id,
+                                    'virtualMachineId': node.id},
+                            method='GET')
         return True
 
     def detach_volume(self, volume):
         """
         :rtype: ``bool``
         """
-        self._async_request('detachVolume', id=volume.id)
+        self._async_request(command='detachVolume',
+                            params={'id': volume.id},
+                            method='GET')
         return True
 
     def list_volumes(self, node=None):
@@ -672,10 +693,12 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         :rtype: ``list`` of :class:`StorageVolume`
         """
         if node:
-            volumes = self._sync_request('listVolumes',
-                                         virtualmachineid=node.id)
+            volumes = self._sync_request(command='listVolumes',
+                                         params={'virtualmachineid': node.id},
+                                         method='GET')
         else:
-            volumes = self._sync_request('listVolumes')
+            volumes = self._sync_request(command='listVolumes',
+                                         method='GET')
 
         list_volumes = []
         for vol in volumes['volume']:
@@ -693,7 +716,8 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         """
         ips = []
 
-        res = self._sync_request('listPublicIpAddresses')
+        res = self._sync_request(command='listPublicIpAddresses',
+                                 method='GET')
 
         # Workaround for basic zones
         if not res:
@@ -715,7 +739,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         if location is None:
             location = self.list_locations()[0]
 
-        addr = self._async_request('associateIpAddress', zoneid=location.id)
+        addr = self._async_request(command='associateIpAddress',
+                                   params={'zoneid': location.id},
+                                   method='GET')
         addr = addr['ipaddress']
         addr = CloudStackAddress(addr['id'], addr['ipaddress'], self)
         return addr
@@ -729,7 +755,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         :rtype: ``bool``
         """
-        res = self._async_request('disassociateIpAddress', id=address.id)
+        res = self._async_request(command='disassociateIpAddress',
+                                  params={'id': address.id},
+                                  method='GET')
         return res['success']
 
     def ex_list_port_forwarding_rules(self):
@@ -739,7 +767,8 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         :rtype: ``list`` of :class:`CloudStackPortForwardingRule`
         """
         rules = []
-        result = self._sync_request('listPortForwardingRules')
+        result = self._sync_request(command='listPortForwardingRules',
+                                    method='GET')
         if result != {}:
             public_ips = self.ex_list_public_ips()
             nodes = self.list_nodes()
@@ -798,7 +827,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         if private_end_port:
             args['privateendport'] = int(private_end_port)
 
-        result = self._async_request('createPortForwardingRule', **args)
+        result = self._async_request(command='createPortForwardingRule',
+                                     params=args,
+                                     method='GET')
         rule = CloudStackPortForwardingRule(node,
                                             result['portforwardingrule']
                                             ['id'],
@@ -827,7 +858,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         node.extra['port_forwarding_rules'].remove(rule)
         node.public_ips.remove(rule.address.address)
-        res = self._async_request('deletePortForwardingRule', id=rule.id)
+        res = self._async_request(command='deletePortForwardingRule',
+                                  params={'id': rule.id},
+                                  method='GET')
         return res['success']
 
     def ex_add_ip_forwarding_rule(self, node, address, protocol,
@@ -865,7 +898,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         if end_port is not None:
             args['endport'] = int(end_port)
 
-        result = self._async_request('createIpForwardingRule', **args)
+        result = self._async_request(command='createIpForwardingRule',
+                                     params=args,
+                                     method='GET')
         result = result['ipforwardingrule']
         rule = CloudStackIPForwardingRule(node, result['id'], address,
                                           protocol, start_port, end_port)
@@ -886,7 +921,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         """
 
         node.extra['ip_forwarding_rules'].remove(rule)
-        self._async_request('deleteIpForwardingRule', id=rule.id)
+        self._async_request(command='deleteIpForwardingRule',
+                            params={'id': rule.id},
+                            method='GET')
         return True
 
     def ex_list_keypairs(self, **kwargs):
@@ -938,7 +975,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         """
 
         extra_args = kwargs.copy()
-        res = self._sync_request('listSSHKeyPairs', **extra_args)
+        res = self._sync_request(command='listSSHKeyPairs',
+                                 params=extra_args,
+                                 method='GET')
         keypairs = res.get('sshkeypair', [])
         return keypairs
 
@@ -971,7 +1010,12 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
                 raise LibcloudError('SSH KeyPair with name=%s already exists'
                                     % (name))
 
-        res = self._sync_request('createSSHKeyPair', name=name, **extra_args)
+        params = {'name': name}
+        params.update(extra_args)
+
+        res = self._sync_request(command='createSSHKeyPair',
+                                 params=params,
+                                 method='GET')
         return res['keypair']
 
     def ex_delete_keypair(self, keypair, **kwargs):
@@ -996,9 +1040,12 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         """
 
         extra_args = kwargs.copy()
+        params = {'name': keypair}
+        params.update(extra_args)
 
-        res = self._sync_request('deleteSSHKeyPair', name=keypair,
-                                 **extra_args)
+        res = self._sync_request(command='deleteSSHKeyPair',
+                                 params=params,
+                                 method='GET')
         return res['success']
 
     def ex_import_keypair_from_string(self, name, key_material):
@@ -1013,8 +1060,10 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         :rtype: ``dict``
         """
-        res = self._sync_request('registerSSHKeyPair', name=name,
-                                 publickey=key_material)
+        res = self._sync_request(command='registerSSHKeyPair',
+                                 params={'name': name,
+                                         'publickey': key_material},
+                                 method='GET')
         return {
             'keyName': res['keypair']['name'],
             'keyFingerprint': res['keypair']['fingerprint']
@@ -1085,8 +1134,10 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
 
         :rtype ``list``
         """
-        extra_args = kwargs
-        res = self._sync_request('listSecurityGroups', **extra_args)
+        extra_args = kwargs.copy()
+        res = self._sync_request(command='listSecurityGroups',
+                                 params=extra_args,
+                                 method='GET')
 
         security_groups = res.get('securitygroup', [])
         return security_groups
@@ -1122,8 +1173,12 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
             if name in sg['name']:
                 raise LibcloudError('This Security Group name already exists')
 
-        return self._sync_request('createSecurityGroup',
-                                  name=name, **extra_args)['securitygroup']
+        params = {'name': name}
+        params.update(extra_args)
+
+        return self._sync_request(command='createSecurityGroup',
+                                  params=params,
+                                  method='GET')['securitygroup']
 
     def ex_delete_security_group(self, name):
         """
@@ -1151,7 +1206,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         :rtype: ``bool``
         """
 
-        return self._sync_request('deleteSecurityGroup', name=name)['success']
+        return self._sync_request(command='deleteSecurityGroup',
+                                  params={'name': name},
+                                  method='GET')['success']
 
     def ex_authorize_security_group_ingress(self, securitygroupname,
                                             protocol, cidrlist, startport,
@@ -1218,8 +1275,9 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         if endport is None:
             args['endport'] = int(startport)
 
-        return self._async_request('authorizeSecurityGroupIngress',
-                                   **args)['securitygroup']
+        return self._async_request(command='authorizeSecurityGroupIngress',
+                                   params=args,
+                                   method='GET')['securitygroup']
 
     def ex_register_iso(self, name, url, location=None, **kwargs):
         """
@@ -1239,19 +1297,22 @@ class CloudStackNodeDriver(CloudStackDriverMixIn, NodeDriver):
         if location is None:
             location = self.list_locations()[0]
 
-        extra_args = {}
-        extra_args['bootable'] = kwargs.pop('bootable', False)
-        if extra_args['bootable']:
+        params = {'name': name,
+                  'displaytext': name,
+                  'url': url,
+                  'zoneid': location.id}
+        params['bootable'] = kwargs.pop('bootable', False)
+        if params['bootable']:
             os_type_id = kwargs.pop('ostypeid', None)
 
             if not os_type_id:
                 raise LibcloudError('If bootable=True, ostypeid is required!')
 
-            extra_args['ostypeid'] = os_type_id
+            params['ostypeid'] = os_type_id
 
-        return self._sync_request('registerIso',
+        return self._sync_request(command='registerIso',
                                   name=name,
                                   displaytext=name,
                                   url=url,
                                   zoneid=location.id,
-                                  **extra_args)
+                                  params=params)

http://git-wip-us.apache.org/repos/asf/libcloud/blob/16cc10e8/libcloud/compute/drivers/ktucloud.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/ktucloud.py b/libcloud/compute/drivers/ktucloud.py
index c635ed7..1bc8544 100644
--- a/libcloud/compute/drivers/ktucloud.py
+++ b/libcloud/compute/drivers/ktucloud.py
@@ -33,7 +33,8 @@ class KTUCloudNodeDriver(CloudStackNodeDriver):
         if location is not None:
             args['zoneid'] = location.id
 
-        imgs = self._sync_request('listAvailableProductTypes')
+        imgs = self._sync_request(command='listAvailableProductTypes',
+                                  method='GET')
         images = []
 
         for img in imgs['producttypes']:
@@ -66,24 +67,24 @@ class KTUCloudNodeDriver(CloudStackNodeDriver):
         return sizes
 
     def create_node(self, name, size, image, location=None, **kwargs):
-        extra_args = {}
+        params = {'displayname': name,
+                  'serviceofferingid': image.id,
+                  'templateid': str(image.extra['templateid']),
+                  'zoneid': str(image.extra['zoneid'])}
+
         usageplantype = kwargs.pop('usageplantype', None)
         if usageplantype is None:
-            extra_args['usageplantype'] = 'hourly'
+            params['usageplantype'] = 'hourly'
         else:
-            extra_args['usageplantype'] = usageplantype
+            params['usageplantype'] = usageplantype
 
         if size.id != self.EMPTY_DISKOFFERINGID:
-            extra_args['diskofferingid'] = size.id
+            params['diskofferingid'] = size.id
 
         result = self._async_request(
-            'deployVirtualMachine',
-            displayname=name,
-            serviceofferingid=image.id,
-            templateid=str(image.extra['templateid']),
-            zoneid=str(image.extra['zoneid']),
-            **extra_args
-        )
+            command='deployVirtualMachine',
+            params=params,
+            method='GET')
 
         node = result['virtualmachine']
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/16cc10e8/libcloud/loadbalancer/drivers/cloudstack.py
----------------------------------------------------------------------
diff --git a/libcloud/loadbalancer/drivers/cloudstack.py b/libcloud/loadbalancer/drivers/cloudstack.py
index dcec636..ee88824 100644
--- a/libcloud/loadbalancer/drivers/cloudstack.py
+++ b/libcloud/loadbalancer/drivers/cloudstack.py
@@ -70,12 +70,15 @@ class CloudStackLBDriver(CloudStackDriverMixIn, Driver):
         return ['tcp']
 
     def list_balancers(self):
-        balancers = self._sync_request('listLoadBalancerRules')
+        balancers = self._sync_request(command='listLoadBalancerRules',
+                                       method='GET')
         balancers = balancers.get('loadbalancerrule', [])
         return [self._to_balancer(balancer) for balancer in balancers]
 
     def get_balancer(self, balancer_id):
-        balancer = self._sync_request('listLoadBalancerRules', id=balancer_id)
+        balancer = self._sync_request(command='listLoadBalancerRules',
+                                      params={'id': balancer_id},
+                                      method='GET')
         balancer = balancer.get('loadbalancerrule', [])
         if not balancer:
             raise Exception("no such load balancer: " + str(balancer_id))
@@ -94,24 +97,26 @@ class CloudStackLBDriver(CloudStackDriverMixIn, Driver):
         :type  private_port: ``int``
         """
         if location is None:
-            locations = self._sync_request('listZones')
+            locations = self._sync_request(command='listZones', method='GET')
             location = locations['zone'][0]['id']
         else:
             location = location.id
         if private_port is None:
             private_port = port
 
-        result = self._async_request('associateIpAddress', zoneid=location)
+        result = self._async_request(command='associateIpAddress',
+                                     params={'zoneid': location},
+                                     method='GET')
         public_ip = result['ipaddress']
 
         result = self._sync_request(
-            'createLoadBalancerRule',
-            algorithm=self._ALGORITHM_TO_VALUE_MAP[algorithm],
-            name=name,
-            privateport=private_port,
-            publicport=port,
-            publicipid=public_ip['id'],
-        )
+            command='createLoadBalancerRule',
+            params={'algorithm': self._ALGORITHM_TO_VALUE_MAP[algorithm],
+                    'name': name,
+                    'privateport': private_port,
+                    'publicport': port,
+                    'publicipid': public_ip['id']},
+            method='GET')
 
         balancer = self._to_balancer(result['loadbalancer'])
 
@@ -121,24 +126,32 @@ class CloudStackLBDriver(CloudStackDriverMixIn, Driver):
         return balancer
 
     def destroy_balancer(self, balancer):
-        self._async_request('deleteLoadBalancerRule', id=balancer.id)
-        self._async_request('disassociateIpAddress',
-                            id=balancer.ex_public_ip_id)
+        self._async_request(command='deleteLoadBalancerRule',
+                            params={'id': balancer.id},
+                            method='GET')
+        self._async_request(command='disassociateIpAddress',
+                            params={'id': balancer.ex_public_ip_id},
+                            method='GET')
 
     def balancer_attach_member(self, balancer, member):
         member.port = balancer.ex_private_port
-        self._async_request('assignToLoadBalancerRule', id=balancer.id,
-                            virtualmachineids=member.id)
+        self._async_request(command='assignToLoadBalancerRule',
+                            params={'id': balancer.id,
+                                    'virtualmachineids': member.id},
+                            method='GET')
         return True
 
     def balancer_detach_member(self, balancer, member):
-        self._async_request('removeFromLoadBalancerRule', id=balancer.id,
-                            virtualmachineids=member.id)
+        self._async_request(command='removeFromLoadBalancerRule',
+                            params={'id': balancer.id,
+                                    'virtualmachineids': member.id},
+                            method='GET')
         return True
 
     def balancer_list_members(self, balancer):
-        members = self._sync_request('listLoadBalancerRuleInstances',
-                                     id=balancer.id)
+        members = self._sync_request(command='listLoadBalancerRuleInstances',
+                                     params={'id': balancer.id},
+                                     method='GET')
         members = members['loadbalancerruleinstance']
         return [self._to_member(m, balancer.ex_private_port, balancer)
                 for m in members]


[2/2] git commit: Modify CloudStack Connection class so it looks more like other connection classes and user can more easily specify which attributes to send as part of the query string and as part of the request body.

Posted by to...@apache.org.
Modify CloudStack Connection class so it looks more like other connection classes and user can more easily specify which attributes to send as part of the query string and as part of the request body.

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/b23d9085
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/b23d9085
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/b23d9085

Branch: refs/heads/trunk
Commit: b23d9085e701c37ce2451978b1a7963c68c031e8
Parents: dd4df81
Author: Tomaz Muraus <to...@apache.org>
Authored: Wed Nov 20 14:20:15 2013 +0100
Committer: Tomaz Muraus <to...@apache.org>
Committed: Wed Nov 20 15:13:32 2013 +0100

----------------------------------------------------------------------
 libcloud/common/cloudstack.py | 82 ++++++++++++++++++++++++++++----------
 1 file changed, 62 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/b23d9085/libcloud/common/cloudstack.py
----------------------------------------------------------------------
diff --git a/libcloud/common/cloudstack.py b/libcloud/common/cloudstack.py
index a34f3df..5f139e2 100644
--- a/libcloud/common/cloudstack.py
+++ b/libcloud/common/cloudstack.py
@@ -15,6 +15,7 @@
 
 import base64
 import hashlib
+import copy
 import hmac
 
 from libcloud.utils.py3 import urlencode
@@ -39,6 +40,17 @@ class CloudStackConnection(ConnectionUserAndKey, PollingConnection):
     ASYNC_SUCCESS = 1
     ASYNC_FAILURE = 2
 
+    def encode_data(self, data):
+        """
+        Must of the data is sent as part of query params (eeww),
+        but in newer versions, userdata argument can be sent as a
+        urlencoded data in the request body.
+        """
+        if data:
+            data = urlencode(data)
+
+        return data
+
     def _make_signature(self, params):
         signature = [(k.lower(), v) for k, v in list(params.items())]
         signature.sort(key=lambda x: x[0])
@@ -59,25 +71,37 @@ class CloudStackConnection(ConnectionUserAndKey, PollingConnection):
 
         return params, headers
 
-    def _async_request(self, command, **kwargs):
-        context = {'command': command}
-        context.update(kwargs)
-        result = super(CloudStackConnection, self).async_request(action=None,
-                                                                 params=None,
-                                                                 data=None,
-                                                                 headers=None,
-                                                                 method=None,
+    def _async_request(self, command, action=None, params=None, data=None,
+                       headers=None, method='GET', context=None):
+        if params:
+            context = copy.deepcopy(params)
+        else:
+            context = {}
+
+        # Command is specified as part of GET call
+        context['command'] = command
+        result = super(CloudStackConnection, self).async_request(action=action,
+                                                                 params=params,
+                                                                 data=data,
+                                                                 headers=
+                                                                 headers,
+                                                                 method=method,
                                                                  context=
                                                                  context)
         return result['jobresult']
 
     def get_request_kwargs(self, action, params=None, data='', headers=None,
                            method='GET', context=None):
-        return context
+        command = context['command']
+        request_kwargs = {'command': command, 'action': action,
+                          'params': params, 'data': data,
+                          'headers': headers, 'method': method}
+        return request_kwargs
 
     def get_poll_request_kwargs(self, response, context, request_kwargs):
         job_id = response['jobid']
-        kwargs = {'command': 'queryAsyncJobResult', 'jobid': job_id}
+        params = {'jobid': job_id}
+        kwargs = {'command': 'queryAsyncJobResult', 'params': params}
         return kwargs
 
     def has_completed(self, response):
@@ -89,13 +113,24 @@ class CloudStackConnection(ConnectionUserAndKey, PollingConnection):
 
         return status == self.ASYNC_SUCCESS
 
-    def _sync_request(self, command, **kwargs):
-        """This method handles synchronous calls which are generally fast
-           information retrieval requests and thus return 'quickly'."""
+    def _sync_request(self, command, action=None, params=None, data=None,
+                      headers=None, method='GET'):
+        """
+        This method handles synchronous calls which are generally fast
+        information retrieval requests and thus return 'quickly'.
+        """
+        # command is always sent as part of "command" query parameter
+        if params:
+            params = copy.deepcopy(params)
+        else:
+            params = {}
+
+        params['command'] = command
+        result = self.request(action=self.driver.path, params=params,
+                              data=data, headers=headers, method=method)
 
-        kwargs['command'] = command
-        result = self.request(self.driver.path, params=kwargs)
         command = command.lower() + 'response'
+
         if command not in result.object:
             raise MalformedResponseError(
                 "Unknown response format",
@@ -116,8 +151,15 @@ class CloudStackDriverMixIn(object):
         super(CloudStackDriverMixIn, self).__init__(key, secret, secure, host,
                                                     port)
 
-    def _sync_request(self, command, **kwargs):
-        return self.connection._sync_request(command, **kwargs)
-
-    def _async_request(self, command, **kwargs):
-        return self.connection._async_request(command, **kwargs)
+    def _sync_request(self, command, action=None, params=None, data=None,
+                      headers=None, method='GET'):
+        return self.connection._sync_request(command=command, action=action,
+                                             params=params, data=data,
+                                             headers=headers, method=method)
+
+    def _async_request(self, command, action=None, params=None, data=None,
+                       headers=None, method='GET', context=None):
+        return self.connection._async_request(command=command, action=action,
+                                              params=params, data=data,
+                                              headers=headers, method=method,
+                                              context=context)