Skip to content

Commit

Permalink
Version 1.7.3 - fixes problems in Identity.
Browse files Browse the repository at this point in the history
  • Loading branch information
EdLeafe committed Apr 7, 2014
1 parent eb80bb0 commit 0b02cbd
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 131 deletions.
14 changes: 14 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Release Notes for pyrax

###2014.04.07 - Version 1.7.3
- Identity
- Updated the identity module and tests to work with the new http library.
GitHub #333

- General
- Fixed some log debug issues.
- Removed locale test, as it is unreliable at best.

- Cloud Files
- Round up the datetime in seconds in convert_list_last_modified to match
the behaviour in https://review.openstack.org/#/c/55488/. GitHub #337
- Fixed ValueError when handling a bulk delete response. GitHub #335

###2014.03.30 - Version 1.7.2
- General
- Fixes a bug that doubly-encoded JSON body content. GitHub #333
Expand Down
14 changes: 13 additions & 1 deletion docs/html/namespacepyrax_1_1http.html
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@
<td class="memname">def <a class="el" href="namespacepyrax_1_1http.html#aff71c1b3b5d2f16e608995f526e4d531">pyrax.http.http_log_req</a> </td>
<td>(</td>
<td class="paramtype">&#160;</td>
<td class="paramname"><em>method</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">&#160;</td>
<td class="paramname"><em>uri</em>, </td>
</tr>
<tr>
<td class="paramkey"></td>
<td></td>
<td class="paramtype">&#160;</td>
<td class="paramname"><em>args</em>, </td>
</tr>
<tr>
Expand Down Expand Up @@ -272,7 +284,7 @@


<hr class="footer"/><address class="footer"><small>
Generated on Fri Mar 28 2014 08:11:55 for pyrax by &#160;<a href="http://www.doxygen.org/index.html">
Generated on Mon Apr 7 2014 11:41:29 for pyrax by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.7.6.1
</small></address>
Expand Down
6 changes: 3 additions & 3 deletions docs/html/namespacepyrax_1_1version.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,15 @@
<table class="memberdecls">
<tr><td colspan="2"><h2><a name="var-members"></a>
Variables</h2></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">string&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespacepyrax_1_1version.html#af9c8593b58583463efe6932e24c9d6e6">version</a> = &quot;1.7.2&quot;</td></tr>
<tr><td class="memItemLeft" align="right" valign="top">string&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespacepyrax_1_1version.html#af9c8593b58583463efe6932e24c9d6e6">version</a> = &quot;1.7.3&quot;</td></tr>
</table>
<hr/><h2>Variable Documentation</h2>
<a class="anchor" id="af9c8593b58583463efe6932e24c9d6e6"></a><!-- doxytag: member="pyrax::version::version" ref="af9c8593b58583463efe6932e24c9d6e6" args="" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">string <a class="el" href="namespacepyrax_1_1version.html#af9c8593b58583463efe6932e24c9d6e6">version</a> = &quot;1.7.2&quot;</td>
<td class="memname">string <a class="el" href="namespacepyrax_1_1version.html#af9c8593b58583463efe6932e24c9d6e6">version</a> = &quot;1.7.3&quot;</td>
</tr>
</table>
</div>
Expand All @@ -139,7 +139,7 @@


<hr class="footer"/><address class="footer"><small>
Generated on Sun Mar 30 2014 12:28:48 for pyrax by &#160;<a href="http://www.doxygen.org/index.html">
Generated on Mon Apr 7 2014 11:41:30 for pyrax by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.7.6.1
</small></address>
Expand Down
4 changes: 2 additions & 2 deletions docs/html/version_8py.html
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
<tr><td class="memItemLeft" align="right" valign="top">namespace &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespacepyrax_1_1version.html">pyrax::version</a></td></tr>
<tr><td colspan="2"><h2><a name="var-members"></a>
Variables</h2></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">string&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespacepyrax_1_1version.html#af9c8593b58583463efe6932e24c9d6e6">version</a> = &quot;1.7.2&quot;</td></tr>
<tr><td class="memItemLeft" align="right" valign="top">string&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="namespacepyrax_1_1version.html#af9c8593b58583463efe6932e24c9d6e6">version</a> = &quot;1.7.3&quot;</td></tr>
</table>
</div><!-- contents -->
<!-- window showing the filter options -->
Expand All @@ -108,7 +108,7 @@


<hr class="footer"/><address class="footer"><small>
Generated on Sun Mar 30 2014 12:28:42 for pyrax by &#160;<a href="http://www.doxygen.org/index.html">
Generated on Mon Apr 7 2014 11:41:24 for pyrax by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.7.6.1
</small></address>
Expand Down
68 changes: 32 additions & 36 deletions pyrax/base_identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,14 @@ def _call_token_auth(self, token, tenant_id, tenant_name):
headers = {"Content-Type": "application/json",
"Accept": "application/json",
}
resp = self.method_post("tokens", data=body, headers=headers,
resp, resp_body = self.method_post("tokens", data=body, headers=headers,
std_headers=False)
if resp.status_code == 401:
# Invalid authorization
raise exc.AuthenticationFailed("Incorrect/unauthorized "
"credentials received")
elif resp.status_code > 299:
msg_dict = resp.json()
msg = msg_dict[msg_dict.keys()[0]]["message"]
msg = resp_body[resp_body.keys()[0]]["message"]
raise exc.AuthenticationFailed("%s - %s." % (resp.reason, msg))
return resp

Expand Down Expand Up @@ -255,8 +254,9 @@ def _call(self, mthd, uri, admin, data, headers, std_headers):
hdrs = {}
if headers:
hdrs.update(headers)
kwargs = {"headers": hdrs,
"body": data}
kwargs = {"headers": hdrs}
if data:
kwargs["body"] = data
if "tokens" in uri:
# We'll handle the exception here
kwargs["raise_exception"] = False
Expand Down Expand Up @@ -363,8 +363,8 @@ def get_extensions(self):
"""
Returns a list of extensions enabled on this service.
"""
resp = self.method_get("extensions")
return resp.json().get("extensions", {}).get("values")
resp, resp_body = self.method_get("extensions")
return resp_body.get("extensions", {}).get("values")


def get_token(self, force=False):
Expand Down Expand Up @@ -392,12 +392,11 @@ def list_tokens(self):
ADMIN ONLY. Returns a dict containing tokens, endpoints, user info, and
role metadata.
"""
resp = self.method_get("tokens/%s" % self.token, admin=True)
resp, resp_body = self.method_get("tokens/%s" % self.token, admin=True)
if resp.status_code in (401, 403):
raise exc.AuthorizationFailure("You must be an admin to make this "
"call.")
token_dct = resp.json()
return token_dct.get("access")
return resp_body.get("access")


def check_token(self, token=None):
Expand All @@ -407,7 +406,7 @@ def check_token(self, token=None):
"""
if token is None:
token = self.token
resp = self.method_head("tokens/%s" % token, admin=True)
resp, resp_body = self.method_head("tokens/%s" % token, admin=True)
if resp.status_code in (401, 403):
raise exc.AuthorizationFailure("You must be an admin to make this "
"call.")
Expand All @@ -418,12 +417,12 @@ def get_token_endpoints(self):
"""
ADMIN ONLY. Returns a list of all endpoints for the current auth token.
"""
resp = self.method_get("tokens/%s/endpoints" % self.token, admin=True)
resp, resp_body = self.method_get("tokens/%s/endpoints" % self.token,
admin=True)
if resp.status_code in (401, 403, 404):
raise exc.AuthorizationFailure("You are not authorized to list "
"token endpoints.")
token_dct = resp.json()
return token_dct.get("access", {}).get("endpoints")
return resp_body.get("access", {}).get("endpoints")


def list_users(self):
Expand All @@ -432,17 +431,16 @@ def list_users(self):
(account) if this request is issued by a user holding the admin role
(identity:user-admin).
"""
resp = self.method_get("users", admin=True)
resp, resp_body = self.method_get("users", admin=True)
if resp.status_code in (401, 403, 404):
raise exc.AuthorizationFailure("You are not authorized to list "
"users.")
users = resp.json()
# The API is inconsistent; if only one user exists, it will not return
# a list.
if "users" in users:
users = users["users"]
if "users" in resp_body:
users = resp_body["users"]
else:
users = [users]
users = [resp_body]
# The returned values may contain password data. Strip that out.
for user in users:
bad_keys = [key for key in user.keys()
Expand Down Expand Up @@ -473,18 +471,16 @@ def create_user(self, name, email, password=None, enabled=True):
}}
if password:
data["user"]["OS-KSADM:password"] = password
resp = self.method_post("users", data=data, admin=True)
resp, resp_body = self.method_post("users", data=data, admin=True)
if resp.status_code == 201:
jresp = resp.json()
return User(self, jresp)
return User(self, resp_body)
elif resp.status_code in (401, 403, 404):
raise exc.AuthorizationFailure("You are not authorized to create "
"users.")
elif resp.status_code == 409:
raise exc.DuplicateUser("User '%s' already exists." % name)
elif resp.status_code == 400:
status = json.loads(resp.text)
message = status["badRequest"]["message"]
message = resp_body["badRequest"]["message"]
if "Expecting valid email address" in message:
raise exc.InvalidEmail("%s is not valid" % email)
else:
Expand All @@ -507,11 +503,11 @@ def update_user(self, user, email=None, username=None,
if enabled is not None:
upd["enabled"] = enabled
data = {"user": upd}
resp = self.method_put(uri, data=data)
resp, resp_body = self.method_put(uri, data=data)
if resp.status_code in (401, 403, 404):
raise exc.AuthorizationFailure("You are not authorized to update "
"users.")
return User(self, resp.json())
return User(self, resp_body)


def delete_user(self, user):
Expand All @@ -522,7 +518,7 @@ def delete_user(self, user):
"""
user_id = utils.get_id(user)
uri = "users/%s" % user_id
resp = self.method_delete(uri)
resp, resp_body = self.method_delete(uri)
if resp.status_code == 404:
raise exc.UserNotFound("User '%s' does not exist." % user)
elif resp.status_code in (401, 403):
Expand All @@ -538,11 +534,11 @@ def list_roles_for_user(self, user):
"""
user_id = utils.get_id(user)
uri = "users/%s/roles" % user_id
resp = self.method_get(uri)
resp, resp_body = self.method_get(uri)
if resp.status_code in (401, 403):
raise exc.AuthorizationFailure("You are not authorized to list "
"user roles.")
roles = resp.json().get("roles")
roles = resp_body.get("roles")
return roles


Expand All @@ -568,9 +564,9 @@ def _list_tenants(self, admin):
Returns either a list of all tenants (admin=True), or the tenant for
the currently-authenticated user (admin=False).
"""
resp = self.method_get("tenants", admin=admin)
resp, resp_body = self.method_get("tenants", admin=admin)
if 200 <= resp.status_code < 300:
tenants = resp.json().get("tenants", [])
tenants = resp_body.get("tenants", [])
return [Tenant(self, tenant) for tenant in tenants]
elif resp.status_code in (401, 403):
raise exc.AuthorizationFailure("You are not authorized to list "
Expand All @@ -589,8 +585,8 @@ def create_tenant(self, name, description=None, enabled=True):
}}
if description:
data["tenant"]["description"] = description
resp = self.method_post("tenants", data=data)
return Tenant(self, resp.json())
resp, resp_body = self.method_post("tenants", data=data)
return Tenant(self, resp_body)


def update_tenant(self, tenant, name=None, description=None, enabled=True):
Expand All @@ -605,8 +601,8 @@ def update_tenant(self, tenant, name=None, description=None, enabled=True):
data["tenant"]["name"] = name
if description:
data["tenant"]["description"] = description
resp = self.method_put("tenants/%s" % tenant_id, data=data)
return Tenant(self, resp.json())
resp, resp_body = self.method_put("tenants/%s" % tenant_id, data=data)
return Tenant(self, resp_body)


def delete_tenant(self, tenant):
Expand All @@ -617,7 +613,7 @@ def delete_tenant(self, tenant):
"""
tenant_id = utils.get_id(tenant)
uri = "tenants/%s" % tenant_id
resp = self.method_delete(uri)
resp, resp_body = self.method_delete(uri)
if resp.status_code == 404:
raise exc.TenantNotFound("Tenant '%s' does not exist." % tenant)

Expand Down
17 changes: 12 additions & 5 deletions pyrax/cf_wrapper/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,22 @@ def _convert_head_object_last_modified_to_local(lm_str):


def _convert_list_last_modified_to_local(attdict):
if 'last_modified' in attdict:
if "last_modified" in attdict:
attdict = attdict.copy()
list_date_format_with_tz = LIST_DATE_FORMAT + ' %Z'
last_modified_utc = attdict['last_modified'] + ' UTC'
list_date_format_with_tz = LIST_DATE_FORMAT + " %Z"
last_modified_utc = attdict["last_modified"] + " UTC"
tm_tuple = time.strptime(last_modified_utc,
list_date_format_with_tz)
dttm = datetime.datetime.fromtimestamp(time.mktime(tm_tuple))
attdict['last_modified'] = dttm.strftime(DATE_FORMAT)

dttm_with_micros = datetime.datetime.strptime(last_modified_utc,
list_date_format_with_tz)
# Round the date *up* in seconds, to match the last modified time
# in head requests
# https://review.openstack.org/#/c/55488/
if dttm_with_micros.microsecond > 0:
dttm += datetime.timedelta(seconds=1)
attdict["last_modified"] = dttm.strftime(DATE_FORMAT)
return attdict


Expand Down Expand Up @@ -1547,7 +1554,7 @@ def run(self):
reason = resp.reason
resp_body = resp.read()
for resp_line in resp_body.splitlines():
if not resp_line:
if not resp_line.strip():
continue
resp_key, val = resp_line.split(":", 1)
result_key = res_keys.get(resp_key)
Expand Down
23 changes: 11 additions & 12 deletions pyrax/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
Wrapper around the requests library. Used for making all HTTP calls.
"""

import logging
import json
import requests

Expand Down Expand Up @@ -48,7 +49,7 @@ def request(method, uri, *args, **kwargs):
req_method = req_methods[method.upper()]
raise_exception = kwargs.pop("raise_exception", True)
kwargs["headers"] = kwargs.get("headers", {})
http_log_req(args, kwargs)
http_log_req(method, uri, args, kwargs)
data = None
if "data" in kwargs:
# The 'data' kwarg is used when you don't want json encoding.
Expand All @@ -72,25 +73,22 @@ def request(method, uri, *args, **kwargs):
return resp, body


def http_log_req(args, kwargs):
def http_log_req(method, uri, args, kwargs):
"""
When pyrax.get_http_debug() is True, outputs the equivalent `curl`
command for the API request being made.
"""
if not pyrax.get_http_debug():
return
string_parts = ["curl -i"]
string_parts = ["curl -i -X %s" % method]
for element in args:
if element in ("GET", "POST", "PUT", "DELETE", "HEAD", "PATCH"):
string_parts.append(" -X %s" % element)
else:
string_parts.append(" %s" % element)

string_parts.append("%s" % element)
for element in kwargs["headers"]:
header = " -H '%s: %s'" % (element, kwargs["headers"][element])
header = "-H '%s: %s'" % (element, kwargs["headers"][element])
string_parts.append(header)

pyrax._logger.debug("\nREQ: %s\n" % "".join(string_parts))
string_parts.append(uri)
log = logging.getLogger("pyrax")
log.debug("\nREQ: %s\n" % " ".join(string_parts))
if "body" in kwargs:
pyrax._logger.debug("REQ BODY: %s\n" % (kwargs["body"]))

Expand All @@ -102,4 +100,5 @@ def http_log_resp(resp, body):
"""
if not pyrax.get_http_debug():
return
pyrax._logger.debug("RESP: %s %s\n", resp, body)
log = logging.getLogger("pyrax")
log.debug("RESP: %s %s\n", resp, body)
Loading

0 comments on commit 0b02cbd

Please sign in to comment.