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):