Merge lp:~rackspace-titan/nova/lp742204 into lp:~hudson-openstack/nova/trunk

Proposed by Brian Lamar
Status: Merged
Approved by: Vish Ishaya
Approved revision: 903
Merged at revision: 908
Proposed branch: lp:~rackspace-titan/nova/lp742204
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 146 lines (+61/-11)
2 files modified
nova/image/glance.py (+11/-6)
nova/tests/image/test_glance.py (+50/-5)
To merge this branch: bzr merge lp:~rackspace-titan/nova/lp742204
Reviewer Review Type Date Requested Status
Rick Harris (community) Approve
Jay Pipes (community) Approve
Dan Prince (community) Approve
Review via email: mp+55200@code.launchpad.net

Description of the change

Glance used to return None when a date field wasn't set, now it returns ''.
Glance used to return dates in format "%Y-%m-%dT%H:%M:%S", now it returns "%Y-%m-%dT%H:%M:%S.%f".

Fixed to allow for all cases.

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

Probably something of a meta question, but why aren't we using timestamps (123567890) instead of timestamps formatted as strings (2006-10-20 13:42:21)? Seems like it would negate the need for some of this.

Revision history for this message
Brian Lamar (blamar) wrote :

ISO8601 allows for timezone and tons of other stuff that a standard UNIX integer timestamp can't account for. Not that we use any of that currently... :)

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

31 +signatures: %(ISO_FORMATS)s""") % (locals()))

no need for the parens around locals() there. :)

Also, the whole thing in there about NOW_GLANCE_OLD_FORMAT and NOW_GLANCE_FORMAT seems strange. AFAIK, Glance hasn't changed the format of its datetime field values returned in the API...was this just a case of a Faked/Stubbed client returning incorrect data in the first place?

-jay

review: Needs Fixing
Revision history for this message
Brian Lamar (blamar) wrote :

> no need for the parens around locals() there. :)

So I understand that using a tuple isn't required here, but I like it for a couple, let's say, personal reasons so I have a question:

This doesn't violate PEP8 or HACKING, so without getting in to my reasons for liking this format, did I get the needs fixing because of this or because of the NOW_GLANCE_OLD_FORMAT vs. NOW_GLANCE_FORMAT?

I'm looking at that now by the way, just a second and I'll get back to you on that second part of your comment.

Revision history for this message
Mark Washenberger (markwash) wrote :

Jay,

When I first switched to converting timestamps to datetimes, people commented that it broke their glance, which was returning timestamps without milliseconds. Ed Leafe noticed it and Rick Harris noticed it enough to change it back in his images branch. So I think it is a real issue.

See https://bugs.launchpad.net/nova/+bug/741429 for Ed's comment.

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

> > no need for the parens around locals() there. :)
>
> So I understand that using a tuple isn't required here, but I like it for a
> couple, let's say, personal reasons so I have a question:
>
> This doesn't violate PEP8 or HACKING, so without getting in to my reasons for
> liking this format, did I get the needs fixing because of this or because of
> the NOW_GLANCE_OLD_FORMAT vs. NOW_GLANCE_FORMAT?

because of the (locals()) thing :)

The other was merely me being curious as to whether something really did change in Glance recently :)

Revision history for this message
Dan Prince (dan-prince) wrote :

Looks good. Just tried it and it works great.

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

> Jay,
>
> When I first switched to converting timestamps to datetimes, people commented
> that it broke their glance, which was returning timestamps without
> milliseconds. Ed Leafe noticed it and Rick Harris noticed it enough to change
> it back in his images branch. So I think it is a real issue.
>
> See https://bugs.launchpad.net/nova/+bug/741429 for Ed's comment.

OK, I just want to make sure that when you are saying "Glance" that you in fact mean the GlanceImageService in Nova, and not Glance itself. AFAIK, the output from Glance API itself has not changed anytime recently, but the GlanceImageService in Nova definitely did in Rick's branch.

It's important to be exact in describing these things so we don't go looking at the wrong thing to fix ;)

-jay

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

Hey Dan, sorry I should have caught this earlier...

30 + raise ValueError(_("""%(timestamp)s does not follow any of the \
31 +signatures: %(ISO_FORMATS)s""") % locals())

No \ is needed there, nor is the """ needed, since the string is inside a parentheses.

