Repository: cloudstack-cloudmonkey
Updated Branches:
  refs/heads/5.3 f0a7c275e -> 4031e5efe


requester: cleanup url encoding, use requests, better error logging

Signed-off-by: Rohit Yadav <rohit.ya...@shapeblue.com>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/commit/4031e5ef
Tree: 
http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/tree/4031e5ef
Diff: 
http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/diff/4031e5ef

Branch: refs/heads/5.3
Commit: 4031e5efe1f0b5dc3e7f47dcd03baa6cf0b291dc
Parents: f0a7c27
Author: Rohit Yadav <rohit.ya...@shapeblue.com>
Authored: Fri Oct 31 22:22:26 2014 +0530
Committer: Rohit Yadav <rohit.ya...@shapeblue.com>
Committed: Fri Oct 31 22:22:26 2014 +0530

----------------------------------------------------------------------
 cloudmonkey/requester.py | 68 +++++++++++++++++++++++++------------------
 1 file changed, 39 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack-cloudmonkey/blob/4031e5ef/cloudmonkey/requester.py
----------------------------------------------------------------------
diff --git a/cloudmonkey/requester.py b/cloudmonkey/requester.py
index e05dc75..63f753c 100644
--- a/cloudmonkey/requester.py
+++ b/cloudmonkey/requester.py
@@ -133,8 +133,8 @@ def make_request_with_password(command, args, logger, url, 
credentials):
             continue
 
         if resp.status_code != 200 and resp.status_code != 401:
-            error = u"{0}: {1}".format(resp.status_code,
-                                       resp.headers.get('X-Description'))
+            error = "{0}: {1}".format(resp.status_code,
+                                      resp.headers.get('X-Description'))
             result = None
             retry = False
 
@@ -142,7 +142,7 @@ def make_request_with_password(command, args, logger, url, 
credentials):
 
 
 def make_request(command, args, logger, url, credentials, expires):
-    response = None
+    result = None
     error = None
 
     if not url.startswith('http'):
@@ -161,6 +161,11 @@ def make_request(command, args, logger, url, credentials, 
expires):
     expirationtime = datetime.utcnow() + timedelta(seconds=int(expires))
     args["expires"] = expirationtime.strftime('%Y-%m-%dT%H:%M:%S+0000')
 
+    for key, value in args.iteritems():
+        if isinstance(value, unicode):
+            value = value.encode("utf-8")
+        args[key] = value
+
     # try to use the apikey/secretkey method by default
     # followed by trying to check if we're using integration port
     # finally use the username/password method
@@ -171,37 +176,42 @@ def make_request(command, args, logger, url, credentials, 
expires):
         except (requests.exceptions.ConnectionError, Exception), e:
             return None, e
 
-    args['apiKey'] = credentials['apikey']
-    secretkey = credentials['secretkey']
-    request = zip(args.keys(), map(lambda x: x.encode("utf-8"), args.values()))
-    request.sort(key=lambda x: x[0].lower())
+    def sign_request(params, secret_key):
+        request = zip(params.keys(), params.values())
+        request.sort(key=lambda x: x[0].lower())
+        hash_str = "&".join(
+            ["=".join(
+                [r[0].lower(),
+                 urllib.quote_plus(str(r[1])).lower().replace("+", "%20")]
+            ) for r in request]
+        )
+        return base64.encodestring(hmac.new(secret_key, hash_str,
+                                   hashlib.sha1).digest()).strip()
 
-    request_url = u"&".join([u"=".join([r[0], urllib.quote(r[1])])
-                            for r in request])
-    hashStr = u"&".join([u"=".join([r[0].lower(), urllib.quote(r[1]).lower()])
-                        for r in request])
-
-    sig = urllib.quote(base64.encodestring(hmac.new(secretkey, hashStr,
-                       hashlib.sha1).digest()).strip())
-    request_url += "&signature=%s" % sig
-    request_url = "%s?%s" % (url, request_url)
+    args['apiKey'] = credentials['apikey']
+    args["signature"] = sign_request(args, credentials['secretkey'])
 
     try:
-        logger_debug(logger, "Request sent: %s" % request_url)
-        connection = urllib2.urlopen(request_url)
-        response = connection.read()
-    except HTTPError, e:
-        error = u"{0}{1}: {2}".format(e.code, e.msg,
-                                      e.info().getheader('X-Description'))
-    except URLError, e:
-        error = e.reason
-
-    logger_debug(logger, "Response received: %s" % response)
+        response = requests.get(url, params=args)
+        logger_debug(logger, "Request sent: %s" % response.url)
+        result = response.text
+
+        if response.status_code == 200:  # success
+            error = None
+        elif response.status_code == 401:      # auth issue
+            error = "401 Authentication error"
+        elif response.status_code != 200 and response.status_code != 401:
+            error = "{0}: {1}".format(response.status_code,
+                                      response.headers.get('X-Description'))
+    except Exception, pokemon:
+        error = unicode(pokemon)
+
+    logger_debug(logger, "Response received: %s" % result)
     if error is not None:
         logger_debug(logger, "Error: %s" % (error))
-        return response, error
+        return result, error
 
-    return response, error
+    return result, error
 
 
 def monkeyrequest(command, args, isasync, asyncblock, logger, url,
@@ -215,7 +225,7 @@ def monkeyrequest(command, args, isasync, asyncblock, 
logger, url,
 
     logger_debug(logger, "======== END Request ========\n")
 
-    if error is not None:
+    if error is not None and not response:
         return response, error
 
     def process_json(response):

Reply via email to