Merge lp:~jaypipes/glance/bug756886 into lp:~glance-coresec/glance/cactus-trunk

Proposed by Jay Pipes
Status: Merged
Approved by: Jay Pipes
Approved revision: 109
Merged at revision: 110
Proposed branch: lp:~jaypipes/glance/bug756886
Merge into: lp:~glance-coresec/glance/cactus-trunk
Diff against target: 94 lines (+57/-4)
3 files modified
doc/source/glanceapi.rst (+1/-2)
glance/utils.py (+15/-2)
tests/unit/test_utils.py (+41/-0)
To merge this branch: bzr merge lp:~jaypipes/glance/bug756886
Reviewer Review Type Date Requested Status
Thierry Carrez (community) Approve
Rick Harris (community) Approve
justinsb (community) Approve
Review via email: mp+57321@code.launchpad.net

Description of the change

Change parsing of headers to accept 'True', 'on', 1 for boolean truth values.

To post a comment you must log in.
Revision history for this message
Rick Harris (rconradharris) wrote :

I'm not so sure I agree with the intent of this patch. The code doesn't match the docs; but, in this case, I think it might be the docs that are in the wrong.

I'm not sure why we would want to loosen our constraints around what's accepted by Glance's boolean fields. I know other projects do this, and it's arisen as a sort of anti-pattern to accept "1", "true" or "on" in a lot of config files. To me, though, a single "True" or "False" value is much less ambiguous and thus easier to communicate to users. ("Use true or false or it ain't gonna work!")

This might cause some issues when configs are more naturally expressed as "on" and "off". But the trade off of a single "Right Way" I think is worth the minor mismatch. Thoughts?

In terms of the code, looks good, but `isinstance` is preferred to `type()` these days (I believe).

Revision history for this message
Jay Pipes (jaypipes) wrote :

I could go either way, really. Not a big deal at all. Justin, what do you think?

Revision history for this message
Devin Carlen (devcamcar) wrote :

Tend to agree - let's just standardize around true/false, case insensitive and keep it simple.

Revision history for this message
Jay Pipes (jaypipes) wrote :

okey dokey, I'll fix up and re-propose.

Revision history for this message
justinsb (justin-fathomdb) wrote :

I don't really mind, as long as the docs match :-) I think most of the issues I filed with glance could be doc issues. It's OK to have a strict API as long as the rules are clearly documented.

Case insensitive 'true' is an improvement though, as is abstracting this logic into a function, and so LGTM, whatever values we converge on.

review: Approve
Revision history for this message
Jay Pipes (jaypipes) wrote :

OK, sounds good. I'm changing the docs and modifying the code to just do case-insensitive checks on 'true' and 'false'. Cheers!

Revision history for this message
Jay Pipes (jaypipes) wrote :

OK, guys, please re-review. Thanks!

Revision history for this message
justinsb (justin-fathomdb) wrote :

LGTM. Thanks for fixing the docs as well!

review: Approve
Revision history for this message
Rick Harris (rconradharris) wrote :

Awesome, thanks Jay.

review: Approve
Revision history for this message
Thierry Carrez (ttx) wrote :

lgtm

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/source/glanceapi.rst'
2--- doc/source/glanceapi.rst 2011-03-08 16:40:35 +0000
3+++ doc/source/glanceapi.rst 2011-04-12 21:48:27 +0000
4@@ -308,8 +308,7 @@
5
6 This header is optional.
7
8- When present, Glance converts the value of the header to a boolean value,
9- so "on, 1, true" are all true values. When true, the image is marked as
10+ When Glance finds the string "true" (case-insensitive), the image is marked as
11 a public image, meaning that any user may view its metadata and may read
12 the disk image from Glance.
13
14
15=== modified file 'glance/utils.py'
16--- glance/utils.py 2011-03-09 13:38:25 +0000
17+++ glance/utils.py 2011-04-12 21:48:27 +0000
18@@ -91,12 +91,25 @@
19 if 'size' in result:
20 result['size'] = int(result['size'])
21 if 'is_public' in result:
22- result['is_public'] = (result['is_public'] == 'True')
23+ result['is_public'] = bool_from_header_value(result['is_public'])
24 if 'deleted' in result:
25- result['deleted'] = (result['deleted'] == 'True')
26+ result['deleted'] = bool_from_header_value(result['deleted'])
27 return result
28
29
30+def bool_from_header_value(value):
31+ """
32+ Returns True if value is a boolean True or the
33+ string 'true', case-insensitive, False otherwise
34+ """
35+ if isinstance(value, bool):
36+ return value
37+ elif isinstance(value, (basestring, unicode)):
38+ if str(value).lower() == 'true':
39+ return True
40+ return False
41+
42+
43 def has_body(req):
44 """
45 Returns whether a Webob.Request object will possess an entity body.
46
47=== modified file 'tests/unit/test_utils.py'
48--- tests/unit/test_utils.py 2011-03-17 21:43:26 +0000
49+++ tests/unit/test_utils.py 2011-04-12 21:48:27 +0000
50@@ -65,3 +65,44 @@
51 result = utils.get_image_meta_from_headers(response)
52 for k, v in fixture.iteritems():
53 self.assertEqual(v, result[k])
54+
55+ def test_boolean_header_values(self):
56+ """
57+ Tests that boolean headers like is_public can be set
58+ to True if any of ('True', 'On', 1) is provided, case-insensitive
59+ """
60+ fixtures = [{'is_public': True},
61+ {'is_public': 'True'},
62+ {'is_public': 'true'}]
63+
64+ expected = {'is_public': True}
65+
66+ class FakeResponse():
67+ pass
68+
69+ for fixture in fixtures:
70+ headers = utils.image_meta_to_http_headers(fixture)
71+
72+ response = FakeResponse()
73+ response.headers = headers
74+ result = utils.get_image_meta_from_headers(response)
75+ for k, v in expected.items():
76+ self.assertEqual(v, result[k])
77+
78+ # Ensure False for other values...
79+ fixtures = [{'is_public': False},
80+ {'is_public': 'Off'},
81+ {'is_public': 'on'},
82+ {'is_public': '1'},
83+ {'is_public': 'False'}]
84+
85+ expected = {'is_public': False}
86+
87+ for fixture in fixtures:
88+ headers = utils.image_meta_to_http_headers(fixture)
89+
90+ response = FakeResponse()
91+ response.headers = headers
92+ result = utils.get_image_meta_from_headers(response)
93+ for k, v in expected.items():
94+ self.assertEqual(v, result[k])

Subscribers

People subscribed via source and target branches