)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":14,"context_line":"send them, we need Cache-Control headers to prevent inadvertent caching"},{"line_number":15,"context_line":"of resources."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"This change adds a microversion 1.14 which adds the headers to GET"},{"line_number":18,"context_line":"requests and any PUT or POST requests that include response bodies."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"Despite what it says \u0027no-cache\u0027 means \"check to see if the version you"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"df87a7cf_4f5d1e13","line":17,"range":{"start_line":17,"start_character":34,"end_line":17,"end_character":36},"updated":"2017-12-11 17:33:37.000000000","message":"15","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":14,"context_line":"send them, we need Cache-Control headers to prevent inadvertent caching"},{"line_number":15,"context_line":"of resources."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"This change adds a microversion 1.14 which adds the headers to GET"},{"line_number":18,"context_line":"requests and any PUT or POST requests that include response bodies."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"Despite what it says \u0027no-cache\u0027 means \"check to see if the version you"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"df87a7cf_851f8706","line":17,"range":{"start_line":17,"start_character":34,"end_line":17,"end_character":36},"in_reply_to":"df87a7cf_4f5d1e13","updated":"2017-12-11 17:54:25.000000000","message":"Stuff like this that leads a man to dread microversions because soon enough it\u0027s going to be 16","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":31,"context_line":"* For collections, discover the max modified time when traversing the"},{"line_number":32,"context_line":"  list of objects to create the serialized JSON output. This is assisted"},{"line_number":33,"context_line":"  by a new util method: pick_last_modfied."},{"line_number":34,"context_line":"* For PUT and POST with bodies use the current time"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":"In typical placement framework fashion this has been done in a very"},{"line_number":37,"context_line":"explicit way, as it makes what the handler is doing very visible, even"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"df87a7cf_ea8c2037","line":34,"range":{"start_line":34,"start_character":2,"end_line":34,"end_character":51},"updated":"2017-12-11 17:33:37.000000000","message":"This isn\u0027t exactly true if I\u0027m looking at the code correctly, or is this statement just about collections? Looking at create inventory, it\u0027s returning the (updated_at or created_at) value of the inventory record that was just created.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":31,"context_line":"* For collections, discover the max modified time when traversing the"},{"line_number":32,"context_line":"  list of objects to create the serialized JSON output. This is assisted"},{"line_number":33,"context_line":"  by a new util method: pick_last_modfied."},{"line_number":34,"context_line":"* For PUT and POST with bodies use the current time"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":"In typical placement framework fashion this has been done in a very"},{"line_number":37,"context_line":"explicit way, as it makes what the handler is doing very visible, even"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"df87a7cf_a5dbab4c","line":34,"range":{"start_line":34,"start_character":2,"end_line":34,"end_character":51},"in_reply_to":"df87a7cf_ea8c2037","updated":"2017-12-11 17:54:25.000000000","message":"No, you\u0027re right. Another detail that got lost in the squash.\n\nWe don\u0027t often return a body on POST or PUT, so I think I just forgot when writing the commit message as it wasn\u0027t burned in my brain.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":41,"context_line":"calculations, the current time is used."},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"Because these changes add new headers (even though they don\u0027t do"},{"line_number":44,"context_line":"anything) a new microversion, 1.14, is added."},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"Partial-Bug: #1632852"},{"line_number":47,"context_line":"Partially-Implements: bp placement-cache-headers"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":8,"id":"df87a7cf_8fc32689","line":44,"range":{"start_line":44,"start_character":32,"end_line":44,"end_character":34},"updated":"2017-12-11 17:33:37.000000000","message":"15","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":31,"context_line":"* For collections, discover the max modified time when traversing the"},{"line_number":32,"context_line":"  list of objects to create the serialized JSON output. In most loops,"},{"line_number":33,"context_line":"  we only do that if we have a high enough microversion such that the"},{"line_number":34,"context_line":"  information will be used. This is not done when listing inventories"},{"line_number":35,"context_line":"  because the expectation is that no single resource provider will"},{"line_number":36,"context_line":"  ever have a huge number of inventory records."},{"line_number":37,"context_line":"* Both of the prior steps are assisted by a new util method:"},{"line_number":38,"context_line":"  pick_last_modfied."},{"line_number":39,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"df87a7cf_7f1f586b","line":36,"range":{"start_line":34,"start_character":28,"end_line":36,"end_character":47},"updated":"2017-12-12 15:36:37.000000000","message":"maybe I\u0027m missing something here, but I don\u0027t see how the fact that resource providers typically have few inventory records is relevant to whether the last modified timestamp for a return of GET /r_p/{uuid}/inventories should be set?\n\nAfter reading the code, it seems like perhaps you meant allocation candidates here and not inventories? Because you definitely include proper last modified date for inventories responses.","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"d765fad14fe4ac85e5d8ed53e963317d87624247","unresolved":false,"context_lines":[{"line_number":31,"context_line":"* For collections, discover the max modified time when traversing the"},{"line_number":32,"context_line":"  list of objects to create the serialized JSON output. In most loops,"},{"line_number":33,"context_line":"  we only do that if we have a high enough microversion such that the"},{"line_number":34,"context_line":"  information will be used. This is not done when listing inventories"},{"line_number":35,"context_line":"  because the expectation is that no single resource provider will"},{"line_number":36,"context_line":"  ever have a huge number of inventory records."},{"line_number":37,"context_line":"* Both of the prior steps are assisted by a new util method:"},{"line_number":38,"context_line":"  pick_last_modfied."},{"line_number":39,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"df87a7cf_d5b0c545","line":36,"range":{"start_line":34,"start_character":28,"end_line":36,"end_character":47},"in_reply_to":"df87a7cf_7f1f586b","updated":"2017-12-12 15:48:10.000000000","message":"I clarify this in the next version. The thing not done is the \"we only do that if we have a high enough microversion\" optimzation.","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":44,"context_line":"though it results in a bit of boilerplate."},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"For those requests that are created from multiple objects or by doing"},{"line_number":47,"context_line":"calculations, such as usages and aggregate associtions the current time"},{"line_number":48,"context_line":"is used."},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"The handler for PUT /traits is modified a bit more extensively than some"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"df87a7cf_b25c3719","line":47,"range":{"start_line":47,"start_character":43,"end_line":47,"end_character":54},"updated":"2017-12-12 15:36:37.000000000","message":"associations,","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"}],"nova/api/openstack/placement/handlers/aggregate.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":40,"context_line":"    response.content_type \u003d \u0027application/json\u0027"},{"line_number":41,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":42,"context_line":"        req.response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":43,"context_line":"        req.response.last_modified \u003d timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":44,"context_line":"    return response"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_0f0b96d5","line":43,"updated":"2017-12-11 17:33:37.000000000","message":"Note to reviewers:\n\nhttps://review.openstack.org/#/c/521639/6/nova/objects/resource_provider.py@420\n\nfor why this is utcnow().\n\nnit: we could replay that response in the review as a comment in the code here.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"}],"nova/api/openstack/placement/handlers/allocation.py":[{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"326bca421d4daab6a99e2f19ada3971759330b17","unresolved":false,"context_lines":[{"line_number":166,"context_line":"    # based off the created_at column because allocations are only"},{"line_number":167,"context_line":"    # ever inserted, never updated."},{"line_number":168,"context_line":"    last_modified \u003d None"},{"line_number":169,"context_line":"    for allocation in allocations:"},{"line_number":170,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, allocation)"},{"line_number":171,"context_line":"        key \u003d key_fetcher(allocation)"},{"line_number":172,"context_line":"        if \u0027resources\u0027 not in allocation_data[key]:"},{"line_number":173,"context_line":"            allocation_data[key][\u0027resources\u0027] \u003d {}"}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_8badb1ea","line":170,"range":{"start_line":169,"start_character":0,"end_line":170,"end_character":74},"updated":"2017-12-07 07:29:47.000000000","message":"Add a (unit or functional) test to check whether latest time of allocations is set to \u0027last_modified\u0027 or not.","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"49b12a2c11c6c3d9dc4d50ec5e3ac95c90241cca","unresolved":false,"context_lines":[{"line_number":166,"context_line":"    # based off the created_at column because allocations are only"},{"line_number":167,"context_line":"    # ever inserted, never updated."},{"line_number":168,"context_line":"    last_modified \u003d None"},{"line_number":169,"context_line":"    for allocation in allocations:"},{"line_number":170,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, allocation)"},{"line_number":171,"context_line":"        key \u003d key_fetcher(allocation)"},{"line_number":172,"context_line":"        if \u0027resources\u0027 not in allocation_data[key]:"},{"line_number":173,"context_line":"            allocation_data[key][\u0027resources\u0027] \u003d {}"}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_d3aa2b6f","line":170,"range":{"start_line":169,"start_character":0,"end_line":170,"end_character":74},"in_reply_to":"df87a7cf_651ad06f","updated":"2017-12-12 06:59:51.000000000","message":"\u003e do it in a follow up?\n\n+1","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b2661c2e74f3c5c03b72dbdeac08e6fb283663bc","unresolved":false,"context_lines":[{"line_number":166,"context_line":"    # based off the created_at column because allocations are only"},{"line_number":167,"context_line":"    # ever inserted, never updated."},{"line_number":168,"context_line":"    last_modified \u003d None"},{"line_number":169,"context_line":"    for allocation in allocations:"},{"line_number":170,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, allocation)"},{"line_number":171,"context_line":"        key \u003d key_fetcher(allocation)"},{"line_number":172,"context_line":"        if \u0027resources\u0027 not in allocation_data[key]:"},{"line_number":173,"context_line":"            allocation_data[key][\u0027resources\u0027] \u003d {}"}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_651ad06f","line":170,"range":{"start_line":169,"start_character":0,"end_line":170,"end_character":74},"in_reply_to":"df87a7cf_8badb1ea","updated":"2017-12-07 15:32:39.000000000","message":"The gabbits are asserting that a last-modified header is returned and it\u0027s a datetime format, and the utility code is tested. Testing the logic for each handler might seem excessive but I can see value in it for the sake of avoiding regressions if this code changes in the future. Since each handler could be returning a last-modified based on created_at, updated_at, the max in a collection or utcnow(), I can see how we might want some test coverage to make sure that each handler is doing the proper thing for the type of resources it returns, but I wouldn\u0027t block on it - maybe do it in a follow up?","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"326bca421d4daab6a99e2f19ada3971759330b17","unresolved":false,"context_lines":[{"line_number":189,"context_line":"            result[\u0027project_id\u0027] \u003d allocations[0].project_id"},{"line_number":190,"context_line":"            result[\u0027user_id\u0027] \u003d allocations[0].user_id"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"    last_modified \u003d last_modified or timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":193,"context_line":"    return result, last_modified"},{"line_number":194,"context_line":""},{"line_number":195,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_eb06bdce","line":192,"range":{"start_line":192,"start_character":4,"end_line":192,"end_character":73},"updated":"2017-12-07 07:29:47.000000000","message":"If there is no allocations, it is current time.\nIf there is allocations, it is latest time (created or updated) in allocations.\nIt should be tested in unit or functional tests.","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":167,"context_line":"    # ever inserted, never updated."},{"line_number":168,"context_line":"    last_modified \u003d None"},{"line_number":169,"context_line":"    for allocation in allocations:"},{"line_number":170,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, allocation)"},{"line_number":171,"context_line":"        key \u003d key_fetcher(allocation)"},{"line_number":172,"context_line":"        if \u0027resources\u0027 not in allocation_data[key]:"},{"line_number":173,"context_line":"            allocation_data[key][\u0027resources\u0027] \u003d {}"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_ef8c3237","line":170,"updated":"2017-12-11 17:33:37.000000000","message":"Thinking out loud, I know this would be gross, but we could check want_version to see if we even need to calculate last_modified at all - that\u0027s semi-gross tight coupling and arguably not any noticeable performance impact though, but figured I\u0027d mention it. The number of allocation records per resource provider shouldn\u0027t be so big we\u0027d notice a major difference. The last_modified calculation on a list of resource providers, on the other hand, might be considerable if you have 100K compute nodes.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"134829d753ac117d4f7206439682b6fdbe9c5f75","unresolved":false,"context_lines":[{"line_number":167,"context_line":"    # ever inserted, never updated."},{"line_number":168,"context_line":"    last_modified \u003d None"},{"line_number":169,"context_line":"    for allocation in allocations:"},{"line_number":170,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, allocation)"},{"line_number":171,"context_line":"        key \u003d key_fetcher(allocation)"},{"line_number":172,"context_line":"        if \u0027resources\u0027 not in allocation_data[key]:"},{"line_number":173,"context_line":"            allocation_data[key][\u0027resources\u0027] \u003d {}"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_5f53876b","line":170,"in_reply_to":"df87a7cf_a582cbfe","updated":"2017-12-11 22:19:48.000000000","message":"\u003e non-solution for clients that are behaving in a modern fashion.\n\nI\u0027m not sure what that means. Oh, I guess by \"modern\" you mean always asking for the latest available max microversion, which at this point nova is already requesting 1.14.\n\nI was thinking non-nova external clients, and until we have paging support in some of the bigger APIs like GET /traits and GET /resource_providers we probably have to optimize a bit for some of the APIs.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":167,"context_line":"    # ever inserted, never updated."},{"line_number":168,"context_line":"    last_modified \u003d None"},{"line_number":169,"context_line":"    for allocation in allocations:"},{"line_number":170,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, allocation)"},{"line_number":171,"context_line":"        key \u003d key_fetcher(allocation)"},{"line_number":172,"context_line":"        if \u0027resources\u0027 not in allocation_data[key]:"},{"line_number":173,"context_line":"            allocation_data[key][\u0027resources\u0027] \u003d {}"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_a582cbfe","line":170,"in_reply_to":"df87a7cf_ef8c3237","updated":"2017-12-11 17:54:25.000000000","message":"I considered that but it felt like an early optimization and a non-solution for clients that are behaving in a modern fashion.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"}],"nova/api/openstack/placement/handlers/inventory.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":185,"context_line":"    response.content_type \u003d \u0027application/json\u0027"},{"line_number":186,"context_line":"    want_version \u003d req.environ[microversion.MICROVERSION_ENVIRON]"},{"line_number":187,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":188,"context_line":"        modified \u003d inventory.updated_at or inventory.created_at"},{"line_number":189,"context_line":"        response.last_modified \u003d modified"},{"line_number":190,"context_line":"        response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":191,"context_line":"    return response"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_8fafa628","line":188,"range":{"start_line":188,"start_character":19,"end_line":188,"end_character":63},"updated":"2017-12-11 17:33:37.000000000","message":"Why not use your utility method here?","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":185,"context_line":"    response.content_type \u003d \u0027application/json\u0027"},{"line_number":186,"context_line":"    want_version \u003d req.environ[microversion.MICROVERSION_ENVIRON]"},{"line_number":187,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":188,"context_line":"        modified \u003d inventory.updated_at or inventory.created_at"},{"line_number":189,"context_line":"        response.last_modified \u003d modified"},{"line_number":190,"context_line":"        response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":191,"context_line":"    return response"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_0595b732","line":188,"range":{"start_line":188,"start_character":19,"end_line":188,"end_character":63},"in_reply_to":"df87a7cf_8fafa628","updated":"2017-12-11 17:54:25.000000000","message":"oversight or laziness probably, I had a mental model of it only being used in loops, but that doesn\u0027t have to be the case","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":213,"context_line":"        inventories_dict[resource_class] \u003d _serialize_inventory("},{"line_number":214,"context_line":"            inventory, generation\u003dNone)"},{"line_number":215,"context_line":"    return ({\u0027resource_provider_generation\u0027: generation,"},{"line_number":216,"context_line":"            \u0027inventories\u0027: inventories_dict}, last_modified)"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"@wsgi_wrapper.PlacementWsgify"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_4ff75e5a","line":216,"updated":"2017-12-11 17:33:37.000000000","message":"nit: alignment on the dict entries","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":213,"context_line":"        inventories_dict[resource_class] \u003d _serialize_inventory("},{"line_number":214,"context_line":"            inventory, generation\u003dNone)"},{"line_number":215,"context_line":"    return ({\u0027resource_provider_generation\u0027: generation,"},{"line_number":216,"context_line":"            \u0027inventories\u0027: inventories_dict}, last_modified)"},{"line_number":217,"context_line":""},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"@wsgi_wrapper.PlacementWsgify"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_a5b08bde","line":216,"in_reply_to":"df87a7cf_4ff75e5a","updated":"2017-12-11 17:54:25.000000000","message":"sigh, why isn\u0027t pep8 catching this anymore, didn\u0027t it used to?","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"}],"nova/api/openstack/placement/handlers/resource_class.py":[{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"326bca421d4daab6a99e2f19ada3971759330b17","unresolved":false,"context_lines":[{"line_number":60,"context_line":"def _serialize_resource_classes(environ, rcs):"},{"line_number":61,"context_line":"    output \u003d []"},{"line_number":62,"context_line":"    last_modified \u003d None"},{"line_number":63,"context_line":"    for rc in rcs:"},{"line_number":64,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, rc)"},{"line_number":65,"context_line":"        data \u003d _serialize_resource_class(environ, rc)"},{"line_number":66,"context_line":"        output.append(data)"},{"line_number":67,"context_line":"    last_modified \u003d last_modified or timeutils.utcnow(with_timezone\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_abf0b5fe","line":64,"range":{"start_line":63,"start_character":0,"end_line":64,"end_character":66},"updated":"2017-12-07 07:29:47.000000000","message":"ditto","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"326bca421d4daab6a99e2f19ada3971759330b17","unresolved":false,"context_lines":[{"line_number":64,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, rc)"},{"line_number":65,"context_line":"        data \u003d _serialize_resource_class(environ, rc)"},{"line_number":66,"context_line":"        output.append(data)"},{"line_number":67,"context_line":"    last_modified \u003d last_modified or timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":68,"context_line":"    return ({\"resource_classes\": output}, last_modified)"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_cb2ad92a","line":67,"range":{"start_line":67,"start_character":4,"end_line":67,"end_character":73},"updated":"2017-12-07 07:29:47.000000000","message":"ditto","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":145,"context_line":"    req.response.content_type \u003d \u0027application/json\u0027"},{"line_number":146,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":147,"context_line":"        req.response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":148,"context_line":"        last_modified \u003d rc.updated_at or rc.created_at or timeutils.utcnow("},{"line_number":149,"context_line":"            with_timezone\u003dTrue)"},{"line_number":150,"context_line":"        req.response.last_modified \u003d last_modified"},{"line_number":151,"context_line":"    return req.response"},{"line_number":152,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_aafe1868","line":149,"range":{"start_line":148,"start_character":24,"end_line":149,"end_character":31},"updated":"2017-12-11 17:33:37.000000000","message":"Why not use your utility?","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"1efaf6b714304256ed8bd9b3b53afbb1a47f0e00","unresolved":false,"context_lines":[{"line_number":145,"context_line":"    req.response.content_type \u003d \u0027application/json\u0027"},{"line_number":146,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":147,"context_line":"        req.response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":148,"context_line":"        last_modified \u003d rc.updated_at or rc.created_at or timeutils.utcnow("},{"line_number":149,"context_line":"            with_timezone\u003dTrue)"},{"line_number":150,"context_line":"        req.response.last_modified \u003d last_modified"},{"line_number":151,"context_line":"    return req.response"},{"line_number":152,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_a8085f91","line":149,"range":{"start_line":148,"start_character":24,"end_line":149,"end_character":31},"in_reply_to":"df87a7cf_050cd7a2","updated":"2017-12-11 18:59:26.000000000","message":"Actually this one is a special cases because of the way resource classes are strange. The util will never see NotImplemented for a non-custom resource classes for we can use the util but we still need the or","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":145,"context_line":"    req.response.content_type \u003d \u0027application/json\u0027"},{"line_number":146,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":147,"context_line":"        req.response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":148,"context_line":"        last_modified \u003d rc.updated_at or rc.created_at or timeutils.utcnow("},{"line_number":149,"context_line":"            with_timezone\u003dTrue)"},{"line_number":150,"context_line":"        req.response.last_modified \u003d last_modified"},{"line_number":151,"context_line":"    return req.response"},{"line_number":152,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_050cd7a2","line":149,"range":{"start_line":148,"start_character":24,"end_line":149,"end_character":31},"in_reply_to":"df87a7cf_aafe1868","updated":"2017-12-11 17:54:25.000000000","message":"see prior about loop brain lock","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":204,"context_line":"            _(\u0027Cannot update standard resource class %(rp_name)s\u0027) %"},{"line_number":205,"context_line":"            {\u0027rp_name\u0027: name})"},{"line_number":206,"context_line":""},{"line_number":207,"context_line":"    req.response.body \u003d encodeutils.to_utf8(jsonutils.dumps("},{"line_number":208,"context_line":"        _serialize_resource_class(req.environ, rc))"},{"line_number":209,"context_line":"    )"},{"line_number":210,"context_line":"    req.response.status \u003d 200"},{"line_number":211,"context_line":"    req.response.content_type \u003d \u0027application/json\u0027"},{"line_number":212,"context_line":"    return req.response"},{"line_number":213,"context_line":""},{"line_number":214,"context_line":""},{"line_number":215,"context_line":"@wsgi_wrapper.PlacementWsgify  # noqa"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_2ad9a820","line":212,"range":{"start_line":207,"start_character":4,"end_line":212,"end_character":23},"updated":"2017-12-11 17:33:37.000000000","message":"What about this?","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":204,"context_line":"            _(\u0027Cannot update standard resource class %(rp_name)s\u0027) %"},{"line_number":205,"context_line":"            {\u0027rp_name\u0027: name})"},{"line_number":206,"context_line":""},{"line_number":207,"context_line":"    req.response.body \u003d encodeutils.to_utf8(jsonutils.dumps("},{"line_number":208,"context_line":"        _serialize_resource_class(req.environ, rc))"},{"line_number":209,"context_line":"    )"},{"line_number":210,"context_line":"    req.response.status \u003d 200"},{"line_number":211,"context_line":"    req.response.content_type \u003d \u0027application/json\u0027"},{"line_number":212,"context_line":"    return req.response"},{"line_number":213,"context_line":""},{"line_number":214,"context_line":""},{"line_number":215,"context_line":"@wsgi_wrapper.PlacementWsgify  # noqa"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_25479bbe","line":212,"range":{"start_line":207,"start_character":4,"end_line":212,"end_character":23},"in_reply_to":"df87a7cf_2ad9a820","updated":"2017-12-11 17:54:25.000000000","message":"This handler is microversion 1.2 to 1.6 only.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"}],"nova/api/openstack/placement/handlers/resource_provider.py":[{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"326bca421d4daab6a99e2f19ada3971759330b17","unresolved":false,"context_lines":[{"line_number":111,"context_line":"def _serialize_providers(environ, resource_providers):"},{"line_number":112,"context_line":"    output \u003d []"},{"line_number":113,"context_line":"    last_modified \u003d None"},{"line_number":114,"context_line":"    for provider in resource_providers:"},{"line_number":115,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, provider)"},{"line_number":116,"context_line":"        provider_data \u003d _serialize_provider(environ, provider)"},{"line_number":117,"context_line":"        output.append(provider_data)"},{"line_number":118,"context_line":"    last_modified \u003d last_modified or timeutils.utcnow(with_timezone\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_cbf5f9ee","line":115,"range":{"start_line":114,"start_character":0,"end_line":115,"end_character":72},"updated":"2017-12-07 07:29:47.000000000","message":"ditto","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"326bca421d4daab6a99e2f19ada3971759330b17","unresolved":false,"context_lines":[{"line_number":115,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, provider)"},{"line_number":116,"context_line":"        provider_data \u003d _serialize_provider(environ, provider)"},{"line_number":117,"context_line":"        output.append(provider_data)"},{"line_number":118,"context_line":"    last_modified \u003d last_modified or timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":119,"context_line":"    return ({\"resource_providers\": output}, last_modified)"},{"line_number":120,"context_line":""},{"line_number":121,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_8b20514a","line":118,"range":{"start_line":118,"start_character":4,"end_line":118,"end_character":73},"updated":"2017-12-07 07:29:47.000000000","message":"ditto","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":139,"context_line":"    return data"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":""},{"line_number":142,"context_line":"def _serialize_providers(environ, resource_providers, want_version):"},{"line_number":143,"context_line":"    output \u003d []"},{"line_number":144,"context_line":"    last_modified \u003d None"},{"line_number":145,"context_line":"    for provider in resource_providers:"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_8a53146b","line":142,"updated":"2017-12-11 17:33:37.000000000","message":"I mentioned this in the allocations handler, but I could see a case for checking up front if we care about last_modified here, in the case that we\u0027re returning potentially tens of thousands of records, calculating the max last modified for all of them would be a waste if we are just going to throw away the value. Could we check for 1.15 in here and not call pick_last_modified if we\u0027re \u003c 1.15? Or do it in the method that\u0027s calling this method and pass in a boolean?","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":139,"context_line":"    return data"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":""},{"line_number":142,"context_line":"def _serialize_providers(environ, resource_providers, want_version):"},{"line_number":143,"context_line":"    output \u003d []"},{"line_number":144,"context_line":"    last_modified \u003d None"},{"line_number":145,"context_line":"    for provider in resource_providers:"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_652a83db","line":142,"in_reply_to":"df87a7cf_8a53146b","updated":"2017-12-11 17:54:25.000000000","message":"since we have want_version anyway, may as well be a matches here","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":236,"context_line":"        _serialize_provider(req.environ, resource_provider, want_version)))"},{"line_number":237,"context_line":"    response.content_type \u003d \u0027application/json\u0027"},{"line_number":238,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":239,"context_line":"        modified \u003d resource_provider.updated_at or resource_provider.created_at"},{"line_number":240,"context_line":"        response.last_modified \u003d modified"},{"line_number":241,"context_line":"        response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":242,"context_line":"    return response"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_2520fbf6","line":239,"updated":"2017-12-11 17:54:25.000000000","message":"note to self, use the util","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":350,"context_line":"        _serialize_provider(req.environ, resource_provider, want_version)))"},{"line_number":351,"context_line":"    response.content_type \u003d \u0027application/json\u0027"},{"line_number":352,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":353,"context_line":"        response.last_modified \u003d timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":354,"context_line":"        response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":355,"context_line":"    return response"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_aa0cd893","line":353,"updated":"2017-12-11 17:33:37.000000000","message":"Why wouldn\u0027t this be updated_at since we just updated the resource provider?","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":350,"context_line":"        _serialize_provider(req.environ, resource_provider, want_version)))"},{"line_number":351,"context_line":"    response.content_type \u003d \u0027application/json\u0027"},{"line_number":352,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":353,"context_line":"        response.last_modified \u003d timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":354,"context_line":"        response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":355,"context_line":"    return response"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_8553076b","line":353,"in_reply_to":"df87a7cf_aa0cd893","updated":"2017-12-11 17:54:25.000000000","message":"Could be","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"}],"nova/api/openstack/placement/handlers/trait.py":[{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"326bca421d4daab6a99e2f19ada3971759330b17","unresolved":false,"context_lines":[{"line_number":89,"context_line":"def _serialize_traits(traits):"},{"line_number":90,"context_line":"    last_modified \u003d None"},{"line_number":91,"context_line":"    trait_names \u003d []"},{"line_number":92,"context_line":"    for trait in traits:"},{"line_number":93,"context_line":"        last_modified \u003d util.pick_last_modified(last_modified, trait)"},{"line_number":94,"context_line":"        trait_names.append(trait.name)"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    # If there were no traits, set last_modified to now"}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_8bdb717a","line":93,"range":{"start_line":92,"start_character":0,"end_line":93,"end_character":69},"updated":"2017-12-07 07:29:47.000000000","message":"ditto","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":7634,"name":"Takashi Natsume","email":"takanattie@gmail.com","username":"natsumet"},"change_message_id":"326bca421d4daab6a99e2f19ada3971759330b17","unresolved":false,"context_lines":[{"line_number":94,"context_line":"        trait_names.append(trait.name)"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":"    # If there were no traits, set last_modified to now"},{"line_number":97,"context_line":"    last_modified \u003d last_modified or timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    return {\u0027traits\u0027: trait_names}, last_modified"},{"line_number":100,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"df87a7cf_2b190521","line":97,"range":{"start_line":97,"start_character":4,"end_line":97,"end_character":73},"updated":"2017-12-07 07:29:47.000000000","message":"ditto","commit_id":"a7602ce95323cafdf1aa1db19238e9f7f4965b07"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":86,"context_line":"    return filters"},{"line_number":87,"context_line":""},{"line_number":88,"context_line":""},{"line_number":89,"context_line":"def _serialize_traits(traits):"},{"line_number":90,"context_line":"    last_modified \u003d None"},{"line_number":91,"context_line":"    trait_names \u003d []"},{"line_number":92,"context_line":"    for trait in traits:"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_ca47dc76","line":89,"updated":"2017-12-11 17:33:37.000000000","message":"This is another one that could be pretty large if we don\u0027t actually care about last_modified, at least in the \"GET /traits\" call.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":122,"context_line":"    except exception.TraitExists:"},{"line_number":123,"context_line":"        req.response.status \u003d 204"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"    req.response.content_type \u003d None"},{"line_number":126,"context_line":"    req.response.location \u003d util.trait_url(req.environ, trait)"},{"line_number":127,"context_line":"    return req.response"},{"line_number":128,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_0a2064ab","line":125,"updated":"2017-12-11 17:33:37.000000000","message":"Why wouldn\u0027t we return last_modified\u003dcreated_at like in get_trait below? If the answer is, \"because we don\u0027t return a body here\" then that should be true for get_trait also.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"134829d753ac117d4f7206439682b6fdbe9c5f75","unresolved":false,"context_lines":[{"line_number":122,"context_line":"    except exception.TraitExists:"},{"line_number":123,"context_line":"        req.response.status \u003d 204"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"    req.response.content_type \u003d None"},{"line_number":126,"context_line":"    req.response.location \u003d util.trait_url(req.environ, trait)"},{"line_number":127,"context_line":"    return req.response"},{"line_number":128,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_9f3cafe1","line":125,"in_reply_to":"df87a7cf_05c4d7f3","updated":"2017-12-11 22:19:48.000000000","message":"If we omit it I think we need a comment saying that omission is intentional so someone doesn\u0027t come along later wondering the same thing.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":122,"context_line":"    except exception.TraitExists:"},{"line_number":123,"context_line":"        req.response.status \u003d 204"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"    req.response.content_type \u003d None"},{"line_number":126,"context_line":"    req.response.location \u003d util.trait_url(req.environ, trait)"},{"line_number":127,"context_line":"    return req.response"},{"line_number":128,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_05c4d7f3","line":125,"in_reply_to":"df87a7cf_0a2064ab","updated":"2017-12-11 17:54:25.000000000","message":"Yes, the general rule would be \"no body, no time\" but in the GET case, the last-modified is a useful bit of information that we know for sure and doesn\u0027t have any ambiguity. In this case, the PUT is either creating or confirming the existence of something so I wasn\u0027t sure. So I punted. If you\u0027d like one, no problem to add.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"304ee7fffd1eb581100dd22e58bcc3d1bbc4c4f8","unresolved":false,"context_lines":[{"line_number":88,"context_line":""},{"line_number":89,"context_line":"def _serialize_traits(traits, want_version):"},{"line_number":90,"context_line":"    last_modified \u003d None"},{"line_number":91,"context_line":"    get_last_modified \u003d want_version.matches((1, 15))"},{"line_number":92,"context_line":"    trait_names \u003d []"},{"line_number":93,"context_line":"    for trait in traits:"},{"line_number":94,"context_line":"        if get_last_modified:"}],"source_content_type":"text/x-python","patch_set":9,"id":"df87a7cf_da524513","line":91,"range":{"start_line":91,"start_character":24,"end_line":91,"end_character":36},"updated":"2017-12-11 22:31:23.000000000","message":"nit: should probably be safe and check that want_version is provided like in some of the other _serialize* methods.","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"6bf431222c0875e649f38c015e1a17da3942eaaf","unresolved":false,"context_lines":[{"line_number":88,"context_line":""},{"line_number":89,"context_line":"def _serialize_traits(traits, want_version):"},{"line_number":90,"context_line":"    last_modified \u003d None"},{"line_number":91,"context_line":"    get_last_modified \u003d want_version.matches((1, 15))"},{"line_number":92,"context_line":"    trait_names \u003d []"},{"line_number":93,"context_line":"    for trait in traits:"},{"line_number":94,"context_line":"        if get_last_modified:"}],"source_content_type":"text/x-python","patch_set":9,"id":"df87a7cf_2ef692d8","line":91,"range":{"start_line":91,"start_character":24,"end_line":91,"end_character":36},"in_reply_to":"df87a7cf_da524513","updated":"2017-12-11 23:04:04.000000000","message":"at least one those where it checks it was kwarg that can be None, the rest of it a required parameter and the tests will blow up if past something that\u0027s not a microversion.","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"}],"nova/api/openstack/placement/handlers/usage.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":89,"context_line":"    req.response.content_type \u003d \u0027application/json\u0027"},{"line_number":90,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":91,"context_line":"        req.response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":92,"context_line":"        req.response.last_modified \u003d timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":93,"context_line":"    return req.response"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_e578d390","line":92,"updated":"2017-12-11 17:33:37.000000000","message":"Note to other reviewers:\n\nhttps://review.openstack.org/#/c/521639/6/nova/objects/resource_provider.py@2172\n\nnit: could be worth a comment here on why we use utcnow for usages.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":89,"context_line":"    req.response.content_type \u003d \u0027application/json\u0027"},{"line_number":90,"context_line":"    if want_version.matches((1, 15)):"},{"line_number":91,"context_line":"        req.response.cache_control \u003d \u0027no-cache\u0027"},{"line_number":92,"context_line":"        req.response.last_modified \u003d timeutils.utcnow(with_timezone\u003dTrue)"},{"line_number":93,"context_line":"    return req.response"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_257f9bab","line":92,"in_reply_to":"df87a7cf_e578d390","updated":"2017-12-11 17:54:25.000000000","message":"ack","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"}],"nova/api/openstack/placement/util.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":126,"context_line":""},{"line_number":127,"context_line":""},{"line_number":128,"context_line":"def pick_last_modified(last_modified, obj):"},{"line_number":129,"context_line":"    \"\"\"Choose max of last_modified and obj.updated_at or obj.created_at.\"\"\""},{"line_number":130,"context_line":"    try:"},{"line_number":131,"context_line":"        current_modified \u003d (obj.updated_at or obj.created_at)"},{"line_number":132,"context_line":"    except NotImplementedError:"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_4feafed7","line":129,"updated":"2017-12-11 17:33:37.000000000","message":"nit: should probably mention in the docstring that if we can\u0027t determine either, utcnow() is consider the last_modified.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"826667e8d7942b3e4a3aee87f9225e23749883cc","unresolved":false,"context_lines":[{"line_number":126,"context_line":""},{"line_number":127,"context_line":""},{"line_number":128,"context_line":"def pick_last_modified(last_modified, obj):"},{"line_number":129,"context_line":"    \"\"\"Choose max of last_modified and obj.updated_at or obj.created_at.\"\"\""},{"line_number":130,"context_line":"    try:"},{"line_number":131,"context_line":"        current_modified \u003d (obj.updated_at or obj.created_at)"},{"line_number":132,"context_line":"    except NotImplementedError:"}],"source_content_type":"text/x-python","patch_set":8,"id":"df87a7cf_855d4748","line":129,"in_reply_to":"df87a7cf_4feafed7","updated":"2017-12-11 17:54:25.000000000","message":"ack","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":132,"context_line":"    \"\"\""},{"line_number":133,"context_line":"    try:"},{"line_number":134,"context_line":"        current_modified \u003d (obj.updated_at or obj.created_at)"},{"line_number":135,"context_line":"    except NotImplementedError:"},{"line_number":136,"context_line":"        # If updated_at is not implemented, we are looking at objects that"},{"line_number":137,"context_line":"        # have not come from the database, so \"now\" is the right modified"},{"line_number":138,"context_line":"        # time."}],"source_content_type":"text/x-python","patch_set":9,"id":"df87a7cf_b27997c5","line":135,"range":{"start_line":135,"start_character":11,"end_line":135,"end_character":30},"updated":"2017-12-12 15:36:37.000000000","message":"Couldn\u0027t this also be AttributeError if obj simply doesn\u0027t have either an updated_at or created_at attribute?","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"d765fad14fe4ac85e5d8ed53e963317d87624247","unresolved":false,"context_lines":[{"line_number":132,"context_line":"    \"\"\""},{"line_number":133,"context_line":"    try:"},{"line_number":134,"context_line":"        current_modified \u003d (obj.updated_at or obj.created_at)"},{"line_number":135,"context_line":"    except NotImplementedError:"},{"line_number":136,"context_line":"        # If updated_at is not implemented, we are looking at objects that"},{"line_number":137,"context_line":"        # have not come from the database, so \"now\" is the right modified"},{"line_number":138,"context_line":"        # time."}],"source_content_type":"text/x-python","patch_set":9,"id":"df87a7cf_b54d013c","line":135,"range":{"start_line":135,"start_character":11,"end_line":135,"end_character":30},"in_reply_to":"df87a7cf_b27997c5","updated":"2017-12-12 15:48:10.000000000","message":"Not that I could discern. We always have the same version of an object (since we\u0027re not versioning) and all the objects that are being passed into this have the fields (and when it is not set NotImplementedError happens).\n\nOr are you saying: \"be defensive in the face of someone passing in an object that doesn\u0027t have the fields\". For example, in case someone decides to passing in an AllocationCandidates (which doesn\u0027t have the fields).\n\nIn that case, we _do_ want to AttributeError to raise, at test time, so that a person knows early (pre-commit) that they\u0027ve written bad code.","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"}],"nova/tests/functional/api/openstack/placement/gabbits/aggregate.yaml":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":125,"context_line":"  response_json_paths:"},{"line_number":126,"context_line":"      $.errors[0].title: Bad Request"},{"line_number":127,"context_line":""},{"line_number":128,"context_line":"# The next two tests confirm that prior to version 1.14 we do"},{"line_number":129,"context_line":"# not set the cache-control or last-modified headers on either"},{"line_number":130,"context_line":"# PUT or GET."},{"line_number":131,"context_line":""}],"source_content_type":"text/x-yaml","patch_set":9,"id":"df87a7cf_323ca7df","line":128,"range":{"start_line":128,"start_character":53,"end_line":128,"end_character":55},"updated":"2017-12-12 15:36:37.000000000","message":"should be 1.15","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":129,"context_line":"# not set the cache-control or last-modified headers on either"},{"line_number":130,"context_line":"# PUT or GET."},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"- name: put some aggregates v1.13"},{"line_number":133,"context_line":"  PUT: $LAST_URL"},{"line_number":134,"context_line":"  request_headers:"},{"line_number":135,"context_line":"      openstack-api-version: placement 1.13"}],"source_content_type":"text/x-yaml","patch_set":9,"id":"df87a7cf_d2269bce","line":132,"range":{"start_line":132,"start_character":31,"end_line":132,"end_character":33},"updated":"2017-12-12 15:36:37.000000000","message":"should be 1.14","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":132,"context_line":"- name: put some aggregates v1.13"},{"line_number":133,"context_line":"  PUT: $LAST_URL"},{"line_number":134,"context_line":"  request_headers:"},{"line_number":135,"context_line":"      openstack-api-version: placement 1.13"},{"line_number":136,"context_line":"  data:"},{"line_number":137,"context_line":"      - *agg_1"},{"line_number":138,"context_line":"      - *agg_2"}],"source_content_type":"text/x-yaml","patch_set":9,"id":"df87a7cf_922c93ac","line":135,"range":{"start_line":135,"start_character":41,"end_line":135,"end_character":43},"updated":"2017-12-12 15:36:37.000000000","message":"14","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":140,"context_line":"      - last-modified"},{"line_number":141,"context_line":"      - cache-control"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"- name: get those aggregates v1.13"},{"line_number":144,"context_line":"  GET: $LAST_URL"},{"line_number":145,"context_line":"  request_headers:"},{"line_number":146,"context_line":"      openstack-api-version: placement 1.13"}],"source_content_type":"text/x-yaml","patch_set":9,"id":"df87a7cf_b22757c7","line":143,"range":{"start_line":143,"start_character":32,"end_line":143,"end_character":34},"updated":"2017-12-12 15:36:37.000000000","message":"14","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":143,"context_line":"- name: get those aggregates v1.13"},{"line_number":144,"context_line":"  GET: $LAST_URL"},{"line_number":145,"context_line":"  request_headers:"},{"line_number":146,"context_line":"      openstack-api-version: placement 1.13"},{"line_number":147,"context_line":"  response_forbidden_headers:"},{"line_number":148,"context_line":"      - last-modified"},{"line_number":149,"context_line":"      - cache-control"}],"source_content_type":"text/x-yaml","patch_set":9,"id":"df87a7cf_521ccb76","line":146,"range":{"start_line":146,"start_character":41,"end_line":146,"end_character":43},"updated":"2017-12-12 15:36:37.000000000","message":"14","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"}],"nova/tests/functional/api/openstack/placement/gabbits/inventory.yaml":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":182,"context_line":"      $.step_size: 10"},{"line_number":183,"context_line":"      $.allocation_ratio: 1.0"},{"line_number":184,"context_line":""},{"line_number":185,"context_line":"- name: get inventory v1.13 no cache headers"},{"line_number":186,"context_line":"  GET: $LAST_URL"},{"line_number":187,"context_line":"  status: 200"},{"line_number":188,"context_line":"  request_headers:"}],"source_content_type":"text/x-yaml","patch_set":9,"id":"df87a7cf_b200b703","line":185,"range":{"start_line":185,"start_character":25,"end_line":185,"end_character":27},"updated":"2017-12-12 15:36:37.000000000","message":"14","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2c00ac76b2faf366679891d2e6f105f0d8222b5c","unresolved":false,"context_lines":[{"line_number":186,"context_line":"  GET: $LAST_URL"},{"line_number":187,"context_line":"  status: 200"},{"line_number":188,"context_line":"  request_headers:"},{"line_number":189,"context_line":"      openstack-api-version: placement 1.13"},{"line_number":190,"context_line":"  response_forbidden_headers:"},{"line_number":191,"context_line":"      - cache-control"},{"line_number":192,"context_line":"      - last-modified"}],"source_content_type":"text/x-yaml","patch_set":9,"id":"df87a7cf_55011504","line":189,"range":{"start_line":189,"start_character":41,"end_line":189,"end_character":43},"updated":"2017-12-12 15:36:37.000000000","message":"14","commit_id":"18f478523a52de920972b6de2ec3852fd0cc22d5"}],"releasenotes/notes/placement-last-modified-cf43aece4c54fc97.yaml":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ce3ca40f1b40ee28cd2ba151765c6eabb8d947ae","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"      Throughout the API, in microversion 1.15, \u0027last-modified\u0027 headers have"},{"line_number":5,"context_line":"      been added to GET responses and those PUT and POST responses that have"},{"line_number":6,"context_line":"      bodies. The value is either the actual last modified time of the most"},{"line_number":7,"context_line":"      recently modified associated database entity or the current time if"}],"source_content_type":"text/x-yaml","patch_set":8,"id":"df87a7cf_85ac67ed","line":4,"range":{"start_line":4,"start_character":4,"end_line":4,"end_character":6},"updated":"2017-12-11 17:33:37.000000000","message":"This is weird. Should align with the pipe. Although it makes no difference in how the release note is actually rendered.","commit_id":"44d629c708efb84b94be8dc3f749d1aa0482cefd"}]}
