)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":1247,"name":"Mark McLoughlin","email":"markmc@redhat.com","username":"markmc"},"change_message_id":"855dee3a932b2449414b662d769c85edaa8787f2","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Correct the tzinfo from V2 GET keypair API resp"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"This patch fix the issue where in datetime object, tzinfo also"},{"line_number":10,"context_line":"comes with microsecond. Which violates the ISO9601 datetime format."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"When database value is stored in datetime object (https://github.com/"},{"line_number":13,"context_line":"openstack/nova/blob/master/nova/objects/base.py#L437), TZ also gets"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"9ad9bd40_dd572c01","line":10,"updated":"2014-04-30 16:04:28.000000000","message":"nitpick: it\u0027s ISO8601","commit_id":"fcd63dbbb12392db7767852e4ef391bed00a9670"}],"nova/api/openstack/compute/contrib/keypairs.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"a726f3b9cbffb03aaa57aaa8b6bc7340fd57f1e2","unresolved":false,"context_lines":[{"line_number":69,"context_line":"            # NOTE(GMann): Strip UTC timezones from datetimes, since they\u0027re"},{"line_number":70,"context_line":"            # stored that way in the database."},{"line_number":71,"context_line":"            if isinstance(value, datetime.datetime):"},{"line_number":72,"context_line":"                value \u003d value.replace(tzinfo\u003dNone)"},{"line_number":73,"context_line":"            _keypair[key] \u003d value"},{"line_number":74,"context_line":"        return {\"keypair\": _keypair}"},{"line_number":75,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAW3%2F%2FRkE%3D","line":72,"updated":"2014-04-15 16:19:02.000000000","message":"I\u0027d suggest looking at how oslo\u0027s timeutils is used here since I had the same problems with instance objects:\n\nhttp://git.openstack.org/cgit/openstack/nova/tree/nova/api/openstack/compute/contrib/simple_tenant_usage.py","commit_id":"33084d99bfc98c8e0bb83c028f365c454ece98f6"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"a6c702b6668d03e7067619c42982f345536c94a4","unresolved":false,"context_lines":[{"line_number":69,"context_line":"            # NOTE(GMann): Strip UTC timezones from datetimes, since they\u0027re"},{"line_number":70,"context_line":"            # stored that way in the database."},{"line_number":71,"context_line":"            if isinstance(value, datetime.datetime):"},{"line_number":72,"context_line":"                value \u003d value.replace(tzinfo\u003dNone)"},{"line_number":73,"context_line":"            _keypair[key] \u003d value"},{"line_number":74,"context_line":"        return {\"keypair\": _keypair}"},{"line_number":75,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAXH%2F%2F%2BMs%3D","line":72,"in_reply_to":"AAAAW3%2F%2FRkE%3D","updated":"2014-04-16 06:25:03.000000000","message":"Thanks Matt for review. I will make the changes as per below discussion.","commit_id":"33084d99bfc98c8e0bb83c028f365c454ece98f6"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"9698c2a478232ace9e34c44455bf79aba4ea6ccc","unresolved":false,"context_lines":[{"line_number":71,"context_line":"            if isinstance(value, datetime.datetime):"},{"line_number":72,"context_line":"                value \u003d value.replace(tzinfo\u003dNone)"},{"line_number":73,"context_line":"            _keypair[key] \u003d value"},{"line_number":74,"context_line":"        return {\"keypair\": _keypair}"},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"    @wsgi.serializers(xml\u003dKeypairTemplate)"},{"line_number":77,"context_line":"    def create(self, req, body):"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAW3%2F%2FRpo%3D","line":74,"updated":"2014-04-15 16:09:20.000000000","message":"Please don\u0027t hate me, but looking into this further, I don\u0027t think this is the right place for this fix.\n\nThe reason is that api.get_key_pair() does not actually return a database model. It returns a nova.objects.keypairs.Keypair object, and I don\u0027t believe that keypairs are the only objects that may have this problem. Let me explain further...\n\nnova.objects.keypairs.Keypair is based on nova.objects.base.PersistentNovaObject, which injects the created_at, updated_at, deleted_at, and deleted fields into all objects that get persisted to storage. The three date fields are defined as nova.objects.fields.DateTime, which looks like this:\n\n    class DateTime(FieldType):\n        @staticmethod\n        def coerce(obj, attr, value):\n            if isinstance(value, six.string_types):\n                value \u003d timeutils.parse_isotime(value)\n            elif not isinstance(value, datetime.datetime):\n                raise ValueError(_(\u0027A datetime.datetime is required here\u0027))\n\n            if value.utcoffset() is None:\n                value \u003d value.replace(tzinfo\u003diso8601.iso8601.Utc())\n            return value\n\n        def from_primitive(self, obj, attr, value):\n            return self.coerce(obj, attr, timeutils.parse_isotime(value))\n\n        @staticmethod\n        def to_primitive(obj, attr, value):\n            return timeutils.isotime(value)\n\nI believe the problem lies in the coerce() function, on this line:\n\n value \u003d value.replace(tzinfo\u003diso8601.iso8601.Utc())\n\nUnless I am mistaken, that should only be executed if there is no microsecond time part to the datetime. What do you think? Perhaps we should bring in Dan Smith to this discussion...","commit_id":"33084d99bfc98c8e0bb83c028f365c454ece98f6"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"a6c702b6668d03e7067619c42982f345536c94a4","unresolved":false,"context_lines":[{"line_number":71,"context_line":"            if isinstance(value, datetime.datetime):"},{"line_number":72,"context_line":"                value \u003d value.replace(tzinfo\u003dNone)"},{"line_number":73,"context_line":"            _keypair[key] \u003d value"},{"line_number":74,"context_line":"        return {\"keypair\": _keypair}"},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"    @wsgi.serializers(xml\u003dKeypairTemplate)"},{"line_number":77,"context_line":"    def create(self, req, body):"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAXH%2F%2F%2BNI%3D","line":74,"in_reply_to":"AAAAW3%2F%2FRfI%3D","updated":"2014-04-16 06:25:03.000000000","message":"Thanks Dan Smith for your valuable inputs. Agree with you and I have put the standardized helper method in timeutils and using that in keypair API.","commit_id":"33084d99bfc98c8e0bb83c028f365c454ece98f6"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"e3877b8724650f7e789a0fa6f7ab0ae7a2e9eb98","unresolved":false,"context_lines":[{"line_number":71,"context_line":"            if isinstance(value, datetime.datetime):"},{"line_number":72,"context_line":"                value \u003d value.replace(tzinfo\u003dNone)"},{"line_number":73,"context_line":"            _keypair[key] \u003d value"},{"line_number":74,"context_line":"        return {\"keypair\": _keypair}"},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"    @wsgi.serializers(xml\u003dKeypairTemplate)"},{"line_number":77,"context_line":"    def create(self, req, body):"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAW3%2F%2FRfI%3D","line":74,"in_reply_to":"AAAAW3%2F%2FRpo%3D","updated":"2014-04-15 16:28:16.000000000","message":"I don\u0027t think this has anything to do with the microsecond thing, and I don\u0027t think there\u0027s anything in Oslo to help with this.\n\nAFAICT, the format for the values in the keypair object are:\n\n  str(datetime.datetime(...))\n\nwhich is a pretty common pattern. If microseconds\u003d0 on the datetime, the result looks like this:\n\n \u00272014-04-15 09:20:00\u0027\n\nand if not, it looks like this:\n\n \u00272014-04-15 09:19:51.121661\u0027\n\nThat\u0027s unfortunate, but it\u0027s different from what the oslo timeutils will do if you use the isotime helpers. So, I think those are of no help here.\n\nThere are probably two issues which are being confused here. One is that the timezone is now included, which probably makes the actual output look like this:\n\n \u00272014-04-15 09:20:00.617797+00:00\u0027\n\nwhich includes microseconds and a timezone offset. Neither of these are (AFAIK) isotime format. So, in order to keep the API format looking like it has in the past, I think this needs to look like this:\n\n value \u003d value.replace(tzinfo\u003dNone, microsecond\u003d0)\n\nI think we have similar things in other bits of the API, so this could probably be standardized into a helper method that is called something like \"string_convert_datetimes_raw_format()\" or some such.\n\nI don\u0027t think changing what\u0027s in the object itself makes sense, and unfortunately, I think we\u0027re probably stuck doing this everywhere we need the old format. One alternative would be to make nova.objects.base.obj_to_primitive() do the above tz and microsecond stripping, and then make things like this keypairs extension use the primitive object conversion instead of the object itself.","commit_id":"33084d99bfc98c8e0bb83c028f365c454ece98f6"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"a6c702b6668d03e7067619c42982f345536c94a4","unresolved":false,"context_lines":[{"line_number":71,"context_line":"            if isinstance(value, datetime.datetime):"},{"line_number":72,"context_line":"                value \u003d value.replace(tzinfo\u003dNone)"},{"line_number":73,"context_line":"            _keypair[key] \u003d value"},{"line_number":74,"context_line":"        return {\"keypair\": _keypair}"},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"    @wsgi.serializers(xml\u003dKeypairTemplate)"},{"line_number":77,"context_line":"    def create(self, req, body):"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAXH%2F%2F%2BM8%3D","line":74,"in_reply_to":"AAAAW3%2F%2FRpo%3D","updated":"2014-04-16 06:25:03.000000000","message":"Thanks Jay for reviews. I like to have reviews of my patches from you guys where I can learn a lot from your experience. Its always my pleasure.","commit_id":"33084d99bfc98c8e0bb83c028f365c454ece98f6"}]}
