)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":15519,"name":"Iury Gregory Melo Ferreira","display_name":"Iury Gregory","email":"iurygregory@gmail.com","username":"iurygregory"},"change_message_id":"471d742d343a4c91af52ef59e5609b943f4fe34d","unresolved":false,"context_lines":[{"line_number":9,"context_line":"Calculate duration_seconds from provision_updated_at and record"},{"line_number":10,"context_line":"provision_state and target_provision_state when creating history entries."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Depends-On: https://review.opendev.org/c/openstack/ironic/+/989994"},{"line_number":13,"context_line":"Story: #2154817"},{"line_number":14,"context_line":"Related-Bug: #2154817"},{"line_number":15,"context_line":"Change-Id: I831aafb1facb0ed82d00fce511a78572ff36f0ee"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":18,"id":"ca1b1233_92ebd6f5","line":12,"updated":"2026-08-11 14:23:25.000000000","message":"nit: since you are working on chain of patches, you don\u0027t need the Depends-On \u003d)","commit_id":"43ca6377391fc80b56f7d74874f22eb36e4f8142"},{"author":{"_account_id":38972,"name":"Esther Domfeh","display_name":"edomfeh","email":"estherdomfeh88@gmail.com","username":"edomfeh"},"change_message_id":"bdc1c54beeabe3d0944287b9c242719028e39074","unresolved":false,"context_lines":[{"line_number":9,"context_line":"Calculate duration_seconds from provision_updated_at and record"},{"line_number":10,"context_line":"provision_state and target_provision_state when creating history entries."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Depends-On: https://review.opendev.org/c/openstack/ironic/+/989994"},{"line_number":13,"context_line":"Story: #2154817"},{"line_number":14,"context_line":"Related-Bug: #2154817"},{"line_number":15,"context_line":"Change-Id: I831aafb1facb0ed82d00fce511a78572ff36f0ee"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":18,"id":"e545e61e_53e80b5c","line":12,"in_reply_to":"ca1b1233_92ebd6f5","updated":"2026-08-11 17:00:20.000000000","message":"Thanks for the feedback,Iury! I’ve removed the Depends-On line in the latest patchset.","commit_id":"43ca6377391fc80b56f7d74874f22eb36e4f8142"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":38972,"name":"Esther Domfeh","display_name":"edomfeh","email":"estherdomfeh88@gmail.com","username":"edomfeh"},"change_message_id":"bcf68646dcc63b95cc69570b158287d814d1c2b8","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":4,"id":"a660ec3e_cb7acc09","updated":"2026-06-23 07:47:46.000000000","message":"recheck","commit_id":"1c016c411d8e5f21491b4311a630d1122373327e"},{"author":{"_account_id":38972,"name":"Esther Domfeh","display_name":"edomfeh","email":"estherdomfeh88@gmail.com","username":"edomfeh"},"change_message_id":"b676bff9397aac1c7b1a3170709308f4c03892d8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"91cf6453_974c9e47","in_reply_to":"a660ec3e_cb7acc09","updated":"2026-07-08 09:56:41.000000000","message":"Done","commit_id":"1c016c411d8e5f21491b4311a630d1122373327e"},{"author":{"_account_id":23851,"name":"Riccardo Pittau","email":"elfosardo@gmail.com","username":"elfosardo"},"change_message_id":"b568330ef05c95cd7344e1ce889df17de2967532","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":19,"id":"8f409d2e_bc28b7de","updated":"2026-08-12 07:44:43.000000000","message":"no change, just a rebase on the parent patch, single approving as it was approved before","commit_id":"3cc18adff6dfdb0dc4b35c98c5e51af9d8f74087"}],"ironic/conductor/utils.py":[{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"643b63d3e87bfdf1a2d79cf03b0cc1aee1177e4c","unresolved":true,"context_lines":[{"line_number":1930,"context_line":"        # Use provision_updated_at as the timestamp when the node entered"},{"line_number":1931,"context_line":"        # its current state"},{"line_number":1932,"context_line":"        duration \u003d None"},{"line_number":1933,"context_line":"        provision_updated_at \u003d getattr(node, \u0027provision_updated_at\u0027, None)"},{"line_number":1934,"context_line":"        if provision_updated_at:"},{"line_number":1935,"context_line":"            try:"},{"line_number":1936,"context_line":"                now \u003d timeutils.utcnow()"}],"source_content_type":"text/x-python","patch_set":2,"id":"e5cca153_616ac93d","line":1933,"range":{"start_line":1933,"start_character":8,"end_line":1933,"end_character":74},"updated":"2026-06-18 12:20:31.000000000","message":"I don\u0027t think we need this variable? Just do `if node.provision_updated_at is not None` - nodes will always have the attribute.","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"},{"author":{"_account_id":38972,"name":"Esther Domfeh","display_name":"edomfeh","email":"estherdomfeh88@gmail.com","username":"edomfeh"},"change_message_id":"e2b123884e7951445ad1b7b196adb2efc83608b3","unresolved":false,"context_lines":[{"line_number":1930,"context_line":"        # Use provision_updated_at as the timestamp when the node entered"},{"line_number":1931,"context_line":"        # its current state"},{"line_number":1932,"context_line":"        duration \u003d None"},{"line_number":1933,"context_line":"        provision_updated_at \u003d getattr(node, \u0027provision_updated_at\u0027, None)"},{"line_number":1934,"context_line":"        if provision_updated_at:"},{"line_number":1935,"context_line":"            try:"},{"line_number":1936,"context_line":"                now \u003d timeutils.utcnow()"}],"source_content_type":"text/x-python","patch_set":2,"id":"ce4d1929_1ea1fdc6","line":1933,"range":{"start_line":1933,"start_character":8,"end_line":1933,"end_character":74},"in_reply_to":"e5cca153_616ac93d","updated":"2026-06-18 17:12:57.000000000","message":"Done","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"643b63d3e87bfdf1a2d79cf03b0cc1aee1177e4c","unresolved":true,"context_lines":[{"line_number":1932,"context_line":"        duration \u003d None"},{"line_number":1933,"context_line":"        provision_updated_at \u003d getattr(node, \u0027provision_updated_at\u0027, None)"},{"line_number":1934,"context_line":"        if provision_updated_at:"},{"line_number":1935,"context_line":"            try:"},{"line_number":1936,"context_line":"                now \u003d timeutils.utcnow()"},{"line_number":1937,"context_line":"                time_spent \u003d now - node.provision_updated_at"},{"line_number":1938,"context_line":"                duration \u003d int(time_spent.total_seconds())"}],"source_content_type":"text/x-python","patch_set":2,"id":"b8437eb3_f29f456f","line":1935,"range":{"start_line":1935,"start_character":0,"end_line":1935,"end_character":2},"updated":"2026-06-18 12:20:31.000000000","message":"I think this is simple enough to not have a try except block. If we want to keep it for defense, change it to catch TypeError only.","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"},{"author":{"_account_id":38972,"name":"Esther Domfeh","display_name":"edomfeh","email":"estherdomfeh88@gmail.com","username":"edomfeh"},"change_message_id":"e2b123884e7951445ad1b7b196adb2efc83608b3","unresolved":false,"context_lines":[{"line_number":1932,"context_line":"        duration \u003d None"},{"line_number":1933,"context_line":"        provision_updated_at \u003d getattr(node, \u0027provision_updated_at\u0027, None)"},{"line_number":1934,"context_line":"        if provision_updated_at:"},{"line_number":1935,"context_line":"            try:"},{"line_number":1936,"context_line":"                now \u003d timeutils.utcnow()"},{"line_number":1937,"context_line":"                time_spent \u003d now - node.provision_updated_at"},{"line_number":1938,"context_line":"                duration \u003d int(time_spent.total_seconds())"}],"source_content_type":"text/x-python","patch_set":2,"id":"a8d6905c_ad7c51ac","line":1935,"range":{"start_line":1935,"start_character":0,"end_line":1935,"end_character":2},"in_reply_to":"b8437eb3_f29f456f","updated":"2026-06-18 17:12:57.000000000","message":"Done","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"643b63d3e87bfdf1a2d79cf03b0cc1aee1177e4c","unresolved":true,"context_lines":[{"line_number":1933,"context_line":"        provision_updated_at \u003d getattr(node, \u0027provision_updated_at\u0027, None)"},{"line_number":1934,"context_line":"        if provision_updated_at:"},{"line_number":1935,"context_line":"            try:"},{"line_number":1936,"context_line":"                now \u003d timeutils.utcnow()"},{"line_number":1937,"context_line":"                time_spent \u003d now - node.provision_updated_at"},{"line_number":1938,"context_line":"                duration \u003d int(time_spent.total_seconds())"},{"line_number":1939,"context_line":"            except Exception:"},{"line_number":1940,"context_line":"                # If something goes wrong with the calculation, we just log it"}],"source_content_type":"text/x-python","patch_set":2,"id":"6d4706cf_67b8c588","line":1937,"range":{"start_line":1936,"start_character":16,"end_line":1937,"end_character":60},"updated":"2026-06-18 12:20:31.000000000","message":"If you look at the CI logs, this always fails:\nJun 16 10:29:12.522579 np7a560a5530f74 ironic-conductor[90617]: DEBUG ironic.conductor.utils [None req-90db3e75-4dfa-460e-b94b-337762584bb8 None None] Failed to calculate duration for node c716c0fc-a98b-466b-b432-66b3f4f2f2bc {{(pid\u003d90617) node_history_record /opt/stack/ironic/ironic/conductor/utils.py:1942}}\n\nRef: https://ca32b7770d8fc21859b8-0343763e072aec8a44b36b196f4e6ba5.ssl.cf1.rackcdn.com/openstack/ff73fd07de134b5f9b92d26d3f864c45/controller/logs/screen-ir-cond.txt\n\nMost likely the time calculation raises TypeError because node.provision_updated_at is tzinfo aware.\n\n```\n    now \u003d timeutils.utcnow(with_timezone\u003dTrue)\n    time_spent \u003d now - node.provision_updated_at\n```\n\nor\n\n```\nupdated_at \u003d timeutils.normalize_time(node.provision_updated_at)\nnow \u003d timeutils.utcnow()\ntime_spent \u003d now - updated_at\n```","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"},{"author":{"_account_id":38972,"name":"Esther Domfeh","display_name":"edomfeh","email":"estherdomfeh88@gmail.com","username":"edomfeh"},"change_message_id":"e2b123884e7951445ad1b7b196adb2efc83608b3","unresolved":false,"context_lines":[{"line_number":1933,"context_line":"        provision_updated_at \u003d getattr(node, \u0027provision_updated_at\u0027, None)"},{"line_number":1934,"context_line":"        if provision_updated_at:"},{"line_number":1935,"context_line":"            try:"},{"line_number":1936,"context_line":"                now \u003d timeutils.utcnow()"},{"line_number":1937,"context_line":"                time_spent \u003d now - node.provision_updated_at"},{"line_number":1938,"context_line":"                duration \u003d int(time_spent.total_seconds())"},{"line_number":1939,"context_line":"            except Exception:"},{"line_number":1940,"context_line":"                # If something goes wrong with the calculation, we just log it"}],"source_content_type":"text/x-python","patch_set":2,"id":"3dd7af11_cb2ffed6","line":1937,"range":{"start_line":1936,"start_character":16,"end_line":1937,"end_character":60},"in_reply_to":"6d4706cf_67b8c588","updated":"2026-06-18 17:12:57.000000000","message":"Thank you for the feedback, Harald. I narrowed the scope down to catch TypeError only,keeping the logic strictly defensive as you suggested.","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"623866e53c76a8ef9d30bd170f49438210cccf91","unresolved":true,"context_lines":[{"line_number":1959,"context_line":"            target_provision_state\u003dnode.target_provision_state,"},{"line_number":1960,"context_line":"            # How many seconds we spent in the previous state"},{"line_number":1961,"context_line":"            # (if we could calculate it)"},{"line_number":1962,"context_line":"            duration_seconds\u003dduration"},{"line_number":1963,"context_line":"            ).create()"},{"line_number":1964,"context_line":""},{"line_number":1965,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"d0215c76_573e970d","line":1962,"updated":"2026-07-30 18:47:37.000000000","message":"So, I believe this will log transient issues or state changes since the last change. Consumers of this data might find it necessary to identify jumps in the value, for example if the node is rescued while deployed or serviced which will cause the value to reset, but I think there is a plus here in that it will log seconds since last change at all times and give a more linear sense to transitions. Others may have varying opinions there. I just highlight it because it might be","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"643b63d3e87bfdf1a2d79cf03b0cc1aee1177e4c","unresolved":true,"context_lines":[{"line_number":1953,"context_line":"            severity\u003derror and \"ERROR\" or \"INFO\","},{"line_number":1954,"context_line":"            event\u003devent,"},{"line_number":1955,"context_line":"            event_type\u003devent_type or \"UNKNOWN\","},{"line_number":1956,"context_line":"            # Track the node\u0027s provision state when this event happened"},{"line_number":1957,"context_line":"            state\u003dnode.provision_state,"},{"line_number":1958,"context_line":"            # Track what state we were trying to get to"},{"line_number":1959,"context_line":"            target_provision_state\u003dnode.target_provision_state,"},{"line_number":1960,"context_line":"            # How many seconds we spent in the previous state"},{"line_number":1961,"context_line":"            # (if we could calculate it)"},{"line_number":1962,"context_line":"            duration_seconds\u003dduration"},{"line_number":1963,"context_line":"            ).create()"},{"line_number":1964,"context_line":""},{"line_number":1965,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"7d733360_fc42ca6f","line":1962,"range":{"start_line":1956,"start_character":0,"end_line":1962,"end_character":37},"updated":"2026-06-18 12:20:31.000000000","message":"nit, I think we could reduce the comments a bit - the code is quite clear with good variable names.","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"},{"author":{"_account_id":38972,"name":"Esther Domfeh","display_name":"edomfeh","email":"estherdomfeh88@gmail.com","username":"edomfeh"},"change_message_id":"e2b123884e7951445ad1b7b196adb2efc83608b3","unresolved":false,"context_lines":[{"line_number":1953,"context_line":"            severity\u003derror and \"ERROR\" or \"INFO\","},{"line_number":1954,"context_line":"            event\u003devent,"},{"line_number":1955,"context_line":"            event_type\u003devent_type or \"UNKNOWN\","},{"line_number":1956,"context_line":"            # Track the node\u0027s provision state when this event happened"},{"line_number":1957,"context_line":"            state\u003dnode.provision_state,"},{"line_number":1958,"context_line":"            # Track what state we were trying to get to"},{"line_number":1959,"context_line":"            target_provision_state\u003dnode.target_provision_state,"},{"line_number":1960,"context_line":"            # How many seconds we spent in the previous state"},{"line_number":1961,"context_line":"            # (if we could calculate it)"},{"line_number":1962,"context_line":"            duration_seconds\u003dduration"},{"line_number":1963,"context_line":"            ).create()"},{"line_number":1964,"context_line":""},{"line_number":1965,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"34624f79_2fa8a33c","line":1962,"range":{"start_line":1956,"start_character":0,"end_line":1962,"end_character":37},"in_reply_to":"7d733360_fc42ca6f","updated":"2026-06-18 17:12:57.000000000","message":"Done","commit_id":"106df54b93f9969c3f162da37526138b7009ec99"}]}