Should be just this:

raise ValueError(_("%(timestamp)s does not follow any of the "
                   "signatures: %(ISO_FORMATS)s") % locals())

Cheers!
jay

fix that up and approved from me.

review: Needs Fixing
Revision history for this message
Brian Lamar (blamar) wrote :

Pushed string format fix. Thanks Jay!

lp:~rackspace-titan/nova/lp742204 updated
903. By Brian Lamar

Switch string concat style.

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

rock on.

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

Looks good, nice work guys.

I think supporting ONE-TRUE-FORMAT for datetime is a good goal, so a "FIXME: remove this old format after 6/1/2011" or something would be nice. Supporting two formats indefinitely just seems messy.

That said, this looks like a good stop-gap, nicely implemented and tested.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/image/glance.py'
2--- nova/image/glance.py 2011-03-24 21:50:27 +0000
3+++ nova/image/glance.py 2011-03-29 16:12:13 +0000
4@@ -220,7 +220,7 @@
5 Returns image with known timestamp fields converted to datetime objects
6 """
7 for attr in ['created_at', 'updated_at', 'deleted_at']:
8- if image_meta.get(attr) is not None:
9+ if image_meta.get(attr):
10 image_meta[attr] = _parse_glance_iso8601_timestamp(
11 image_meta[attr])
12 return image_meta
13@@ -230,8 +230,13 @@
14 """
15 Parse a subset of iso8601 timestamps into datetime objects
16 """
17- GLANCE_FMT = "%Y-%m-%dT%H:%M:%S"
18- ISO_FMT = "%Y-%m-%dT%H:%M:%S.%f"
19- # FIXME(sirp): Glance is not returning in ISO format, we should fix Glance
20- # to do so, and then switch to parsing it here
21- return datetime.datetime.strptime(timestamp, GLANCE_FMT)
22+ iso_formats = ["%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%dT%H:%M:%S"]
23+
24+ for iso_format in iso_formats:
25+ try:
26+ return datetime.datetime.strptime(timestamp, iso_format)
27+ except ValueError:
28+ pass
29+
30+ raise ValueError(_("%(timestamp)s does not follow any of the "
31+ "signatures: %(ISO_FORMATS)s") % locals())
32
33=== modified file 'nova/tests/image/test_glance.py'
34--- nova/tests/image/test_glance.py 2011-03-24 21:13:55 +0000
35+++ nova/tests/image/test_glance.py 2011-03-29 16:12:13 +0000
36@@ -55,7 +55,8 @@
37
38
39 class BaseGlanceTest(unittest.TestCase):
40- NOW_GLANCE_FORMAT = "2010-10-11T10:30:22"
41+ NOW_GLANCE_OLD_FORMAT = "2010-10-11T10:30:22"
42+ NOW_GLANCE_FORMAT = "2010-10-11T10:30:22.000000"
43 NOW_DATETIME = datetime.datetime(2010, 10, 11, 10, 30, 22)
44
45 def setUp(self):
46@@ -74,6 +75,10 @@
47 self.assertEqual(image_meta['updated_at'], None)
48 self.assertEqual(image_meta['deleted_at'], None)
49
50+ def assertDateTimesBlank(self, image_meta):
51+ self.assertEqual(image_meta['updated_at'], '')
52+ self.assertEqual(image_meta['deleted_at'], '')
53+
54
55 class TestGlanceImageServiceProperties(BaseGlanceTest):
56 def test_show_passes_through_to_client(self):
57@@ -108,38 +113,72 @@
58 image_meta = self.service.show(self.context, 'image1')
59 self.assertDateTimesEmpty(image_meta)
60
61+ def test_show_handles_blank_datetimes(self):
62+ self.client.images = self._make_blank_datetime_fixtures()
63+ image_meta = self.service.show(self.context, 'image1')
64+ self.assertDateTimesBlank(image_meta)
65+
66 def test_detail_handles_none_datetimes(self):
67 self.client.images = self._make_none_datetime_fixtures()
68 image_meta = self.service.detail(self.context)[0]
69 self.assertDateTimesEmpty(image_meta)
70
71+ def test_detail_handles_blank_datetimes(self):
72+ self.client.images = self._make_blank_datetime_fixtures()
73+ image_meta = self.service.detail(self.context)[0]
74+ self.assertDateTimesBlank(image_meta)
75+
76 def test_get_handles_none_datetimes(self):
77 self.client.images = self._make_none_datetime_fixtures()
78 writer = NullWriter()
79 image_meta = self.service.get(self.context, 'image1', writer)
80 self.assertDateTimesEmpty(image_meta)
81
82+ def test_get_handles_blank_datetimes(self):
83+ self.client.images = self._make_blank_datetime_fixtures()
84+ writer = NullWriter()
85+ image_meta = self.service.get(self.context, 'image1', writer)
86+ self.assertDateTimesBlank(image_meta)
87+
88 def test_show_makes_datetimes(self):
89 self.client.images = self._make_datetime_fixtures()
90 image_meta = self.service.show(self.context, 'image1')
91 self.assertDateTimesFilled(image_meta)
92+ image_meta = self.service.show(self.context, 'image2')
93+ self.assertDateTimesFilled(image_meta)
94
95 def test_detail_makes_datetimes(self):
96 self.client.images = self._make_datetime_fixtures()
97 image_meta = self.service.detail(self.context)[0]
98 self.assertDateTimesFilled(image_meta)
99+ image_meta = self.service.detail(self.context)[1]
100+ self.assertDateTimesFilled(image_meta)
101
102 def test_get_makes_datetimes(self):
103 self.client.images = self._make_datetime_fixtures()
104 writer = NullWriter()
105 image_meta = self.service.get(self.context, 'image1', writer)
106 self.assertDateTimesFilled(image_meta)
107+ image_meta = self.service.get(self.context, 'image2', writer)
108+ self.assertDateTimesFilled(image_meta)
109
110 def _make_datetime_fixtures(self):
111- fixtures = {'image1': {'name': 'image1', 'is_public': True,
112- 'created_at': self.NOW_GLANCE_FORMAT,
113- 'updated_at': self.NOW_GLANCE_FORMAT,
114- 'deleted_at': self.NOW_GLANCE_FORMAT}}
115+ fixtures = {
116+ 'image1': {
117+ 'name': 'image1',
118+ 'is_public': True,
119+ 'created_at': self.NOW_GLANCE_FORMAT,
120+ 'updated_at': self.NOW_GLANCE_FORMAT,
121+ 'deleted_at': self.NOW_GLANCE_FORMAT,
122+ },
123+ 'image2': {
124+ 'name': 'image2',
125+ 'is_public': True,
126+ 'created_at': self.NOW_GLANCE_OLD_FORMAT,
127+ 'updated_at': self.NOW_GLANCE_OLD_FORMAT,
128+ 'deleted_at': self.NOW_GLANCE_OLD_FORMAT,
129+ },
130+ }
131 return fixtures
132
133 def _make_none_datetime_fixtures(self):
134@@ -148,6 +187,12 @@
135 'deleted_at': None}}
136 return fixtures
137
138+ def _make_blank_datetime_fixtures(self):
139+ fixtures = {'image1': {'name': 'image1', 'is_public': True,
140+ 'updated_at': '',
141+ 'deleted_at': ''}}
142+ return fixtures
143+
144
145 class TestMutatorDateTimeTests(BaseGlanceTest):
146 """Tests create(), update()"""