)]}'
{"nova/api/openstack/placement/errors.py":[{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"fe8cfea0c138ce15a08619da394e4a932886b4b6","unresolved":false,"context_lines":[{"line_number":44,"context_line":"RESOURCES_REQUIRED_IN_REQUEST_GROUP \u003d ("},{"line_number":45,"context_line":"    \u0027placement.allocation_candidates.resources_required_in_request_group\u0027)"},{"line_number":46,"context_line":"AT_LEAST_ONE_REQUEST_GROUP_REQUIRED \u003d ("},{"line_number":47,"context_line":"    \u0027placement.allocation_candidates.at_least_one_request_group_required\u0027)"}],"source_content_type":"text/x-python","patch_set":25,"id":"9f6a8fd7_5a185183","line":47,"updated":"2018-04-26 12:04:09.000000000","message":"These seem long to me. They are supposed to be codes that enable looking things up elsewhere and distinguishing different errors, not repeated error messages.","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":44,"context_line":"RESOURCES_REQUIRED_IN_REQUEST_GROUP \u003d ("},{"line_number":45,"context_line":"    \u0027placement.allocation_candidates.resources_required_in_request_group\u0027)"},{"line_number":46,"context_line":"AT_LEAST_ONE_REQUEST_GROUP_REQUIRED \u003d ("},{"line_number":47,"context_line":"    \u0027placement.allocation_candidates.at_least_one_request_group_required\u0027)"}],"source_content_type":"text/x-python","patch_set":25,"id":"5f7c97a3_7d82d951","line":47,"in_reply_to":"9f6a8fd7_51f6f4fb","updated":"2018-05-04 14:48:31.000000000","message":"\u003e The point\n \u003e of the error codes was to allow machine-switchable behaviour based\n \u003e on some event.\n\nor to facilitate debugging, in cases of duplicated exceptions / error text?\n\nChris said the API guidelines indicate we should strive for unique error codes for every API error.  But even he was meh on whether this class of error warrants them.\n\nI\u0027m not interested in blocking this series while we haggle about it.  I\u0027ll just remove the error codes for now and we can work on it separately.","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0558995f5d9452d3d1d044cd15dde687fd7d2777","unresolved":false,"context_lines":[{"line_number":44,"context_line":"RESOURCES_REQUIRED_IN_REQUEST_GROUP \u003d ("},{"line_number":45,"context_line":"    \u0027placement.allocation_candidates.resources_required_in_request_group\u0027)"},{"line_number":46,"context_line":"AT_LEAST_ONE_REQUEST_GROUP_REQUIRED \u003d ("},{"line_number":47,"context_line":"    \u0027placement.allocation_candidates.at_least_one_request_group_required\u0027)"}],"source_content_type":"text/x-python","patch_set":25,"id":"9f6a8fd7_863a1496","line":47,"in_reply_to":"9f6a8fd7_5a185183","updated":"2018-04-26 13:51:58.000000000","message":"Yes, I agree.  Let\u0027s set a proper precedent here.  But I don\u0027t really know how to begin.  Can you make some suggestions for these?","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"75c8849facc5b28d090f4f16370b38fd76945390","unresolved":false,"context_lines":[{"line_number":44,"context_line":"RESOURCES_REQUIRED_IN_REQUEST_GROUP \u003d ("},{"line_number":45,"context_line":"    \u0027placement.allocation_candidates.resources_required_in_request_group\u0027)"},{"line_number":46,"context_line":"AT_LEAST_ONE_REQUEST_GROUP_REQUIRED \u003d ("},{"line_number":47,"context_line":"    \u0027placement.allocation_candidates.at_least_one_request_group_required\u0027)"}],"source_content_type":"text/x-python","patch_set":25,"id":"9f6a8fd7_51f6f4fb","line":47,"in_reply_to":"9f6a8fd7_863a1496","updated":"2018-05-03 21:23:13.000000000","message":"I\u0027m not sure what use the above error codes would have. The point of the error codes was to allow machine-switchable behaviour based on some event.\n\nThe above are bad syntax/format errors. It\u0027s not like getting one of those back would allow the machine code to do something different (the machine code wouldn\u0027t have submitted the invalid request to begin with).","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"75c8849facc5b28d090f4f16370b38fd76945390","unresolved":false,"context_lines":[{"line_number":41,"context_line":"DEFAULT \u003d \u0027placement.undefined_code\u0027"},{"line_number":42,"context_line":"INVENTORY_INUSE \u003d \u0027placement.inventory.inuse\u0027"},{"line_number":43,"context_line":"# \u0027ac\u0027 \u003d\u003e GET /allocation_candidates"},{"line_number":44,"context_line":"GROUP_POLICY_REQUIRED \u003d \u0027placement.ac.group_policy_required\u0027"},{"line_number":45,"context_line":"RESOURCES_REQUIRED \u003d \u0027placement.ac.resources_required\u0027"},{"line_number":46,"context_line":"# \u0027rg\u0027 \u003d\u003e request group"},{"line_number":47,"context_line":"AT_LEAST_ONE_REQUEST_GROUP \u003d \u0027placement.ac.rg.at_least_one\u0027"}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_467ab224","line":44,"range":{"start_line":44,"start_character":35,"end_line":44,"end_character":37},"updated":"2018-05-03 21:23:13.000000000","message":"I continue to not see much of a point in codifying for things that humans need to react to. But, if you are going to add codes for these bad input subcategories, just leave off the \"ac\" or \"rg\" stuff entirely. So, I would recommend just doing this:\n\n GROUP_POLICY_REQUIRED \u003d \u0027placement.group_policy_required\u0027\n RESOURCES_REQUIRED \u003d \u0027placement.resources_required\u0027\n AT_LEAST_ONE_REQUEST_GROUP \u003d \u0027placement.at_least_one_request_group\u0027\n\netc..","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":41,"context_line":"DEFAULT \u003d \u0027placement.undefined_code\u0027"},{"line_number":42,"context_line":"INVENTORY_INUSE \u003d \u0027placement.inventory.inuse\u0027"},{"line_number":43,"context_line":"# \u0027ac\u0027 \u003d\u003e GET /allocation_candidates"},{"line_number":44,"context_line":"GROUP_POLICY_REQUIRED \u003d \u0027placement.ac.group_policy_required\u0027"},{"line_number":45,"context_line":"RESOURCES_REQUIRED \u003d \u0027placement.ac.resources_required\u0027"},{"line_number":46,"context_line":"# \u0027rg\u0027 \u003d\u003e request group"},{"line_number":47,"context_line":"AT_LEAST_ONE_REQUEST_GROUP \u003d \u0027placement.ac.rg.at_least_one\u0027"}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_3d38e1d1","line":44,"range":{"start_line":44,"start_character":35,"end_line":44,"end_character":37},"in_reply_to":"5f7c97a3_467ab224","updated":"2018-05-04 14:48:31.000000000","message":"okay.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"}],"nova/api/openstack/placement/handlers/allocation_candidate.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"df17734b771387f2624e284920a6fdea474cbac0","unresolved":false,"context_lines":[{"line_number":233,"context_line":"    if limit:"},{"line_number":234,"context_line":"        limit \u003d int(limit[0])"},{"line_number":235,"context_line":""},{"line_number":236,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027)"},{"line_number":237,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":238,"context_line":"    if group_policy:"},{"line_number":239,"context_line":"        group_policy \u003d group_policy[0]"},{"line_number":240,"context_line":""},{"line_number":241,"context_line":"    try:"},{"line_number":242,"context_line":"        cands \u003d rp_obj.AllocationCandidates.get_by_requests("}],"source_content_type":"text/x-python","patch_set":13,"id":"9f6a8fd7_846b67b5","line":239,"range":{"start_line":236,"start_character":0,"end_line":239,"end_character":38},"updated":"2018-04-20 12:04:10.000000000","message":"validate group_policy required if \u003e1 numbered request group.","commit_id":"d0ffd0196ac7b9958132be3f336702c3bcdfd96f"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"33b0106555c006ba7e9b3ba42d0eca8f8f5c6afa","unresolved":false,"context_lines":[{"line_number":225,"context_line":"    # Control whether we handle forbidden traits."},{"line_number":226,"context_line":"    allow_forbidden \u003d want_version.matches((1, 22))"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    requests \u003d util.parse_qs_request_groups("},{"line_number":229,"context_line":"        req.GET, allow_forbidden\u003dallow_forbidden)"},{"line_number":230,"context_line":"    limit \u003d req.GET.getall(\u0027limit\u0027)"},{"line_number":231,"context_line":"    # JSONschema has already confirmed that limit has the form"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_197b39f5","line":228,"updated":"2018-04-20 14:33:39.000000000","message":"Would it make sense to put the group_policy check within the utility code?","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0ea43cf027fda32fb0924f0c92fcc9713e97344c","unresolved":false,"context_lines":[{"line_number":225,"context_line":"    # Control whether we handle forbidden traits."},{"line_number":226,"context_line":"    allow_forbidden \u003d want_version.matches((1, 22))"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    requests \u003d util.parse_qs_request_groups("},{"line_number":229,"context_line":"        req.GET, allow_forbidden\u003dallow_forbidden)"},{"line_number":230,"context_line":"    limit \u003d req.GET.getall(\u0027limit\u0027)"},{"line_number":231,"context_line":"    # JSONschema has already confirmed that limit has the form"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_0d8c5334","line":228,"in_reply_to":"9f6a8fd7_02ae6297","updated":"2018-04-20 16:35:54.000000000","message":"Ah - group_policy is related to the request as a whole, not to each group.\n\nI had an iteration (back when I was working on ``separate_providers``) where I put it as a separate key in the requests dict that comes back from parse_qs_request_groups, but that was ugly and I didn\u0027t like it.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f82c4d55a2186e2c0ab6bd1a254aaab1695d75df","unresolved":false,"context_lines":[{"line_number":225,"context_line":"    # Control whether we handle forbidden traits."},{"line_number":226,"context_line":"    allow_forbidden \u003d want_version.matches((1, 22))"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    requests \u003d util.parse_qs_request_groups("},{"line_number":229,"context_line":"        req.GET, allow_forbidden\u003dallow_forbidden)"},{"line_number":230,"context_line":"    limit \u003d req.GET.getall(\u0027limit\u0027)"},{"line_number":231,"context_line":"    # JSONschema has already confirmed that limit has the form"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_185a4a29","line":228,"in_reply_to":"9f6a8fd7_0801a105","updated":"2018-04-20 23:11:11.000000000","message":"I could imagine some kind of RequestGroup field that would be like \"keep_separate_from\u003d\u003clist of other RequestGroups\u003e\", which would have to be populated carefully based on *parsing* group_policy.  Though my plan (when I was implementing separate_providers) was going to be passing those in as is and doing the inter-AllocationRequest filtering in the same kind of shape I\u0027m doing it now.  (Which is actually why I\u0027m using dicts suffixed by the original key - though I found that to make some other stuff easier as well.)","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"4c97431f594f4f0174605d518a78a01c53d1a583","unresolved":false,"context_lines":[{"line_number":225,"context_line":"    # Control whether we handle forbidden traits."},{"line_number":226,"context_line":"    allow_forbidden \u003d want_version.matches((1, 22))"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    requests \u003d util.parse_qs_request_groups("},{"line_number":229,"context_line":"        req.GET, allow_forbidden\u003dallow_forbidden)"},{"line_number":230,"context_line":"    limit \u003d req.GET.getall(\u0027limit\u0027)"},{"line_number":231,"context_line":"    # JSONschema has already confirmed that limit has the form"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_0801a105","line":228,"in_reply_to":"9f6a8fd7_0d8c5334","updated":"2018-04-20 16:57:43.000000000","message":"I was imagining that the input of group_policy would result in a value on _some_ of the RequestGroupS would be come truthy and we wouldn\u0027t carry the group_policy itself over into the object/db layer. But perhaps that couldn\u0027t work (now). It seems like down the road that it will eventually need to work that way.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d2e27cbdd25914c29b1000f60d3f72d588115bde","unresolved":false,"context_lines":[{"line_number":225,"context_line":"    # Control whether we handle forbidden traits."},{"line_number":226,"context_line":"    allow_forbidden \u003d want_version.matches((1, 22))"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    requests \u003d util.parse_qs_request_groups("},{"line_number":229,"context_line":"        req.GET, allow_forbidden\u003dallow_forbidden)"},{"line_number":230,"context_line":"    limit \u003d req.GET.getall(\u0027limit\u0027)"},{"line_number":231,"context_line":"    # JSONschema has already confirmed that limit has the form"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_dcda8f49","line":228,"in_reply_to":"9f6a8fd7_197b39f5","updated":"2018-04-20 14:52:06.000000000","message":"You mean write a utility method to do the error check?  Or move the whole check into the parse_qs_request_groups method?  If the latter, that would mean I either have to return the group_policy out of that method (which is a little dirty) or re-grab it here.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"e0ce3509e3294328383add3ffe513ca9a3d3ef10","unresolved":false,"context_lines":[{"line_number":225,"context_line":"    # Control whether we handle forbidden traits."},{"line_number":226,"context_line":"    allow_forbidden \u003d want_version.matches((1, 22))"},{"line_number":227,"context_line":""},{"line_number":228,"context_line":"    requests \u003d util.parse_qs_request_groups("},{"line_number":229,"context_line":"        req.GET, allow_forbidden\u003dallow_forbidden)"},{"line_number":230,"context_line":"    limit \u003d req.GET.getall(\u0027limit\u0027)"},{"line_number":231,"context_line":"    # JSONschema has already confirmed that limit has the form"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_02ae6297","line":228,"in_reply_to":"9f6a8fd7_dcda8f49","updated":"2018-04-20 15:55:21.000000000","message":"No, I mean make group_poilicy a member of the RequestGroup object. I don\u0027t know if that\u0027s a good idea or not, but it sort of makes sense and it isolates processing related to processing query parameters related to RequestGroups in one spot.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"33b0106555c006ba7e9b3ba42d0eca8f8f5c6afa","unresolved":false,"context_lines":[{"line_number":236,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027)"},{"line_number":237,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":238,"context_line":"    if group_policy:"},{"line_number":239,"context_line":"        group_policy \u003d group_policy[0]"},{"line_number":240,"context_line":"    else:"},{"line_number":241,"context_line":"        # group_policy is required if more than one numbered request group was"},{"line_number":242,"context_line":"        # specified."}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_d9a8618d","line":239,"updated":"2018-04-20 14:33:39.000000000","message":"Probably just matter of preference but you can do a different dance with reg.GET[\u0027group_policy\u0027] instead of getall and list indexing, if you\u0027re inclined.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d2e27cbdd25914c29b1000f60d3f72d588115bde","unresolved":false,"context_lines":[{"line_number":236,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027)"},{"line_number":237,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":238,"context_line":"    if group_policy:"},{"line_number":239,"context_line":"        group_policy \u003d group_policy[0]"},{"line_number":240,"context_line":"    else:"},{"line_number":241,"context_line":"        # group_policy is required if more than one numbered request group was"},{"line_number":242,"context_line":"        # specified."}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_dca84f8d","line":239,"in_reply_to":"9f6a8fd7_d9a8618d","updated":"2018-04-20 14:52:06.000000000","message":"Ack.  I was following the pattern of `limit` above.  Mostly because I was too lazy to go figure out the semantics of GET[key] or GET.get(key) or whatever allowing for the value to not exist.  But I\u0027ll cite consistency with `limit` so I can continue to be lazy.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"33b0106555c006ba7e9b3ba42d0eca8f8f5c6afa","unresolved":false,"context_lines":[{"line_number":240,"context_line":"    else:"},{"line_number":241,"context_line":"        # group_policy is required if more than one numbered request group was"},{"line_number":242,"context_line":"        # specified."},{"line_number":243,"context_line":"        if len([rg for rg in requests.values() if rg.use_same_provider]) \u003c 2:"},{"line_number":244,"context_line":"            # TODO(efried): error code"},{"line_number":245,"context_line":"            raise webob.exc.HTTPBadRequest("},{"line_number":246,"context_line":"                _(\u0027The \"group_policy\" parameter is required when specifying \u0027"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_19081990","line":243,"range":{"start_line":243,"start_character":73,"end_line":243,"end_character":74},"updated":"2018-04-20 14:33:39.000000000","message":"\u003c is confusing me here, I\u0027m expecting \u003e 1. Is something wrong or am I confused?","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d2e27cbdd25914c29b1000f60d3f72d588115bde","unresolved":false,"context_lines":[{"line_number":240,"context_line":"    else:"},{"line_number":241,"context_line":"        # group_policy is required if more than one numbered request group was"},{"line_number":242,"context_line":"        # specified."},{"line_number":243,"context_line":"        if len([rg for rg in requests.values() if rg.use_same_provider]) \u003c 2:"},{"line_number":244,"context_line":"            # TODO(efried): error code"},{"line_number":245,"context_line":"            raise webob.exc.HTTPBadRequest("},{"line_number":246,"context_line":"                _(\u0027The \"group_policy\" parameter is required when specifying \u0027"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_1c8c8734","line":243,"range":{"start_line":243,"start_character":73,"end_line":243,"end_character":74},"in_reply_to":"9f6a8fd7_19081990","updated":"2018-04-20 14:52:06.000000000","message":"You\u0027re right, I just goofed.  Thanks.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"e0ce3509e3294328383add3ffe513ca9a3d3ef10","unresolved":false,"context_lines":[{"line_number":248,"context_line":""},{"line_number":249,"context_line":"    try:"},{"line_number":250,"context_line":"        cands \u003d rp_obj.AllocationCandidates.get_by_requests("},{"line_number":251,"context_line":"            context, requests, limit\u003dlimit, group_policy\u003dgroup_policy)"},{"line_number":252,"context_line":"    except exception.ResourceClassNotFound as exc:"},{"line_number":253,"context_line":"        raise webob.exc.HTTPBadRequest("},{"line_number":254,"context_line":"            _(\u0027Invalid resource class in resources parameter: %(error)s\u0027) %"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_62aabe71","line":251,"updated":"2018-04-20 15:55:21.000000000","message":"And thus not pass it here just find it on the requests/","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0ea43cf027fda32fb0924f0c92fcc9713e97344c","unresolved":false,"context_lines":[{"line_number":248,"context_line":""},{"line_number":249,"context_line":"    try:"},{"line_number":250,"context_line":"        cands \u003d rp_obj.AllocationCandidates.get_by_requests("},{"line_number":251,"context_line":"            context, requests, limit\u003dlimit, group_policy\u003dgroup_policy)"},{"line_number":252,"context_line":"    except exception.ResourceClassNotFound as exc:"},{"line_number":253,"context_line":"        raise webob.exc.HTTPBadRequest("},{"line_number":254,"context_line":"            _(\u0027Invalid resource class in resources parameter: %(error)s\u0027) %"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_cd965b3f","line":251,"in_reply_to":"9f6a8fd7_62aabe71","updated":"2018-04-20 16:35:54.000000000","message":"Yeah; it\u0027s much more like `limit` in that regard: it applies to the request as a whole, not to the individual request groups.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":246,"context_line":"                _(\u0027The \"group_policy\" parameter is required when specifying \u0027"},{"line_number":247,"context_line":"                  \u0027more than one \"resources\u003cN\u003e\" parameter.\u0027),"},{"line_number":248,"context_line":"                comment\u003derrors.GROUP_POLICY_REQUIRED)"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"    try:"},{"line_number":251,"context_line":"        cands \u003d rp_obj.AllocationCandidates.get_by_requests("},{"line_number":252,"context_line":"            context, requests, limit\u003dlimit, group_policy\u003dgroup_policy)"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_63b956ca","line":249,"updated":"2018-04-21 14:45:50.000000000","message":"If we reach this point (i.e. no group_policy in the request but it not required as only a single group is provided) then group_policy is set to [] then it is passed to get_by_requests() where the docstring  says that it is expected to be a string or None. As far as I understand the value of this param only checked down in _satisfies_group_policy() where the [] value is treated like policy \"none\". So it seems wrong but at the end the code is logically correct.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":246,"context_line":"                _(\u0027The \"group_policy\" parameter is required when specifying \u0027"},{"line_number":247,"context_line":"                  \u0027more than one \"resources\u003cN\u003e\" parameter.\u0027),"},{"line_number":248,"context_line":"                comment\u003derrors.GROUP_POLICY_REQUIRED)"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"    try:"},{"line_number":251,"context_line":"        cands \u003d rp_obj.AllocationCandidates.get_by_requests("},{"line_number":252,"context_line":"            context, requests, limit\u003dlimit, group_policy\u003dgroup_policy)"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_492471af","line":249,"in_reply_to":"9f6a8fd7_63b956ca","updated":"2018-04-23 18:43:26.000000000","message":"Done","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"75c8849facc5b28d090f4f16370b38fd76945390","unresolved":false,"context_lines":[{"line_number":226,"context_line":"    # Control whether we handle forbidden traits."},{"line_number":227,"context_line":"    allow_forbidden \u003d want_version.matches((1, 22))"},{"line_number":228,"context_line":""},{"line_number":229,"context_line":"    requests \u003d util.parse_qs_request_groups("},{"line_number":230,"context_line":"        req.GET, allow_forbidden\u003dallow_forbidden)"},{"line_number":231,"context_line":"    limit \u003d req.GET.getall(\u0027limit\u0027)"},{"line_number":232,"context_line":"    # JSONschema has already confirmed that limit has the form"},{"line_number":233,"context_line":"    # of an integer."}],"source_content_type":"text/x-python","patch_set":25,"id":"9f6a8fd7_d1ba0409","line":230,"range":{"start_line":229,"start_character":4,"end_line":230,"end_character":49},"updated":"2018-05-03 21:23:13.000000000","message":"the validation should be done in the parse_qs_request_groups() method (as was asked of me in the multi-member-of series).","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"fe8cfea0c138ce15a08619da394e4a932886b4b6","unresolved":false,"context_lines":[{"line_number":234,"context_line":"    if limit:"},{"line_number":235,"context_line":"        limit \u003d int(limit[0])"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027) or None"},{"line_number":238,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":239,"context_line":"    if group_policy:"},{"line_number":240,"context_line":"        group_policy \u003d group_policy[0]"},{"line_number":241,"context_line":"    else:"},{"line_number":242,"context_line":"        # group_policy is required if more than one numbered request group was"},{"line_number":243,"context_line":"        # specified."},{"line_number":244,"context_line":"        if len([rg for rg in requests.values() if rg.use_same_provider]) \u003e 1:"},{"line_number":245,"context_line":"            raise webob.exc.HTTPBadRequest("},{"line_number":246,"context_line":"                _(\u0027The \"group_policy\" parameter is required when specifying \u0027"},{"line_number":247,"context_line":"                  \u0027more than one \"resources\u003cN\u003e\" parameter.\u0027),"},{"line_number":248,"context_line":"                comment\u003derrors.GROUP_POLICY_REQUIRED)"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"    try:"},{"line_number":251,"context_line":"        cands \u003d rp_obj.AllocationCandidates.get_by_requests("}],"source_content_type":"text/x-python","patch_set":25,"id":"9f6a8fd7_9a058917","line":248,"range":{"start_line":237,"start_character":0,"end_line":248,"end_character":53},"updated":"2018-04-26 12:04:09.000000000","message":"consider extracting to own method, then you can unit test it if you want: https://docs.openstack.org/nova/latest/contributor/placement.html#testing","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"75c8849facc5b28d090f4f16370b38fd76945390","unresolved":false,"context_lines":[{"line_number":234,"context_line":"    if limit:"},{"line_number":235,"context_line":"        limit \u003d int(limit[0])"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027) or None"},{"line_number":238,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":239,"context_line":"    if group_policy:"},{"line_number":240,"context_line":"        group_policy \u003d group_policy[0]"},{"line_number":241,"context_line":"    else:"},{"line_number":242,"context_line":"        # group_policy is required if more than one numbered request group was"},{"line_number":243,"context_line":"        # specified."},{"line_number":244,"context_line":"        if len([rg for rg in requests.values() if rg.use_same_provider]) \u003e 1:"},{"line_number":245,"context_line":"            raise webob.exc.HTTPBadRequest("},{"line_number":246,"context_line":"                _(\u0027The \"group_policy\" parameter is required when specifying \u0027"},{"line_number":247,"context_line":"                  \u0027more than one \"resources{N}\" parameter.\u0027),"},{"line_number":248,"context_line":"                comment\u003derrors.GROUP_POLICY_REQUIRED)"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"    try:"},{"line_number":251,"context_line":"        cands \u003d rp_obj.AllocationCandidates.get_by_requests("}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_46f63292","line":248,"range":{"start_line":237,"start_character":0,"end_line":248,"end_character":53},"updated":"2018-05-03 21:23:13.000000000","message":"you should be able to move all of this into util.parse_qs_request_groups()","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":234,"context_line":"    if limit:"},{"line_number":235,"context_line":"        limit \u003d int(limit[0])"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027) or None"},{"line_number":238,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":239,"context_line":"    if group_policy:"},{"line_number":240,"context_line":"        group_policy \u003d group_policy[0]"},{"line_number":241,"context_line":"    else:"},{"line_number":242,"context_line":"        # group_policy is required if more than one numbered request group was"},{"line_number":243,"context_line":"        # specified."},{"line_number":244,"context_line":"        if len([rg for rg in requests.values() if rg.use_same_provider]) \u003e 1:"},{"line_number":245,"context_line":"            raise webob.exc.HTTPBadRequest("},{"line_number":246,"context_line":"                _(\u0027The \"group_policy\" parameter is required when specifying \u0027"},{"line_number":247,"context_line":"                  \u0027more than one \"resources{N}\" parameter.\u0027),"},{"line_number":248,"context_line":"                comment\u003derrors.GROUP_POLICY_REQUIRED)"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"    try:"},{"line_number":251,"context_line":"        cands \u003d rp_obj.AllocationCandidates.get_by_requests("}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_7d2659ba","line":248,"range":{"start_line":237,"start_character":0,"end_line":248,"end_character":53},"in_reply_to":"5f7c97a3_46f63292","updated":"2018-05-04 14:48:31.000000000","message":"Yup, I was waiting for your member_of patch to land, rather than duplicating the refactoring you did there.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":229,"context_line":"    if limit:"},{"line_number":230,"context_line":"        limit \u003d int(limit[0])"},{"line_number":231,"context_line":""},{"line_number":232,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027) or None"},{"line_number":233,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":234,"context_line":"    if group_policy:"},{"line_number":235,"context_line":"        group_policy \u003d group_policy[0]"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_5a37a3b1","line":232,"range":{"start_line":232,"start_character":27,"end_line":232,"end_character":33},"updated":"2018-05-08 15:47:40.000000000","message":"Could have just done:\n\n group_policy \u003d req.GET.get(\u0027group_policy\u0027)\n if not group_policy:\n     ...","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":229,"context_line":"    if limit:"},{"line_number":230,"context_line":"        limit \u003d int(limit[0])"},{"line_number":231,"context_line":""},{"line_number":232,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027) or None"},{"line_number":233,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":234,"context_line":"    if group_policy:"},{"line_number":235,"context_line":"        group_policy \u003d group_policy[0]"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_c5df54d4","line":232,"range":{"start_line":232,"start_character":27,"end_line":232,"end_character":33},"in_reply_to":"5f7c97a3_5a37a3b1","updated":"2018-05-08 16:53:54.000000000","message":"Right, we talked about this in a previous PS, I was just doing this to match `limit` above.  I can tweak both in a fup if you like.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5f94320d769ef253b9afe7b0724eac5015ecdeee","unresolved":false,"context_lines":[{"line_number":229,"context_line":"    if limit:"},{"line_number":230,"context_line":"        limit \u003d int(limit[0])"},{"line_number":231,"context_line":""},{"line_number":232,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027) or None"},{"line_number":233,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":234,"context_line":"    if group_policy:"},{"line_number":235,"context_line":"        group_policy \u003d group_policy[0]"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_ced7de4a","line":232,"range":{"start_line":232,"start_character":27,"end_line":232,"end_character":33},"in_reply_to":"5f7c97a3_b48dab32","updated":"2018-05-15 22:35:56.000000000","message":"See https://review.openstack.org/568713","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4769f15df6937ae4cfea48969918306522439a50","unresolved":false,"context_lines":[{"line_number":229,"context_line":"    if limit:"},{"line_number":230,"context_line":"        limit \u003d int(limit[0])"},{"line_number":231,"context_line":""},{"line_number":232,"context_line":"    group_policy \u003d req.GET.getall(\u0027group_policy\u0027) or None"},{"line_number":233,"context_line":"    # Schema ensures we get either \"none\" or \"isolate\""},{"line_number":234,"context_line":"    if group_policy:"},{"line_number":235,"context_line":"        group_policy \u003d group_policy[0]"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_b48dab32","line":232,"range":{"start_line":232,"start_character":27,"end_line":232,"end_character":33},"in_reply_to":"5f7c97a3_c5df54d4","updated":"2018-05-08 17:10:36.000000000","message":"no worries :)","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"}],"nova/api/openstack/placement/objects/resource_provider.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"02f98185f76201ad8728050fd7c30a2cb29e3db4","unresolved":false,"context_lines":[{"line_number":939,"context_line":"            # We want the return value to have the root provider UUID even if"},{"line_number":940,"context_line":"            # we don\u0027t push it back to the database."},{"line_number":941,"context_line":"            db_resource_provider[\u0027root_provider_uuid\u0027] \u003d uuid"},{"line_number":942,"context_line":"            if do_migration:"},{"line_number":943,"context_line":"                # Online data migration to populate root_provider_id"},{"line_number":944,"context_line":"                _set_root_provider_id(context, rp_id, rp_id)"},{"line_number":945,"context_line":"        for field in resource_provider.fields:"},{"line_number":946,"context_line":"            setattr(resource_provider, field, db_resource_provider[field])"},{"line_number":947,"context_line":"        resource_provider._context \u003d context"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_abd02a52","line":944,"range":{"start_line":942,"start_character":0,"end_line":944,"end_character":60},"updated":"2018-04-16 18:06:30.000000000","message":"Why is this separated out like this?","commit_id":"a256f311fd4ba3977fa15f3eed4f70642160607c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[{"line_number":939,"context_line":"            # We want the return value to have the root provider UUID even if"},{"line_number":940,"context_line":"            # we don\u0027t push it back to the database."},{"line_number":941,"context_line":"            db_resource_provider[\u0027root_provider_uuid\u0027] \u003d uuid"},{"line_number":942,"context_line":"            if do_migration:"},{"line_number":943,"context_line":"                # Online data migration to populate root_provider_id"},{"line_number":944,"context_line":"                _set_root_provider_id(context, rp_id, rp_id)"},{"line_number":945,"context_line":"        for field in resource_provider.fields:"},{"line_number":946,"context_line":"            setattr(resource_provider, field, db_resource_provider[field])"},{"line_number":947,"context_line":"        resource_provider._context \u003d context"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_c675559a","line":944,"range":{"start_line":942,"start_character":0,"end_line":944,"end_character":60},"in_reply_to":"9f6a8fd7_abd02a52","updated":"2018-04-16 18:33:40.000000000","message":"Yeah, funny story.\n\nI needed to get at the root provider UUID for the resource providers in the allocation candidates built by each iteration of _get_by_one_request.  Imagine my chagrin when I found that they were only being populated with the RP UUID.  So I wanted to retrieve the full record from the DB; but when I went to do that, I got complaints about upgrading a reader transaction to a writer.  Turns out it was because _from_db_object needed the writer transaction to do this db migration.  So I made a reader version that can pull the info without caring that it gets written back to the db.\n\nIf there\u0027s a better way, please do tell.","commit_id":"a256f311fd4ba3977fa15f3eed4f70642160607c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0e3e2fc537f88c86325e5e8dbda7854c5d376fac","unresolved":false,"context_lines":[{"line_number":939,"context_line":"            # We want the return value to have the root provider UUID even if"},{"line_number":940,"context_line":"            # we don\u0027t push it back to the database."},{"line_number":941,"context_line":"            db_resource_provider[\u0027root_provider_uuid\u0027] \u003d uuid"},{"line_number":942,"context_line":"            if do_migration:"},{"line_number":943,"context_line":"                # Online data migration to populate root_provider_id"},{"line_number":944,"context_line":"                _set_root_provider_id(context, rp_id, rp_id)"},{"line_number":945,"context_line":"        for field in resource_provider.fields:"},{"line_number":946,"context_line":"            setattr(resource_provider, field, db_resource_provider[field])"},{"line_number":947,"context_line":"        resource_provider._context \u003d context"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_3fc37d5f","line":944,"range":{"start_line":942,"start_character":0,"end_line":944,"end_character":60},"in_reply_to":"9f6a8fd7_c675559a","updated":"2018-04-20 15:13:58.000000000","message":"Since both you and cdent asked about this, I went ahead and added some comments.","commit_id":"a256f311fd4ba3977fa15f3eed4f70642160607c"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"02f98185f76201ad8728050fd7c30a2cb29e3db4","unresolved":false,"context_lines":[{"line_number":3726,"context_line":"                    resources.add(psumres)"},{"line_number":3727,"context_line":"            psums_by_rp[rp_uuid].resources \u003d list(resources)"},{"line_number":3728,"context_line":""},{"line_number":3729,"context_line":"        # We are done."},{"line_number":3730,"context_line":"        return areqs, list(psums_by_rp.values())"},{"line_number":3731,"context_line":""},{"line_number":3732,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_eb8e222d","line":3729,"updated":"2018-04-16 18:06:30.000000000","message":"unnecessary comment, please remove.","commit_id":"a256f311fd4ba3977fa15f3eed4f70642160607c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[{"line_number":3726,"context_line":"                    resources.add(psumres)"},{"line_number":3727,"context_line":"            psums_by_rp[rp_uuid].resources \u003d list(resources)"},{"line_number":3728,"context_line":""},{"line_number":3729,"context_line":"        # We are done."},{"line_number":3730,"context_line":"        return areqs, list(psums_by_rp.values())"},{"line_number":3731,"context_line":""},{"line_number":3732,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_e69f39b2","line":3729,"in_reply_to":"9f6a8fd7_eb8e222d","updated":"2018-04-16 18:33:40.000000000","message":"Done","commit_id":"a256f311fd4ba3977fa15f3eed4f70642160607c"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"33b0106555c006ba7e9b3ba42d0eca8f8f5c6afa","unresolved":false,"context_lines":[{"line_number":2660,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2661,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2662,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."},{"line_number":2663,"context_line":"        \u0027use_same_provider\u0027: fields.BooleanField(),"},{"line_number":2664,"context_line":"        \u0027resource_requests\u0027: fields.ListOfObjectsField("},{"line_number":2665,"context_line":"            \u0027AllocationRequestResource\u0027"},{"line_number":2666,"context_line":"        ),"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_b9d9edf3","line":2663,"updated":"2018-04-20 14:33:39.000000000","message":"Until now I\u0027ve thought of the AllocationRequest as an output related object, so it is not immediately obvious to me what these changes are doing.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"e0ce3509e3294328383add3ffe513ca9a3d3ef10","unresolved":false,"context_lines":[{"line_number":2660,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2661,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2662,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."},{"line_number":2663,"context_line":"        \u0027use_same_provider\u0027: fields.BooleanField(),"},{"line_number":2664,"context_line":"        \u0027resource_requests\u0027: fields.ListOfObjectsField("},{"line_number":2665,"context_line":"            \u0027AllocationRequestResource\u0027"},{"line_number":2666,"context_line":"        ),"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_e2e48ee2","line":2663,"in_reply_to":"9f6a8fd7_5cf19f94","updated":"2018-04-20 15:55:21.000000000","message":"Right, I don\u0027t like those fields that Ed has done on the Consumer object either. Of course, I don\u0027t like that we have a Consumer object at all, so my opinions on using these objects any other than the interface to the DB is perhaps suspect. But ya know, we\u0027ve all got opinions.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"4c97431f594f4f0174605d518a78a01c53d1a583","unresolved":false,"context_lines":[{"line_number":2660,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2661,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2662,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."},{"line_number":2663,"context_line":"        \u0027use_same_provider\u0027: fields.BooleanField(),"},{"line_number":2664,"context_line":"        \u0027resource_requests\u0027: fields.ListOfObjectsField("},{"line_number":2665,"context_line":"            \u0027AllocationRequestResource\u0027"},{"line_number":2666,"context_line":"        ),"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_6817fd46","line":2663,"in_reply_to":"9f6a8fd7_adca074b","updated":"2018-04-20 16:57:43.000000000","message":"Oh, you know me, just pass around a lot of parameters is my default position. It makes it clear that the activity being performed is messy, in reality.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d2e27cbdd25914c29b1000f60d3f72d588115bde","unresolved":false,"context_lines":[{"line_number":2660,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2661,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2662,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."},{"line_number":2663,"context_line":"        \u0027use_same_provider\u0027: fields.BooleanField(),"},{"line_number":2664,"context_line":"        \u0027resource_requests\u0027: fields.ListOfObjectsField("},{"line_number":2665,"context_line":"            \u0027AllocationRequestResource\u0027"},{"line_number":2666,"context_line":"        ),"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_5cf19f94","line":2663,"in_reply_to":"9f6a8fd7_b9d9edf3","updated":"2018-04-20 14:52:06.000000000","message":"These fields are helping the merge/filter processing.  They don\u0027t show up in the output.  I felt okay doing that since the output format doesn\u0027t follow the object format at all; and it\u0027s created by a method somewhere else - it\u0027s not like there\u0027s an implicit serializer or something that I had to hack to make it *not* report these fields.\n\nIt\u0027s a lot like Ed\u0027s enforce_generation and request_generation fields in Consumer [1].\n\nIs there something I could maybe say in the comments that would make this easier to swallow?\n\n[1] https://review.openstack.org/#/c/561406/4/nova/api/openstack/placement/objects/resource_provider.py@3721","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0ea43cf027fda32fb0924f0c92fcc9713e97344c","unresolved":false,"context_lines":[{"line_number":2660,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2661,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2662,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."},{"line_number":2663,"context_line":"        \u0027use_same_provider\u0027: fields.BooleanField(),"},{"line_number":2664,"context_line":"        \u0027resource_requests\u0027: fields.ListOfObjectsField("},{"line_number":2665,"context_line":"            \u0027AllocationRequestResource\u0027"},{"line_number":2666,"context_line":"        ),"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_adca074b","line":2663,"in_reply_to":"9f6a8fd7_e2e48ee2","updated":"2018-04-20 16:35:54.000000000","message":"I\u0027ll admit, adding these fields here was something of a last resort.  I cast around for a good long while trying to figure out other ways to get the appropriate information to the appropriate places, and everything else was *way* hackier and messier.  If you\u0027d like to suggest alternatives, I\u0027m happy to hear them.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"6e301601bb86eff6ee9756684743f005ce79215d","unresolved":false,"context_lines":[{"line_number":719,"context_line":"        \"\"\"Returns a new ResourceProvider object with the supplied UUID."},{"line_number":720,"context_line":""},{"line_number":721,"context_line":"        :raises NotFound if no such provider could be found"},{"line_number":722,"context_line":"        :param uuid: UUID of the provider to search for"},{"line_number":723,"context_line":"        \"\"\""},{"line_number":724,"context_line":"        rp_rec \u003d _get_provider_by_uuid(context, uuid)"},{"line_number":725,"context_line":"        meth \u003d (cls._from_db_object if do_migration"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_a2b0d644","line":722,"updated":"2018-04-20 16:52:19.000000000","message":"Need to add the param \u0027do_migration\u0027","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f82c4d55a2186e2c0ab6bd1a254aaab1695d75df","unresolved":false,"context_lines":[{"line_number":719,"context_line":"        \"\"\"Returns a new ResourceProvider object with the supplied UUID."},{"line_number":720,"context_line":""},{"line_number":721,"context_line":"        :raises NotFound if no such provider could be found"},{"line_number":722,"context_line":"        :param uuid: UUID of the provider to search for"},{"line_number":723,"context_line":"        \"\"\""},{"line_number":724,"context_line":"        rp_rec \u003d _get_provider_by_uuid(context, uuid)"},{"line_number":725,"context_line":"        meth \u003d (cls._from_db_object if do_migration"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_c53dcfc4","line":722,"in_reply_to":"9f6a8fd7_a2b0d644","updated":"2018-04-20 23:11:11.000000000","message":"Done","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"70fc8b2ffe443c03ef45dd4c043ff8641e1e8c1d","unresolved":false,"context_lines":[{"line_number":722,"context_line":"        :param uuid: UUID of the provider to search for"},{"line_number":723,"context_line":"        \"\"\""},{"line_number":724,"context_line":"        rp_rec \u003d _get_provider_by_uuid(context, uuid)"},{"line_number":725,"context_line":"        meth \u003d (cls._from_db_object if do_migration"},{"line_number":726,"context_line":"                else cls._from_db_object_no_migration)"},{"line_number":727,"context_line":"        return meth(context, cls(), rp_rec)"},{"line_number":728,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_3f8b7d6e","line":725,"range":{"start_line":725,"start_character":8,"end_line":725,"end_character":12},"updated":"2018-04-20 15:27:46.000000000","message":"Who are you, Walter White?","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0ea43cf027fda32fb0924f0c92fcc9713e97344c","unresolved":false,"context_lines":[{"line_number":722,"context_line":"        :param uuid: UUID of the provider to search for"},{"line_number":723,"context_line":"        \"\"\""},{"line_number":724,"context_line":"        rp_rec \u003d _get_provider_by_uuid(context, uuid)"},{"line_number":725,"context_line":"        meth \u003d (cls._from_db_object if do_migration"},{"line_number":726,"context_line":"                else cls._from_db_object_no_migration)"},{"line_number":727,"context_line":"        return meth(context, cls(), rp_rec)"},{"line_number":728,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_42677abe","line":725,"range":{"start_line":725,"start_character":8,"end_line":725,"end_character":12},"in_reply_to":"9f6a8fd7_3f8b7d6e","updated":"2018-04-20 16:35:54.000000000","message":"That\u0027s Heisenberg to you, chum.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"70fc8b2ffe443c03ef45dd4c043ff8641e1e8c1d","unresolved":false,"context_lines":[{"line_number":930,"context_line":"                    reason\u003d_(\u0027parent provider UUID does not exist.\u0027))"},{"line_number":931,"context_line":""},{"line_number":932,"context_line":"    @staticmethod"},{"line_number":933,"context_line":"    def __from_db_object(context, resource_provider, db_resource_provider,"},{"line_number":934,"context_line":"                         do_migration):"},{"line_number":935,"context_line":"        # TODO(jaypipes): Remove when all root_provider_id values are NOT NULL"},{"line_number":936,"context_line":"        if db_resource_provider[\u0027root_provider_uuid\u0027] is None:"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_dfc921ac","line":933,"range":{"start_line":933,"start_character":8,"end_line":933,"end_character":24},"updated":"2018-04-20 15:27:46.000000000","message":"dunders are usually only for special methods. If you just want to distinguish from the single underscore method, change the name to indicate the distinction. Otherwise, it makes it hard to keep straight.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0ea43cf027fda32fb0924f0c92fcc9713e97344c","unresolved":false,"context_lines":[{"line_number":930,"context_line":"                    reason\u003d_(\u0027parent provider UUID does not exist.\u0027))"},{"line_number":931,"context_line":""},{"line_number":932,"context_line":"    @staticmethod"},{"line_number":933,"context_line":"    def __from_db_object(context, resource_provider, db_resource_provider,"},{"line_number":934,"context_line":"                         do_migration):"},{"line_number":935,"context_line":"        # TODO(jaypipes): Remove when all root_provider_id values are NOT NULL"},{"line_number":936,"context_line":"        if db_resource_provider[\u0027root_provider_uuid\u0027] is None:"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_e20c8eed","line":933,"range":{"start_line":933,"start_character":8,"end_line":933,"end_character":24},"in_reply_to":"9f6a8fd7_dfc921ac","updated":"2018-04-20 16:35:54.000000000","message":"ack","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"bd80013bbaaccea7ee0fc734999705cb8e19177f","unresolved":false,"context_lines":[{"line_number":2659,"context_line":"    fields \u003d {"},{"line_number":2660,"context_line":"        # UUID of (the root of the tree including) the resource provider that"},{"line_number":2661,"context_line":"        # \"anchors\" this AllocationRequest."},{"line_number":2662,"context_line":"        \u0027anchor_root_provider_uuid\u0027: fields.UUIDField(nullable\u003dTrue),"},{"line_number":2663,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2664,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2665,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_8254b222","line":2662,"range":{"start_line":2662,"start_character":9,"end_line":2662,"end_character":34},"updated":"2018-04-20 17:04:47.000000000","message":"Could the anchor be anything else now than the root of the tree providing the allocations?","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"bd80013bbaaccea7ee0fc734999705cb8e19177f","unresolved":false,"context_lines":[{"line_number":2659,"context_line":"    fields \u003d {"},{"line_number":2660,"context_line":"        # UUID of (the root of the tree including) the resource provider that"},{"line_number":2661,"context_line":"        # \"anchors\" this AllocationRequest."},{"line_number":2662,"context_line":"        \u0027anchor_root_provider_uuid\u0027: fields.UUIDField(nullable\u003dTrue),"},{"line_number":2663,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2664,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2665,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_222da6fd","line":2662,"range":{"start_line":2662,"start_character":54,"end_line":2662,"end_character":67},"updated":"2018-04-20 17:04:47.000000000","message":"What does it mean if this field is set to None?","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f82c4d55a2186e2c0ab6bd1a254aaab1695d75df","unresolved":false,"context_lines":[{"line_number":2659,"context_line":"    fields \u003d {"},{"line_number":2660,"context_line":"        # UUID of (the root of the tree including) the resource provider that"},{"line_number":2661,"context_line":"        # \"anchors\" this AllocationRequest."},{"line_number":2662,"context_line":"        \u0027anchor_root_provider_uuid\u0027: fields.UUIDField(nullable\u003dTrue),"},{"line_number":2663,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2664,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2665,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_e5ad73e9","line":2662,"range":{"start_line":2662,"start_character":54,"end_line":2662,"end_character":67},"in_reply_to":"9f6a8fd7_222da6fd","updated":"2018-04-20 23:11:11.000000000","message":"It\u0027s only used for certain parts of the granular code path (see below), wherein it *can\u0027t* be None.  But once that part of the algorithm is done, we don\u0027t need it anymore (it\u0027s not involved in the output) so we don\u0027t set it when we build the final version of the AllocationRequest.  That\u0027s why it\u0027s allowed to be nullable.\n\nI suppose it wouldn\u0027t hurt anything for me to set it on that final AllocationRequest.  That would allow me to make it non-nullable, which would provide some inherent consistency checking.  I\u0027ll try that out.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":2659,"context_line":"    fields \u003d {"},{"line_number":2660,"context_line":"        # UUID of (the root of the tree including) the resource provider that"},{"line_number":2661,"context_line":"        # \"anchors\" this AllocationRequest."},{"line_number":2662,"context_line":"        \u0027anchor_root_provider_uuid\u0027: fields.UUIDField(nullable\u003dTrue),"},{"line_number":2663,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2664,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2665,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_838a6a67","line":2662,"range":{"start_line":2662,"start_character":9,"end_line":2662,"end_character":34},"in_reply_to":"9f6a8fd7_457bfff3","updated":"2018-04-21 14:45:50.000000000","message":"OK, so it is either the root_provider of the tree that provides the resources or the root_provider of the tree a sharing provider provides resource. I suggest to add some of these details to the doc as now the \"anchor\" term is not well defined.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f82c4d55a2186e2c0ab6bd1a254aaab1695d75df","unresolved":false,"context_lines":[{"line_number":2659,"context_line":"    fields \u003d {"},{"line_number":2660,"context_line":"        # UUID of (the root of the tree including) the resource provider that"},{"line_number":2661,"context_line":"        # \"anchors\" this AllocationRequest."},{"line_number":2662,"context_line":"        \u0027anchor_root_provider_uuid\u0027: fields.UUIDField(nullable\u003dTrue),"},{"line_number":2663,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2664,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2665,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_457bfff3","line":2662,"range":{"start_line":2662,"start_character":9,"end_line":2662,"end_character":34},"in_reply_to":"9f6a8fd7_8254b222","updated":"2018-04-20 23:11:11.000000000","message":"The reason I can\u0027t just look at resource_requests[N].resource_provider.root_provider_uuid is for situations where this AllocationRequest *only* has sharing providers in it.  The helper method that creates it knows which non-sharing provider it was associated with, so we set it at that point.  We then need to use the information later so we can correctly merge AllocationRequests that came from different request groups.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":2659,"context_line":"    fields \u003d {"},{"line_number":2660,"context_line":"        # UUID of (the root of the tree including) the resource provider that"},{"line_number":2661,"context_line":"        # \"anchors\" this AllocationRequest."},{"line_number":2662,"context_line":"        \u0027anchor_root_provider_uuid\u0027: fields.UUIDField(nullable\u003dTrue),"},{"line_number":2663,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2664,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2665,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_4959d132","line":2662,"range":{"start_line":2662,"start_character":9,"end_line":2662,"end_character":34},"in_reply_to":"9f6a8fd7_838a6a67","updated":"2018-04-23 18:43:26.000000000","message":"True, defining it in terms of itself is not helpful.  I\u0027ve reworded the definition to avoid the word \"anchor\".  Hopefully it makes sense - it\u0027s not the easiest concept.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":2659,"context_line":"    fields \u003d {"},{"line_number":2660,"context_line":"        # UUID of (the root of the tree including) the resource provider that"},{"line_number":2661,"context_line":"        # \"anchors\" this AllocationRequest."},{"line_number":2662,"context_line":"        \u0027anchor_root_provider_uuid\u0027: fields.UUIDField(nullable\u003dTrue),"},{"line_number":2663,"context_line":"        # Whether all AllocationRequestResources in this AllocationRequest are"},{"line_number":2664,"context_line":"        # required to be satisfied by the same provider (based on the"},{"line_number":2665,"context_line":"        # corresponding RequestGroup\u0027s use_same_provider attribute)."}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_a3e3ee33","line":2662,"range":{"start_line":2662,"start_character":54,"end_line":2662,"end_character":67},"in_reply_to":"9f6a8fd7_e5ad73e9","updated":"2018-04-21 14:45:50.000000000","message":"I see. In the meantime I found the mailthread where it was agreed that we don\u0027t need to return the anchor on the API.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"70fc8b2ffe443c03ef45dd4c043ff8641e1e8c1d","unresolved":false,"context_lines":[{"line_number":3630,"context_line":"        for trait_map, traits in ("},{"line_number":3631,"context_line":"            (required_trait_map, request.required_traits),"},{"line_number":3632,"context_line":"            (forbidden_trait_map, request.forbidden_traits)):"},{"line_number":3633,"context_line":"            if traits:"},{"line_number":3634,"context_line":"                trait_map.update(_trait_ids_from_names(context, traits))"},{"line_number":3635,"context_line":"                # Double-check that we found a trait ID for each requested name"},{"line_number":3636,"context_line":"                if len(trait_map) !\u003d len(traits):"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_bf930d5b","line":3633,"updated":"2018-04-20 15:27:46.000000000","message":"This is why continued lines should be indented two levels: to distinguish a continued line from the block it introduces. I abhor single level indentation anywhere, but when the block below is at the same level, it should be enforced. Indentation is semantic in Python.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f82c4d55a2186e2c0ab6bd1a254aaab1695d75df","unresolved":false,"context_lines":[{"line_number":3630,"context_line":"        for trait_map, traits in ("},{"line_number":3631,"context_line":"            (required_trait_map, request.required_traits),"},{"line_number":3632,"context_line":"            (forbidden_trait_map, request.forbidden_traits)):"},{"line_number":3633,"context_line":"            if traits:"},{"line_number":3634,"context_line":"                trait_map.update(_trait_ids_from_names(context, traits))"},{"line_number":3635,"context_line":"                # Double-check that we found a trait ID for each requested name"},{"line_number":3636,"context_line":"                if len(trait_map) !\u003d len(traits):"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_657de37d","line":3633,"in_reply_to":"9f6a8fd7_adb0c78b","updated":"2018-04-20 23:11:11.000000000","message":"Meh, matter of opinion I guess.  In the docstring case I find what you\u0027re calling \"visual\" makes it easy for me to see the blocks, though it\u0027s often a PITA to wrap, and the overall (zoomed out) effect is somewhat jarring.\n\nI guess I\u0027m not in the habit of using 2-level indent everywhere because I started pythoning in a project with all the pep8 rules enabled, plus sonar, and that simply wasn\u0027t allowed.  But I do like the idea and will try to work it up to habit status.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0ea43cf027fda32fb0924f0c92fcc9713e97344c","unresolved":false,"context_lines":[{"line_number":3630,"context_line":"        for trait_map, traits in ("},{"line_number":3631,"context_line":"            (required_trait_map, request.required_traits),"},{"line_number":3632,"context_line":"            (forbidden_trait_map, request.forbidden_traits)):"},{"line_number":3633,"context_line":"            if traits:"},{"line_number":3634,"context_line":"                trait_map.update(_trait_ids_from_names(context, traits))"},{"line_number":3635,"context_line":"                # Double-check that we found a trait ID for each requested name"},{"line_number":3636,"context_line":"                if len(trait_map) !\u003d len(traits):"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_cdb3bb09","line":3633,"in_reply_to":"9f6a8fd7_bf930d5b","updated":"2018-04-20 16:35:54.000000000","message":"Agree, fixed.\n\nThere are pep and sonar rules for this, but we have the former disabled in nova, and in my experience the latter can conflict with the former in some cases, making it nearly impossible to get right.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"6e301601bb86eff6ee9756684743f005ce79215d","unresolved":false,"context_lines":[{"line_number":3630,"context_line":"        for trait_map, traits in ("},{"line_number":3631,"context_line":"            (required_trait_map, request.required_traits),"},{"line_number":3632,"context_line":"            (forbidden_trait_map, request.forbidden_traits)):"},{"line_number":3633,"context_line":"            if traits:"},{"line_number":3634,"context_line":"                trait_map.update(_trait_ids_from_names(context, traits))"},{"line_number":3635,"context_line":"                # Double-check that we found a trait ID for each requested name"},{"line_number":3636,"context_line":"                if len(trait_map) !\u003d len(traits):"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_adb0c78b","line":3633,"in_reply_to":"9f6a8fd7_cdb3bb09","updated":"2018-04-20 16:52:19.000000000","message":"I\u0027ve found that using 2 level indent for continued lines works well. I absolutely hate visual indentation; see lines 3580-3598 for the horrible visual effect it creates.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"bd80013bbaaccea7ee0fc734999705cb8e19177f","unresolved":false,"context_lines":[{"line_number":3888,"context_line":"        # `candidates` dict is guaranteed to contain entries for all suffixes,"},{"line_number":3889,"context_line":"        # or we would have short-circuited above."},{"line_number":3890,"context_line":"        alloc_request_objs, summary_objs \u003d cls._merge_candidates("},{"line_number":3891,"context_line":"            candidates, group_policy\u003dgroup_policy)"},{"line_number":3892,"context_line":""},{"line_number":3893,"context_line":"        # Limit the number of allocation request objects. We do this after"},{"line_number":3894,"context_line":"        # creating all of them so that we can do a random slice without"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_481a396f","line":3891,"updated":"2018-04-20 17:04:47.000000000","message":"Assume that two groups(G1, G2) request resource from the same class (G1: {VCPU: 1}, G2: {VCPU: 2}) and the requests can be satisfied one by one by the same RP (RP1: {VCPU: 1}). Do we check during the folding that the total request still can satisfied by the selected RP? As in this example the answer is no.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f82c4d55a2186e2c0ab6bd1a254aaab1695d75df","unresolved":false,"context_lines":[{"line_number":3888,"context_line":"        # `candidates` dict is guaranteed to contain entries for all suffixes,"},{"line_number":3889,"context_line":"        # or we would have short-circuited above."},{"line_number":3890,"context_line":"        alloc_request_objs, summary_objs \u003d cls._merge_candidates("},{"line_number":3891,"context_line":"            candidates, group_policy\u003dgroup_policy)"},{"line_number":3892,"context_line":""},{"line_number":3893,"context_line":"        # Limit the number of allocation request objects. We do this after"},{"line_number":3894,"context_line":"        # creating all of them so that we can do a random slice without"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_580c42ec","line":3891,"in_reply_to":"9f6a8fd7_481a396f","updated":"2018-04-20 23:11:11.000000000","message":"Wow, that is an excellent point.\n\nI *think* I can look at `capacity` in the provider_summary, which already takes `allocation_ratio` and `reserved` into account, and then filter out the whole AllocationRequest if `used` plus the allocated amount exceeds `capacity`.  Agree?","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3888,"context_line":"        # `candidates` dict is guaranteed to contain entries for all suffixes,"},{"line_number":3889,"context_line":"        # or we would have short-circuited above."},{"line_number":3890,"context_line":"        alloc_request_objs, summary_objs \u003d cls._merge_candidates("},{"line_number":3891,"context_line":"            candidates, group_policy\u003dgroup_policy)"},{"line_number":3892,"context_line":""},{"line_number":3893,"context_line":"        # Limit the number of allocation request objects. We do this after"},{"line_number":3894,"context_line":"        # creating all of them so that we can do a random slice without"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_8366eac0","line":3891,"in_reply_to":"9f6a8fd7_580c42ec","updated":"2018-04-21 14:45:50.000000000","message":"Yes I agree. We have to take every AllocationRequestResource from an AllocationRequest, group them by AllocationRequestResource.resource_provider.uuid then sum the amount per resource class then compare that with the provider summary.\n\nI\u0027m wondering if this is something that can be done efficiently in the DB but that would mean a pretty different strategy than what you started implementing here. (And also it would mean I could not understand it implementation of it :))","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3888,"context_line":"        # `candidates` dict is guaranteed to contain entries for all suffixes,"},{"line_number":3889,"context_line":"        # or we would have short-circuited above."},{"line_number":3890,"context_line":"        alloc_request_objs, summary_objs \u003d cls._merge_candidates("},{"line_number":3891,"context_line":"            candidates, group_policy\u003dgroup_policy)"},{"line_number":3892,"context_line":""},{"line_number":3893,"context_line":"        # Limit the number of allocation request objects. We do this after"},{"line_number":3894,"context_line":"        # creating all of them so that we can do a random slice without"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_9eeaa60c","line":3891,"in_reply_to":"9f6a8fd7_8366eac0","updated":"2018-04-23 18:43:26.000000000","message":"Absolutely.  I agree that the whole granular business would almost certainly be more efficient if more of the logic was done in the database, AND I agree that that would be even harder to comprehend than what we\u0027ve got here.  This is a key point for reviewers to understand: I believe this approach is simple (well, *simpler* anyway) so we should start here; and if it winds up being a horrible performance drag, we can look at trying to push more of it down into the database.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8d8958723d99a389a5ee93129dd3c26c5960ea7d","unresolved":false,"context_lines":[{"line_number":3888,"context_line":"        # `candidates` dict is guaranteed to contain entries for all suffixes,"},{"line_number":3889,"context_line":"        # or we would have short-circuited above."},{"line_number":3890,"context_line":"        alloc_request_objs, summary_objs \u003d cls._merge_candidates("},{"line_number":3891,"context_line":"            candidates, group_policy\u003dgroup_policy)"},{"line_number":3892,"context_line":""},{"line_number":3893,"context_line":"        # Limit the number of allocation request objects. We do this after"},{"line_number":3894,"context_line":"        # creating all of them so that we can do a random slice without"}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_9b162649","line":3891,"in_reply_to":"9f6a8fd7_9eeaa60c","updated":"2018-04-24 09:09:16.000000000","message":"I totally agree with you about starting with the more readable implementation.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3168,"context_line":"                    context,"},{"line_number":3169,"context_line":"                    rp_uuid,"},{"line_number":3170,"context_line":"                    # In a reader transaction: disable online data migration."},{"line_number":3171,"context_line":"                    do_migration\u003dFalse"},{"line_number":3172,"context_line":"                ),"},{"line_number":3173,"context_line":"                resources\u003d[],"},{"line_number":3174,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_63071684","line":3171,"updated":"2018-04-21 14:45:50.000000000","message":"I think it can happen that we build a summary out of non-migrated RP and therefore we return a summary with resource_provider.root_provider_uuid\u003dNone here. However I don\u0027t see any code that later on uses this field so I think we are safe. But it would be good to add a test case to catch a code that might want to use that field later.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3168,"context_line":"                    context,"},{"line_number":3169,"context_line":"                    rp_uuid,"},{"line_number":3170,"context_line":"                    # In a reader transaction: disable online data migration."},{"line_number":3171,"context_line":"                    do_migration\u003dFalse"},{"line_number":3172,"context_line":"                ),"},{"line_number":3173,"context_line":"                resources\u003d[],"},{"line_number":3174,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_6977f5a1","line":3171,"in_reply_to":"9f6a8fd7_63071684","updated":"2018-04-23 18:43:26.000000000","message":"get_by_uuid *always* computes and includes the root_provider_uuid [1], even if it doesn\u0027t flush that datum back to the database.  So it should be impossible for it to be None here.\n\n[1] https://review.openstack.org/#/c/517757/19/nova/api/openstack/placement/objects/resource_provider.py@947","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8d8958723d99a389a5ee93129dd3c26c5960ea7d","unresolved":false,"context_lines":[{"line_number":3168,"context_line":"                    context,"},{"line_number":3169,"context_line":"                    rp_uuid,"},{"line_number":3170,"context_line":"                    # In a reader transaction: disable online data migration."},{"line_number":3171,"context_line":"                    do_migration\u003dFalse"},{"line_number":3172,"context_line":"                ),"},{"line_number":3173,"context_line":"                resources\u003d[],"},{"line_number":3174,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_3865a046","line":3171,"in_reply_to":"9f6a8fd7_6977f5a1","updated":"2018-04-24 09:09:16.000000000","message":"You are right. My mistake.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3572,"context_line":""},{"line_number":3573,"context_line":"def _rp_rc_key(rp, rc):"},{"line_number":3574,"context_line":"    \"\"\"Creates hashable string key unique to a provider + resource class.\"\"\""},{"line_number":3575,"context_line":"    return \u0027_\u0027.join([rp.uuid, rc])"},{"line_number":3576,"context_line":""},{"line_number":3577,"context_line":""},{"line_number":3578,"context_line":"def deflate(areqs):"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_83a7cabd","line":3575,"range":{"start_line":3575,"start_character":11,"end_line":3575,"end_character":34},"updated":"2018-04-21 14:45:50.000000000","message":"While [rp.uuid, rc] is non hashable (as list is mutable), (rp.uuid, rc) is hashable so you don\u0027t need to do the extra join if you don\u0027t want to","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3572,"context_line":""},{"line_number":3573,"context_line":"def _rp_rc_key(rp, rc):"},{"line_number":3574,"context_line":"    \"\"\"Creates hashable string key unique to a provider + resource class.\"\"\""},{"line_number":3575,"context_line":"    return \u0027_\u0027.join([rp.uuid, rc])"},{"line_number":3576,"context_line":""},{"line_number":3577,"context_line":""},{"line_number":3578,"context_line":"def deflate(areqs):"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_0968b9b6","line":3575,"range":{"start_line":3575,"start_character":11,"end_line":3575,"end_character":34},"in_reply_to":"9f6a8fd7_83a7cabd","updated":"2018-04-23 18:43:26.000000000","message":"Mm, good point.  And I think if I do that, it allows me to refactor some of the code below to reduce the number of additional \"indexing\" objects I need.\n\n...or maybe not.  But done anyway.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3633,"context_line":"    :return: True if areqs satisfies group_policy; False otherwise."},{"line_number":3634,"context_line":"    \"\"\""},{"line_number":3635,"context_line":"    if group_policy !\u003d \u0027isolate\u0027:"},{"line_number":3636,"context_line":"        # group_policy\u003d\"none\" means no filtering"},{"line_number":3637,"context_line":"        return True"},{"line_number":3638,"context_line":""},{"line_number":3639,"context_line":"    # If isolation was requested, see if we need to filter this one out. We do"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_86c27858","line":3636,"updated":"2018-04-21 14:45:50.000000000","message":"I think we also hit this when group_policy is not provided in the request and therefore the group_policy is set to [] by the API code. But returning True in this case is also the correct answer.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3633,"context_line":"    :return: True if areqs satisfies group_policy; False otherwise."},{"line_number":3634,"context_line":"    \"\"\""},{"line_number":3635,"context_line":"    if group_policy !\u003d \u0027isolate\u0027:"},{"line_number":3636,"context_line":"        # group_policy\u003d\"none\" means no filtering"},{"line_number":3637,"context_line":"        return True"},{"line_number":3638,"context_line":""},{"line_number":3639,"context_line":"    # If isolation was requested, see if we need to filter this one out. We do"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_c9b2c149","line":3636,"in_reply_to":"9f6a8fd7_86c27858","updated":"2018-04-23 18:43:26.000000000","message":"Fixed it so group_policy is None in that case.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3641,"context_line":"    # use_same_provider\u003dTrue groups.  This must match the number of"},{"line_number":3642,"context_line":"    # use_same_provider\u003dTrue RequestGroups in the input."},{"line_number":3643,"context_line":"    return num_granular_groups \u003d\u003d len(set("},{"line_number":3644,"context_line":"        areq.resource_requests[0].resource_provider"},{"line_number":3645,"context_line":"        for areq in areqs"},{"line_number":3646,"context_line":"        if areq.use_same_provider))"},{"line_number":3647,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_26b36c0c","line":3644,"range":{"start_line":3644,"start_character":13,"end_line":3644,"end_character":33},"updated":"2018-04-21 14:45:50.000000000","message":"note to myself: Taking only the first resource_provider from the list is correct here because we filter for areq.use_same_provider \u003d\u003d True below and that means that _every_ resource request in an allocation request has the same resource provider.\n\nThis assumption is documented in the function\u0027s doc at L3618 so it is OK","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3641,"context_line":"    # use_same_provider\u003dTrue groups.  This must match the number of"},{"line_number":3642,"context_line":"    # use_same_provider\u003dTrue RequestGroups in the input."},{"line_number":3643,"context_line":"    return num_granular_groups \u003d\u003d len(set("},{"line_number":3644,"context_line":"        areq.resource_requests[0].resource_provider"},{"line_number":3645,"context_line":"        for areq in areqs"},{"line_number":3646,"context_line":"        if areq.use_same_provider))"},{"line_number":3647,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_6985b559","line":3644,"range":{"start_line":3644,"start_character":13,"end_line":3644,"end_character":33},"in_reply_to":"9f6a8fd7_26b36c0c","updated":"2018-04-23 18:43:26.000000000","message":"Worth reiterating in a comment here, though.  (I\u0027m sure I had done that at some point along the way :)","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3658,"context_line":"    for arr in areq.resource_requests:"},{"line_number":3659,"context_line":"        key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3660,"context_line":"        psum_res \u003d psum_res_by_rp_rc[key]"},{"line_number":3661,"context_line":"        if psum_res.used + arr.amount \u003e psum_res.capacity:"},{"line_number":3662,"context_line":"            return True"},{"line_number":3663,"context_line":"    return False"},{"line_number":3664,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_c6987076","line":3661,"updated":"2018-04-21 14:45:50.000000000","message":"Unfortunately this calculation does not take into account: \n* max_unit: Two independent allocation request might be smaller than max_unit of the inventory but the sum of the two can exceed max_unit. This will lead to invalid allocation candidate, i.e. an allocation candidate that will be rejected by the POST /allocations API call later on.\n\nHowever other inventory constraints seems OK:\n* step_size: if each individual allocation request is a multiple of the step_size then the sum of them is also multiple of the step_size\n* min_size: if each allocation request is bigger than min_size then the sum of them is also bigger than min_size\n* allocation_ratio: capacity is defined as: \n\n    int((usage[\u0027total\u0027] - usage[\u0027reserved\u0027]) * allocation_ratio)\n\ntherefore this condition already calculates with allocation_ratio properly\n* reserved: already calculated in the used value","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3658,"context_line":"    for arr in areq.resource_requests:"},{"line_number":3659,"context_line":"        key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3660,"context_line":"        psum_res \u003d psum_res_by_rp_rc[key]"},{"line_number":3661,"context_line":"        if psum_res.used + arr.amount \u003e psum_res.capacity:"},{"line_number":3662,"context_line":"            return True"},{"line_number":3663,"context_line":"    return False"},{"line_number":3664,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_e998e5c0","line":3661,"in_reply_to":"9f6a8fd7_c6987076","updated":"2018-04-23 18:43:26.000000000","message":"Rats.  I was trying to avoid calling back into the inventory database.\n\nExcellent observation, though.  I\u0027ll have to noodle it...\n\n[Later] Easy enough to add max_unit to ProviderSummaryResource, done.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3692,"context_line":"    # areq_lists_by_anchor \u003d"},{"line_number":3693,"context_line":"    #   { anchor_root_provider_uuid: {"},{"line_number":3694,"context_line":"    #         \u0027\u0027: [AllocationRequest, ...],   \\  This dict must contain"},{"line_number":3695,"context_line":"    #         \u00271\u0027: [AllocationRequest, ...],   \\ exactly one entry per"},{"line_number":3696,"context_line":"    #         ...                              / suffix to be viable. That"},{"line_number":3697,"context_line":"    #         \u002742\u0027: [AllocationRequest, ...], /  filtering is done later."},{"line_number":3698,"context_line":"    #     },"},{"line_number":3699,"context_line":"    #     ..."}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_4659c032","line":3696,"range":{"start_line":3695,"start_character":48,"end_line":3696,"end_character":69},"updated":"2018-04-21 14:45:50.000000000","message":"Exactly one or at least one? L3689 says at least one.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3692,"context_line":"    # areq_lists_by_anchor \u003d"},{"line_number":3693,"context_line":"    #   { anchor_root_provider_uuid: {"},{"line_number":3694,"context_line":"    #         \u0027\u0027: [AllocationRequest, ...],   \\  This dict must contain"},{"line_number":3695,"context_line":"    #         \u00271\u0027: [AllocationRequest, ...],   \\ exactly one entry per"},{"line_number":3696,"context_line":"    #         ...                              / suffix to be viable. That"},{"line_number":3697,"context_line":"    #         \u002742\u0027: [AllocationRequest, ...], /  filtering is done later."},{"line_number":3698,"context_line":"    #     },"},{"line_number":3699,"context_line":"    #     ..."}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_a98e6d76","line":3696,"range":{"start_line":3695,"start_character":48,"end_line":3696,"end_character":69},"in_reply_to":"9f6a8fd7_4659c032","updated":"2018-04-23 18:43:26.000000000","message":"It\u0027s correct, if confusing.  The dict must contain *exactly* one entry per suffix; and that entry is a list which must contain *at least one* AllocationRequest.  I reworded slightly; hopefully it\u0027s clearer now.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3698,"context_line":"    #     },"},{"line_number":3699,"context_line":"    #     ..."},{"line_number":3700,"context_line":"    #   }"},{"line_number":3701,"context_line":"    areq_lists_by_anchor \u003d collections.defaultdict(collections.defaultdict)"},{"line_number":3702,"context_line":"    # Save off all the provider summaries lists - we\u0027ll use \u0027em later."},{"line_number":3703,"context_line":"    all_psums \u003d []"},{"line_number":3704,"context_line":"    # Construct a dict, keyed by resource provider + resource class, of"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_467220af","line":3701,"range":{"start_line":3701,"start_character":27,"end_line":3701,"end_character":75},"updated":"2018-04-21 14:45:50.000000000","message":"If you do:\n\n    defaultdict(lambda: defaultdict(list))\n\nthen you can skip the \u0027if\u0027 at L3711","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3698,"context_line":"    #     },"},{"line_number":3699,"context_line":"    #     ..."},{"line_number":3700,"context_line":"    #   }"},{"line_number":3701,"context_line":"    areq_lists_by_anchor \u003d collections.defaultdict(collections.defaultdict)"},{"line_number":3702,"context_line":"    # Save off all the provider summaries lists - we\u0027ll use \u0027em later."},{"line_number":3703,"context_line":"    all_psums \u003d []"},{"line_number":3704,"context_line":"    # Construct a dict, keyed by resource provider + resource class, of"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_c98ba165","line":3701,"range":{"start_line":3701,"start_character":27,"end_line":3701,"end_character":75},"in_reply_to":"9f6a8fd7_467220af","updated":"2018-04-23 18:43:26.000000000","message":"Ah, yes, thanks.  I tried defaultdict(defaultdict(list)) which of course didn\u0027t work.  I figured out lambda later, somewhere else, but didn\u0027t bring it back here.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3712,"context_line":"                areq_lists_by_anchor[anchor][suffix] \u003d []"},{"line_number":3713,"context_line":"            areq_lists_by_anchor[anchor][suffix].append(areq)"},{"line_number":3714,"context_line":"        for psum in psums:"},{"line_number":3715,"context_line":"            all_psums.append(psum)"},{"line_number":3716,"context_line":"            rp_uuid \u003d psum.resource_provider.uuid"},{"line_number":3717,"context_line":"            for psum_res in psum.resources:"},{"line_number":3718,"context_line":"                key \u003d \u0027_\u0027.join([rp_uuid, psum_res.resource_class])"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_0602e83d","line":3715,"updated":"2018-04-21 14:45:50.000000000","message":"I think we add provider summary about a single RP more than once to the all_psums list if an RP is matched to more than one resource request group.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3712,"context_line":"                areq_lists_by_anchor[anchor][suffix] \u003d []"},{"line_number":3713,"context_line":"            areq_lists_by_anchor[anchor][suffix].append(areq)"},{"line_number":3714,"context_line":"        for psum in psums:"},{"line_number":3715,"context_line":"            all_psums.append(psum)"},{"line_number":3716,"context_line":"            rp_uuid \u003d psum.resource_provider.uuid"},{"line_number":3717,"context_line":"            for psum_res in psum.resources:"},{"line_number":3718,"context_line":"                key \u003d \u0027_\u0027.join([rp_uuid, psum_res.resource_class])"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_29f01dfd","line":3715,"in_reply_to":"9f6a8fd7_0602e83d","updated":"2018-04-23 18:43:26.000000000","message":"Until/unless we implement placement-return-all-resources, the summaries could be different (contain different combinations of the provider\u0027s resource classes).  There\u0027s still a possibility of duplication, but I figured this would probably be more efficient than making a set() out of it and having to calculate the hash of each ProviderSummary as we go.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8d8958723d99a389a5ee93129dd3c26c5960ea7d","unresolved":false,"context_lines":[{"line_number":3712,"context_line":"                areq_lists_by_anchor[anchor][suffix] \u003d []"},{"line_number":3713,"context_line":"            areq_lists_by_anchor[anchor][suffix].append(areq)"},{"line_number":3714,"context_line":"        for psum in psums:"},{"line_number":3715,"context_line":"            all_psums.append(psum)"},{"line_number":3716,"context_line":"            rp_uuid \u003d psum.resource_provider.uuid"},{"line_number":3717,"context_line":"            for psum_res in psum.resources:"},{"line_number":3718,"context_line":"                key \u003d \u0027_\u0027.join([rp_uuid, psum_res.resource_class])"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_f8e8887c","line":3715,"in_reply_to":"9f6a8fd7_29f01dfd","updated":"2018-04-24 09:09:16.000000000","message":"Ahh I missed that the same provider can have different summary from different group perspective. You are right we need to collect all the variations and merge them later.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3715,"context_line":"            all_psums.append(psum)"},{"line_number":3716,"context_line":"            rp_uuid \u003d psum.resource_provider.uuid"},{"line_number":3717,"context_line":"            for psum_res in psum.resources:"},{"line_number":3718,"context_line":"                key \u003d \u0027_\u0027.join([rp_uuid, psum_res.resource_class])"},{"line_number":3719,"context_line":"                psum_res_by_rp_rc[key] \u003d psum_res"},{"line_number":3720,"context_line":""},{"line_number":3721,"context_line":"    # Create all combinations picking one AllocationRequest from each list"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_e6d01422","line":3718,"range":{"start_line":3718,"start_character":1,"end_line":3718,"end_character":66},"updated":"2018-04-21 14:45:50.000000000","message":"this could be simplified to:\n\n    key \u003d (rp_uuid, psum_res.resource_class)\n\nbecause a tuple of hashables is hashable.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3715,"context_line":"            all_psums.append(psum)"},{"line_number":3716,"context_line":"            rp_uuid \u003d psum.resource_provider.uuid"},{"line_number":3717,"context_line":"            for psum_res in psum.resources:"},{"line_number":3718,"context_line":"                key \u003d \u0027_\u0027.join([rp_uuid, psum_res.resource_class])"},{"line_number":3719,"context_line":"                psum_res_by_rp_rc[key] \u003d psum_res"},{"line_number":3720,"context_line":""},{"line_number":3721,"context_line":"    # Create all combinations picking one AllocationRequest from each list"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_49f551ec","line":3718,"range":{"start_line":3718,"start_character":1,"end_line":3718,"end_character":66},"in_reply_to":"9f6a8fd7_e6d01422","updated":"2018-04-23 18:43:26.000000000","message":"It should have just been a call to _rp_rc_key.  Fixed.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3728,"context_line":"        # *all* suffixes (i.e. all RequestGroups)"},{"line_number":3729,"context_line":"        if set(areq_lists_by_suffix) !\u003d all_suffixes:"},{"line_number":3730,"context_line":"            continue"},{"line_number":3731,"context_line":"        for areq_list in itertools.product("},{"line_number":3732,"context_line":"                *list(areq_lists_by_suffix.values())):"},{"line_number":3733,"context_line":"            if not _satisfies_group_policy("},{"line_number":3734,"context_line":"                    areq_list, group_policy, num_granular_groups):"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_c6eab0d6","line":3731,"range":{"start_line":3731,"start_character":12,"end_line":3731,"end_character":21},"updated":"2018-04-21 14:45:50.000000000","message":"note to myself: areq_list is one allocation candidate produced by taking one allocation request for each resource request group.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3728,"context_line":"        # *all* suffixes (i.e. all RequestGroups)"},{"line_number":3729,"context_line":"        if set(areq_lists_by_suffix) !\u003d all_suffixes:"},{"line_number":3730,"context_line":"            continue"},{"line_number":3731,"context_line":"        for areq_list in itertools.product("},{"line_number":3732,"context_line":"                *list(areq_lists_by_suffix.values())):"},{"line_number":3733,"context_line":"            if not _satisfies_group_policy("},{"line_number":3734,"context_line":"                    areq_list, group_policy, num_granular_groups):"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_4a7c4d1e","line":3731,"range":{"start_line":3731,"start_character":12,"end_line":3731,"end_character":21},"in_reply_to":"9f6a8fd7_c6eab0d6","updated":"2018-04-23 18:43:26.000000000","message":"I owed Ed some pretty pictures and extra comments here too - see if it helps.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3729,"context_line":"        if set(areq_lists_by_suffix) !\u003d all_suffixes:"},{"line_number":3730,"context_line":"            continue"},{"line_number":3731,"context_line":"        for areq_list in itertools.product("},{"line_number":3732,"context_line":"                *list(areq_lists_by_suffix.values())):"},{"line_number":3733,"context_line":"            if not _satisfies_group_policy("},{"line_number":3734,"context_line":"                    areq_list, group_policy, num_granular_groups):"},{"line_number":3735,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_e6e7b411","line":3732,"range":{"start_line":3732,"start_character":22,"end_line":3732,"end_character":51},"updated":"2018-04-21 14:45:50.000000000","message":"Note to myself: This is the point where we loose the information about which resource request group is fulfilled by which AllocationRequest in a allocation candidate returned. Therefore this is the place where we could change the algorithm to keep this information and eventually send it back as part of the allocation_candidate response. So that nova could know which piece of bandwidth resource is allocated for which neutron port. This information could be pretty useful for the network bandwidth provider spec.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3729,"context_line":"        if set(areq_lists_by_suffix) !\u003d all_suffixes:"},{"line_number":3730,"context_line":"            continue"},{"line_number":3731,"context_line":"        for areq_list in itertools.product("},{"line_number":3732,"context_line":"                *list(areq_lists_by_suffix.values())):"},{"line_number":3733,"context_line":"            if not _satisfies_group_policy("},{"line_number":3734,"context_line":"                    areq_list, group_policy, num_granular_groups):"},{"line_number":3735,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_6a327160","line":3732,"range":{"start_line":3732,"start_character":22,"end_line":3732,"end_character":51},"in_reply_to":"9f6a8fd7_e6e7b411","updated":"2018-04-23 18:43:26.000000000","message":"True (added some comments).\n\nNote to self: Add a \"suffix\" field to the AllocationRequestResource object to facilitate that.\n\n(But btw, would have to add \"suffix\" to AllocationRequest as well - right now I\u0027m just using use_same_provider while group_policy is \"global\".)","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3740,"context_line":"            # folded together.  So do a final capacity check/filter."},{"line_number":3741,"context_line":"            if _exceeds_capacity(areq, psum_res_by_rp_rc):"},{"line_number":3742,"context_line":"                continue"},{"line_number":3743,"context_line":"            # TODO(efried): Need a final \"forbidden traits\" filter too."},{"line_number":3744,"context_line":"            areqs.append(areq)"},{"line_number":3745,"context_line":""},{"line_number":3746,"context_line":"    # It\u0027s possible we\u0027ve filtered out everything.  If so, short out."}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_4686a015","line":3743,"range":{"start_line":3743,"start_character":12,"end_line":3743,"end_character":71},"updated":"2018-04-21 14:45:50.000000000","message":"I don\u0027t think so. If one resource request group had forbidden trait then the individual query made sure (has to make sure) that the group is satisfied from an RP without such trait. \nIf another resource request group in the same query satisfied from an RP with such trait that does not mean we have to invalidate the candidate. The forbidden trait filter is local to the group having the forbidden trait specified.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3740,"context_line":"            # folded together.  So do a final capacity check/filter."},{"line_number":3741,"context_line":"            if _exceeds_capacity(areq, psum_res_by_rp_rc):"},{"line_number":3742,"context_line":"                continue"},{"line_number":3743,"context_line":"            # TODO(efried): Need a final \"forbidden traits\" filter too."},{"line_number":3744,"context_line":"            areqs.append(areq)"},{"line_number":3745,"context_line":""},{"line_number":3746,"context_line":"    # It\u0027s possible we\u0027ve filtered out everything.  If so, short out."}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_7296faf2","line":3743,"range":{"start_line":3743,"start_character":12,"end_line":3743,"end_character":71},"in_reply_to":"9f6a8fd7_4686a015","updated":"2018-04-23 18:43:26.000000000","message":"You\u0027re right.  I hadn\u0027t been thinking of invalidating the whole candidate based on a forbidden trait existing in an AllocationRequest satisfied by a different RequestGroup.  What I had been thinking (but hadn\u0027t thought all the way through) was if we satisfied one RequestGroup *without* a forbidden trait from RP X, and then satisfied a different RequestGroup *with* a forbidden trait also from RP X, and then combined them.  But the latter couldn\u0027t happen because the forbidden trait would stop us from landing on RP X for that piece anyway.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3769,"context_line":"    psums_by_rp \u003d {}"},{"line_number":3770,"context_line":"    for psum in all_psums:"},{"line_number":3771,"context_line":"        rp_uuid \u003d psum.resource_provider.uuid"},{"line_number":3772,"context_line":"        if rp_uuid not in psums_by_rp:"},{"line_number":3773,"context_line":"            psums_by_rp[rp_uuid] \u003d ProviderSummary("},{"line_number":3774,"context_line":"                resource_provider\u003dpsum.resource_provider, resources\u003d[],"},{"line_number":3775,"context_line":"                # Should always be the same; no need to check/update below."}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_c6f71059","line":3772,"range":{"start_line":3772,"start_character":8,"end_line":3772,"end_character":38},"updated":"2018-04-21 14:45:50.000000000","message":"here we can already filter for just those rp_uuids that are also in the rcs_by_rp as those are the only summaries we actually need for the final candidates.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3769,"context_line":"    psums_by_rp \u003d {}"},{"line_number":3770,"context_line":"    for psum in all_psums:"},{"line_number":3771,"context_line":"        rp_uuid \u003d psum.resource_provider.uuid"},{"line_number":3772,"context_line":"        if rp_uuid not in psums_by_rp:"},{"line_number":3773,"context_line":"            psums_by_rp[rp_uuid] \u003d ProviderSummary("},{"line_number":3774,"context_line":"                resource_provider\u003dpsum.resource_provider, resources\u003d[],"},{"line_number":3775,"context_line":"                # Should always be the same; no need to check/update below."}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_cac4ddf7","line":3772,"range":{"start_line":3772,"start_character":8,"end_line":3772,"end_character":38},"in_reply_to":"9f6a8fd7_c6f71059","updated":"2018-04-23 18:43:26.000000000","message":"Yeah, thanks - \"already\" - I don\u0027t think I was filtering these out at all.  So we would likely end up with some \"empty\" ProviderSummary objects (no ProviderSummaryResource entries).  Fixed.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3777,"context_line":"        # NOTE(efried): To subsume blueprint placement-return-all-resources"},{"line_number":3778,"context_line":"        # replace this loop with:"},{"line_number":3779,"context_line":"        # psums_by_rp[rp_uuid].resources \u003d psum.resources"},{"line_number":3780,"context_line":"        resources \u003d set(psums_by_rp[rp_uuid].resources)"},{"line_number":3781,"context_line":"        for psumres in psum.resources:"},{"line_number":3782,"context_line":"            if psumres.resource_class in rcs_by_rp[rp_uuid]:"},{"line_number":3783,"context_line":"                resources.add(psumres)"}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_c670700b","line":3780,"range":{"start_line":3780,"start_character":8,"end_line":3780,"end_character":17},"updated":"2018-04-21 14:45:50.000000000","message":"note to myself: this resources is an alias to the psums_by_rp[rp_uuid].resources which is initialized to [] at L3774","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":3781,"context_line":"        for psumres in psum.resources:"},{"line_number":3782,"context_line":"            if psumres.resource_class in rcs_by_rp[rp_uuid]:"},{"line_number":3783,"context_line":"                resources.add(psumres)"},{"line_number":3784,"context_line":"        psums_by_rp[rp_uuid].resources \u003d list(resources)"},{"line_number":3785,"context_line":""},{"line_number":3786,"context_line":"    return areqs, list(psums_by_rp.values())"},{"line_number":3787,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_869b5816","line":3784,"range":{"start_line":3784,"start_character":8,"end_line":3784,"end_character":56},"updated":"2018-04-21 14:45:50.000000000","message":"Why we need this?\nI think psums_by_rp[rp_uuid].resources points to the same list as resources.\nAlso resources is already a list from L3774","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":3781,"context_line":"        for psumres in psum.resources:"},{"line_number":3782,"context_line":"            if psumres.resource_class in rcs_by_rp[rp_uuid]:"},{"line_number":3783,"context_line":"                resources.add(psumres)"},{"line_number":3784,"context_line":"        psums_by_rp[rp_uuid].resources \u003d list(resources)"},{"line_number":3785,"context_line":""},{"line_number":3786,"context_line":"    return areqs, list(psums_by_rp.values())"},{"line_number":3787,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_fe5de214","line":3784,"range":{"start_line":3784,"start_character":8,"end_line":3784,"end_character":56},"in_reply_to":"9f6a8fd7_869b5816","updated":"2018-04-23 18:43:26.000000000","message":"This weirdness (L3780-4) is because the original ProviderSummary won\u0027t necessarily include *all* resources (until bp placement-return-all-resources happens).  We know that the combination of *all* ProviderSummary objects will contain all the ProviderSummaryResource we need.  So this chunk\n- peels out whatever we\u0027ve accumulated so far (psums_by_rp[rp_uuid].resources);\n- converts it to a set (L3780) so we don\u0027t end up with duplicates\n- adds in any of the ProviderSummaryResource entries (L3781-3) for which we identified a resource class in L3760-3;\n- and then converts back to a list (L3784) because that\u0027s what ProviderSummary.resources expects.\n\nI don\u0027t *think* I can avoid L3784 because L3780 does a copy-out from the ProviderSummary object.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"cfe4a76600778135d8cf0e44df42299240c7c984","unresolved":false,"context_lines":[{"line_number":3781,"context_line":"        for psumres in psum.resources:"},{"line_number":3782,"context_line":"            if psumres.resource_class in rcs_by_rp[rp_uuid]:"},{"line_number":3783,"context_line":"                resources.add(psumres)"},{"line_number":3784,"context_line":"        psums_by_rp[rp_uuid].resources \u003d list(resources)"},{"line_number":3785,"context_line":""},{"line_number":3786,"context_line":"    return areqs, list(psums_by_rp.values())"},{"line_number":3787,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"9f6a8fd7_eed01ecc","line":3784,"range":{"start_line":3784,"start_character":8,"end_line":3784,"end_character":56},"in_reply_to":"9f6a8fd7_fe5de214","updated":"2018-05-02 15:30:57.000000000","message":"You are right. I missed the set() call in L3780.","commit_id":"4b157561874e143900f557c92171a2cf9bd45990"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"cfe4a76600778135d8cf0e44df42299240c7c984","unresolved":false,"context_lines":[{"line_number":3763,"context_line":"                _(\"Expected every AllocationRequest in `deflate` to have the \""},{"line_number":3764,"context_line":"                  \"same anchor!\"))"},{"line_number":3765,"context_line":"        for arr in areq.resource_requests:"},{"line_number":3766,"context_line":"            key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3767,"context_line":"            if key not in arrs_by_rp_rc:"},{"line_number":3768,"context_line":"                arrs_by_rp_rc[key] \u003d copy.deepcopy(arr)"},{"line_number":3769,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":33,"id":"9f6a8fd7_6e02ceb6","line":3766,"range":{"start_line":3766,"start_character":18,"end_line":3766,"end_character":28},"updated":"2018-05-02 15:30:57.000000000","message":"nit: Now you can simply inline _rp_rc_key() by deleting the name of the function at every place you call it and you lose nothing :)","commit_id":"f219736f70bc87a51551121d6846ca143762db70"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"81f6a63631e5a73535b267f7eebe1f96c5ef463d","unresolved":false,"context_lines":[{"line_number":3763,"context_line":"                _(\"Expected every AllocationRequest in `deflate` to have the \""},{"line_number":3764,"context_line":"                  \"same anchor!\"))"},{"line_number":3765,"context_line":"        for arr in areq.resource_requests:"},{"line_number":3766,"context_line":"            key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3767,"context_line":"            if key not in arrs_by_rp_rc:"},{"line_number":3768,"context_line":"                arrs_by_rp_rc[key] \u003d copy.deepcopy(arr)"},{"line_number":3769,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":33,"id":"5f7c97a3_affcc53e","line":3766,"range":{"start_line":3766,"start_character":18,"end_line":3766,"end_character":28},"in_reply_to":"9f6a8fd7_6d173347","updated":"2018-05-03 08:13:10.000000000","message":"You are right again. :) I should not try to do code review with my late afternoon brain. I agree not to inline it.","commit_id":"f219736f70bc87a51551121d6846ca143762db70"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"706ef4d224d19e71bf9d3cf3672e000047c55645","unresolved":false,"context_lines":[{"line_number":3763,"context_line":"                _(\"Expected every AllocationRequest in `deflate` to have the \""},{"line_number":3764,"context_line":"                  \"same anchor!\"))"},{"line_number":3765,"context_line":"        for arr in areq.resource_requests:"},{"line_number":3766,"context_line":"            key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3767,"context_line":"            if key not in arrs_by_rp_rc:"},{"line_number":3768,"context_line":"                arrs_by_rp_rc[key] \u003d copy.deepcopy(arr)"},{"line_number":3769,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":33,"id":"9f6a8fd7_6d173347","line":3766,"range":{"start_line":3766,"start_character":18,"end_line":3766,"end_character":28},"in_reply_to":"9f6a8fd7_6e02ceb6","updated":"2018-05-02 16:08:33.000000000","message":"Except for the fact that it uses the UUID of the resource provider.  I could inline that and it would still be a reduction in chars.  But having the method enforces consistency and protects at least somewhat from changing it in some places and missing others.","commit_id":"f219736f70bc87a51551121d6846ca143762db70"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"cfe4a76600778135d8cf0e44df42299240c7c984","unresolved":false,"context_lines":[{"line_number":3829,"context_line":"    for arr in areq.resource_requests:"},{"line_number":3830,"context_line":"        key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3831,"context_line":"        psum_res \u003d psum_res_by_rp_rc[key]"},{"line_number":3832,"context_line":"        if psum_res.used + arr.amount \u003e psum_res.capacity:"},{"line_number":3833,"context_line":"            return True"},{"line_number":3834,"context_line":"        if arr.amount \u003e psum_res.max_unit:"},{"line_number":3835,"context_line":"            return True"},{"line_number":3836,"context_line":"    return False"},{"line_number":3837,"context_line":""},{"line_number":3838,"context_line":""}],"source_content_type":"text/x-python","patch_set":33,"id":"9f6a8fd7_6eac0e8c","line":3835,"range":{"start_line":3832,"start_character":0,"end_line":3835,"end_character":23},"updated":"2018-05-02 15:30:57.000000000","message":"I think this is still broken as L3832 does not verify max_unit but allows the function to return True. You have to combine the two conditions from L3832 and L3834 with AND and return True only if the full condition is True.\n\nDo you have test for the case when the \n\n  psum_res.used + arr.amount \u003e psum_res.capacity\n\nis True but\n\n   arr.amount \u003e psum_res.max_unit\n\nis False?","commit_id":"f219736f70bc87a51551121d6846ca143762db70"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"e7fb63755918530677e849c0c0577f5f11d4d1c8","unresolved":false,"context_lines":[{"line_number":3829,"context_line":"    for arr in areq.resource_requests:"},{"line_number":3830,"context_line":"        key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3831,"context_line":"        psum_res \u003d psum_res_by_rp_rc[key]"},{"line_number":3832,"context_line":"        if psum_res.used + arr.amount \u003e psum_res.capacity:"},{"line_number":3833,"context_line":"            return True"},{"line_number":3834,"context_line":"        if arr.amount \u003e psum_res.max_unit:"},{"line_number":3835,"context_line":"            return True"},{"line_number":3836,"context_line":"    return False"},{"line_number":3837,"context_line":""},{"line_number":3838,"context_line":""}],"source_content_type":"text/x-python","patch_set":33,"id":"9f6a8fd7_0e3eb2d9","line":3835,"range":{"start_line":3832,"start_character":0,"end_line":3835,"end_character":23},"in_reply_to":"9f6a8fd7_6eac0e8c","updated":"2018-05-02 15:33:27.000000000","message":"I\u0027m wrong. True is returned when the group exceeds capacity. So we have to return True for each condition.","commit_id":"f219736f70bc87a51551121d6846ca143762db70"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"68168401c80f54eba41fa24b7a18d7949bee8032","unresolved":false,"context_lines":[{"line_number":4055,"context_line":"    def _get_by_one_request(context, request):"},{"line_number":4056,"context_line":"        \"\"\"Get allocation candidates for one RequestGroup."},{"line_number":4057,"context_line":""},{"line_number":4058,"context_line":"        Must be called from within an api_context_manager context."},{"line_number":4059,"context_line":""},{"line_number":4060,"context_line":"        :param context: Nova RequestContext."},{"line_number":4061,"context_line":"        :param request: One nova.api.openstack.placement.util.RequestGroup"}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_346fa9c6","line":4058,"range":{"start_line":4058,"start_character":38,"end_line":4058,"end_character":57},"updated":"2018-05-03 11:28:20.000000000","message":"Does it need api_context_manager.reader context or any api_context_manager?","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":4055,"context_line":"    def _get_by_one_request(context, request):"},{"line_number":4056,"context_line":"        \"\"\"Get allocation candidates for one RequestGroup."},{"line_number":4057,"context_line":""},{"line_number":4058,"context_line":"        Must be called from within an api_context_manager context."},{"line_number":4059,"context_line":""},{"line_number":4060,"context_line":"        :param context: Nova RequestContext."},{"line_number":4061,"context_line":"        :param request: One nova.api.openstack.placement.util.RequestGroup"}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_723f71d6","line":4058,"range":{"start_line":4058,"start_character":38,"end_line":4058,"end_character":57},"in_reply_to":"5f7c97a3_346fa9c6","updated":"2018-05-04 14:48:31.000000000","message":"Yeah, I\u0027m sure I meant to say reader (though a writer would work too).  Will fix.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"75c8849facc5b28d090f4f16370b38fd76945390","unresolved":false,"context_lines":[{"line_number":4086,"context_line":"        member_of \u003d getattr(request, \"member_of\", \"\")"},{"line_number":4087,"context_line":""},{"line_number":4088,"context_line":"        if not request.use_same_provider:"},{"line_number":4089,"context_line":"            # TODO(jaypipes): The check/callout to handle trees goes here."},{"line_number":4090,"context_line":"            # Build a dict, keyed by resource class internal ID, of lists of"},{"line_number":4091,"context_line":"            # internal IDs of resource providers that share some inventory for"},{"line_number":4092,"context_line":"            # each resource class requested."},{"line_number":4093,"context_line":"            # TODO(jaypipes): Consider caching this for some amount of time"},{"line_number":4094,"context_line":"            # since sharing providers generally don\u0027t change often and here we"},{"line_number":4095,"context_line":"            # aren\u0027t concerned with how *much* inventory/capacity the sharing"},{"line_number":4096,"context_line":"            # provider has, only that it is sharing *some* inventory of a"},{"line_number":4097,"context_line":"            # particular resource class."},{"line_number":4098,"context_line":"            sharing_providers \u003d {"},{"line_number":4099,"context_line":"                rc_id: _get_providers_with_shared_capacity(context, rc_id,"},{"line_number":4100,"context_line":"                                                           amount)"},{"line_number":4101,"context_line":"                for rc_id, amount in resources.items()"},{"line_number":4102,"context_line":"            }"},{"line_number":4103,"context_line":"            # We check this here as an optimization: if we have no sharing"},{"line_number":4104,"context_line":"            # providers, we fall through to the (simpler, more efficient)"},{"line_number":4105,"context_line":"            # algorithm below."}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_064cbac5","line":4102,"range":{"start_line":4089,"start_character":0,"end_line":4102,"end_character":13},"updated":"2018-05-03 21:23:13.000000000","message":"There is no reason to re-execute this for each request group. The idea here was to do a single (potentially cacheable) call for each resource class involved in the request to get the providers sharing that resource class.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":4086,"context_line":"        member_of \u003d getattr(request, \"member_of\", \"\")"},{"line_number":4087,"context_line":""},{"line_number":4088,"context_line":"        if not request.use_same_provider:"},{"line_number":4089,"context_line":"            # TODO(jaypipes): The check/callout to handle trees goes here."},{"line_number":4090,"context_line":"            # Build a dict, keyed by resource class internal ID, of lists of"},{"line_number":4091,"context_line":"            # internal IDs of resource providers that share some inventory for"},{"line_number":4092,"context_line":"            # each resource class requested."},{"line_number":4093,"context_line":"            # TODO(jaypipes): Consider caching this for some amount of time"},{"line_number":4094,"context_line":"            # since sharing providers generally don\u0027t change often and here we"},{"line_number":4095,"context_line":"            # aren\u0027t concerned with how *much* inventory/capacity the sharing"},{"line_number":4096,"context_line":"            # provider has, only that it is sharing *some* inventory of a"},{"line_number":4097,"context_line":"            # particular resource class."},{"line_number":4098,"context_line":"            sharing_providers \u003d {"},{"line_number":4099,"context_line":"                rc_id: _get_providers_with_shared_capacity(context, rc_id,"},{"line_number":4100,"context_line":"                                                           amount)"},{"line_number":4101,"context_line":"                for rc_id, amount in resources.items()"},{"line_number":4102,"context_line":"            }"},{"line_number":4103,"context_line":"            # We check this here as an optimization: if we have no sharing"},{"line_number":4104,"context_line":"            # providers, we fall through to the (simpler, more efficient)"},{"line_number":4105,"context_line":"            # algorithm below."}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_bd03910d","line":4102,"range":{"start_line":4089,"start_character":0,"end_line":4102,"end_character":13},"in_reply_to":"5f7c97a3_064cbac5","updated":"2018-05-04 14:48:31.000000000","message":"A cache would have to be at the level of the caller of this method, which means an extra param.  (This isn\u0027t the right patch in which to implement a global, timed cache as suggested by the TODO.)\n\nEach cache entry would only be worthwhile for one rc+amount pair (we can\u0027t even factor out by max(amounts) because we have to do min unit and step size checks).\n\nIs the occurrence of duplicated rc+amount pairs in a single GET /a_c request likely to be frequent enough to warrant the extra logic involved there?\n\nEven if that answer is yes, would it be acceptable to do that refactoring in a fup?","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a82a06290927cf4af4dbb288e2415713cd280f2d","unresolved":false,"context_lines":[{"line_number":4154,"context_line":"                # Shortcut: If any one request resulted in no candidates, the"},{"line_number":4155,"context_line":"                # whole operation is shot."},{"line_number":4156,"context_line":"                return [], []"},{"line_number":4157,"context_line":"            # Mark each allocation request according to whether its"},{"line_number":4158,"context_line":"            # corresponding RequestGroup required it to be restricted to a"},{"line_number":4159,"context_line":"            # single provider.  We\u0027ll need this later to evaluate group_policy."},{"line_number":4160,"context_line":"            for areq in alloc_reqs:"},{"line_number":4161,"context_line":"                areq.use_same_provider \u003d request.use_same_provider"},{"line_number":4162,"context_line":"            candidates[suffix] \u003d alloc_reqs, summaries"},{"line_number":4163,"context_line":""},{"line_number":4164,"context_line":"        # At this point, each (alloc_requests, summary_obj) in `candidates` is"}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_5d083d27","line":4161,"range":{"start_line":4157,"start_character":0,"end_line":4161,"end_character":66},"updated":"2018-05-03 21:49:45.000000000","message":"This is an example of something that would not be necessary to do with the MatchSpec being passed to the various matching functions. The RequestGroup objects are passed to the various matching functions because they are a part of the MatchSpec object itself.\n\nTherefore, there\u0027s no reason to have an AllocationRequest.use_same_provider field.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3779,"context_line":"    return {r[0]: r[1] for r in ctx.session.execute(sel)}"},{"line_number":3780,"context_line":""},{"line_number":3781,"context_line":""},{"line_number":3782,"context_line":"def _rp_rc_key(rp, rc):"},{"line_number":3783,"context_line":"    \"\"\"Creates hashable key unique to a provider + resource class.\"\"\""},{"line_number":3784,"context_line":"    return rp.uuid, rc"},{"line_number":3785,"context_line":""},{"line_number":3786,"context_line":""},{"line_number":3787,"context_line":"def deflate(areqs):"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_1a0febe1","line":3784,"range":{"start_line":3782,"start_character":0,"end_line":3784,"end_character":22},"updated":"2018-05-08 15:47:40.000000000","message":"not sure this function is necessary.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3779,"context_line":"    return {r[0]: r[1] for r in ctx.session.execute(sel)}"},{"line_number":3780,"context_line":""},{"line_number":3781,"context_line":""},{"line_number":3782,"context_line":"def _rp_rc_key(rp, rc):"},{"line_number":3783,"context_line":"    \"\"\"Creates hashable key unique to a provider + resource class.\"\"\""},{"line_number":3784,"context_line":"    return rp.uuid, rc"},{"line_number":3785,"context_line":""},{"line_number":3786,"context_line":""},{"line_number":3787,"context_line":"def deflate(areqs):"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_65be8066","line":3784,"range":{"start_line":3782,"start_character":0,"end_line":3784,"end_character":22},"in_reply_to":"5f7c97a3_1a0febe1","updated":"2018-05-08 16:53:54.000000000","message":"Yeah, gibi and I talked about that previously: https://review.openstack.org/#/c/517757/33/nova/api/openstack/placement/objects/resource_provider.py@3766\n\nI can remove it if you feel strongly about it, but I would prefer to keep it for the reason explained there.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3784,"context_line":"    return rp.uuid, rc"},{"line_number":3785,"context_line":""},{"line_number":3786,"context_line":""},{"line_number":3787,"context_line":"def deflate(areqs):"},{"line_number":3788,"context_line":"    \"\"\"Consolidates a list of AllocationRequest into one."},{"line_number":3789,"context_line":""},{"line_number":3790,"context_line":"    :param areqs: A list containing one AllocationRequest for each input"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_faca2f6c","line":3787,"range":{"start_line":3787,"start_character":4,"end_line":3787,"end_character":11},"updated":"2018-05-08 15:47:40.000000000","message":"suggest renaming to consolidate_allocation_requests()","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3784,"context_line":"    return rp.uuid, rc"},{"line_number":3785,"context_line":""},{"line_number":3786,"context_line":""},{"line_number":3787,"context_line":"def deflate(areqs):"},{"line_number":3788,"context_line":"    \"\"\"Consolidates a list of AllocationRequest into one."},{"line_number":3789,"context_line":""},{"line_number":3790,"context_line":"    :param areqs: A list containing one AllocationRequest for each input"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_05722ce4","line":3787,"range":{"start_line":3787,"start_character":4,"end_line":3787,"end_character":11},"in_reply_to":"5f7c97a3_faca2f6c","updated":"2018-05-08 16:53:54.000000000","message":"Done, and oops, made it private, which I\u0027m sure I meant to do originally when I moved it out of merge_candidates.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3808,"context_line":"                _(\"Expected every AllocationRequest in `deflate` to have the \""},{"line_number":3809,"context_line":"                  \"same anchor!\"))"},{"line_number":3810,"context_line":"        for arr in areq.resource_requests:"},{"line_number":3811,"context_line":"            key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3812,"context_line":"            if key not in arrs_by_rp_rc:"},{"line_number":3813,"context_line":"                arrs_by_rp_rc[key] \u003d copy.deepcopy(arr)"},{"line_number":3814,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_9a021bb4","line":3811,"range":{"start_line":3811,"start_character":12,"end_line":3811,"end_character":71},"updated":"2018-05-08 15:47:40.000000000","message":"could just do:\n\n key \u003d (arr.resource_provider.uuid, arr.resource_class)","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3808,"context_line":"                _(\"Expected every AllocationRequest in `deflate` to have the \""},{"line_number":3809,"context_line":"                  \"same anchor!\"))"},{"line_number":3810,"context_line":"        for arr in areq.resource_requests:"},{"line_number":3811,"context_line":"            key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3812,"context_line":"            if key not in arrs_by_rp_rc:"},{"line_number":3813,"context_line":"                arrs_by_rp_rc[key] \u003d copy.deepcopy(arr)"},{"line_number":3814,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_a580188d","line":3811,"range":{"start_line":3811,"start_character":12,"end_line":3811,"end_character":71},"in_reply_to":"5f7c97a3_9a021bb4","updated":"2018-05-08 16:53:54.000000000","message":"right, see above.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3825,"context_line":"    AllocationRequest satisfies group_policy, as follows:"},{"line_number":3826,"context_line":""},{"line_number":3827,"context_line":"    * \"isolate\": Each AllocationRequest with use_same_provider\u003dTrue"},{"line_number":3828,"context_line":"                 is assumed to be satisfied by a single resource"},{"line_number":3829,"context_line":"                 provider.  If the \"isolate\" policy is in effect, each"},{"line_number":3830,"context_line":"                 such AllocationRequest must be satisfied by a *unique*"},{"line_number":3831,"context_line":"                 resource provider."}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_9aac5b8d","line":3828,"range":{"start_line":3828,"start_character":17,"end_line":3828,"end_character":30},"updated":"2018-05-08 15:47:40.000000000","message":"s/is assumed to/will/","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3825,"context_line":"    AllocationRequest satisfies group_policy, as follows:"},{"line_number":3826,"context_line":""},{"line_number":3827,"context_line":"    * \"isolate\": Each AllocationRequest with use_same_provider\u003dTrue"},{"line_number":3828,"context_line":"                 is assumed to be satisfied by a single resource"},{"line_number":3829,"context_line":"                 provider.  If the \"isolate\" policy is in effect, each"},{"line_number":3830,"context_line":"                 such AllocationRequest must be satisfied by a *unique*"},{"line_number":3831,"context_line":"                 resource provider."}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_e55ff03e","line":3828,"range":{"start_line":3828,"start_character":17,"end_line":3828,"end_character":30},"in_reply_to":"5f7c97a3_9aac5b8d","updated":"2018-05-08 16:53:54.000000000","message":"Done","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3845,"context_line":"        # group_policy\u003d\"none\" means no filtering"},{"line_number":3846,"context_line":"        return True"},{"line_number":3847,"context_line":""},{"line_number":3848,"context_line":"    # If isolation was requested, see if we need to filter this one out. We do"},{"line_number":3849,"context_line":"    # this by counting the number of unique resource providers in the"},{"line_number":3850,"context_line":"    # use_same_provider\u003dTrue groups.  This must match the number of"},{"line_number":3851,"context_line":"    # use_same_provider\u003dTrue RequestGroups in the input."}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_3a03c775","line":3848,"range":{"start_line":3848,"start_character":4,"end_line":3848,"end_character":72},"updated":"2018-05-08 15:47:40.000000000","message":"perhaps an earlier version of this code was modifying the areqs parameter (and thus there was some \"filtering\" going on). But the current code doesn\u0027t modify areqs and this sentence doesn\u0027t need to be here. This comment should just be:\n\n # The number of unique resource providers referenced in the\n # request groups having use_same_provider\u003dTrue must be equal\n # to the number of granular groups.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3845,"context_line":"        # group_policy\u003d\"none\" means no filtering"},{"line_number":3846,"context_line":"        return True"},{"line_number":3847,"context_line":""},{"line_number":3848,"context_line":"    # If isolation was requested, see if we need to filter this one out. We do"},{"line_number":3849,"context_line":"    # this by counting the number of unique resource providers in the"},{"line_number":3850,"context_line":"    # use_same_provider\u003dTrue groups.  This must match the number of"},{"line_number":3851,"context_line":"    # use_same_provider\u003dTrue RequestGroups in the input."}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_c502f40b","line":3848,"range":{"start_line":3848,"start_character":4,"end_line":3848,"end_character":72},"in_reply_to":"5f7c97a3_3a03c775","updated":"2018-05-08 16:53:54.000000000","message":"Done","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3859,"context_line":""},{"line_number":3860,"context_line":""},{"line_number":3861,"context_line":"def _exceeds_capacity(areq, psum_res_by_rp_rc):"},{"line_number":3862,"context_line":"    \"\"\"Checks a (deflated) AllocationRequest against the provider summaries to"},{"line_number":3863,"context_line":"    ensure that it does not exceed capacity."},{"line_number":3864,"context_line":""},{"line_number":3865,"context_line":"    Exceeding capacity can mean the total amount (already used plus this"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_faf46f89","line":3862,"range":{"start_line":3862,"start_character":17,"end_line":3862,"end_character":25},"updated":"2018-05-08 15:47:40.000000000","message":"consolidated","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3859,"context_line":""},{"line_number":3860,"context_line":""},{"line_number":3861,"context_line":"def _exceeds_capacity(areq, psum_res_by_rp_rc):"},{"line_number":3862,"context_line":"    \"\"\"Checks a (deflated) AllocationRequest against the provider summaries to"},{"line_number":3863,"context_line":"    ensure that it does not exceed capacity."},{"line_number":3864,"context_line":""},{"line_number":3865,"context_line":"    Exceeding capacity can mean the total amount (already used plus this"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_8002aa08","line":3862,"range":{"start_line":3862,"start_character":17,"end_line":3862,"end_character":25},"in_reply_to":"5f7c97a3_faf46f89","updated":"2018-05-08 16:53:54.000000000","message":"Done","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3872,"context_line":"    :return: True if areq exceeds capacity; False otherwise."},{"line_number":3873,"context_line":"    \"\"\""},{"line_number":3874,"context_line":"    for arr in areq.resource_requests:"},{"line_number":3875,"context_line":"        key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3876,"context_line":"        psum_res \u003d psum_res_by_rp_rc[key]"},{"line_number":3877,"context_line":"        if psum_res.used + arr.amount \u003e psum_res.capacity:"},{"line_number":3878,"context_line":"            return True"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_5a2b23ea","line":3875,"range":{"start_line":3875,"start_character":8,"end_line":3875,"end_character":67},"updated":"2018-05-08 15:47:40.000000000","message":"key \u003d (arr.resource_provider.uuid, arr.resource_class)","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3872,"context_line":"    :return: True if areq exceeds capacity; False otherwise."},{"line_number":3873,"context_line":"    \"\"\""},{"line_number":3874,"context_line":"    for arr in areq.resource_requests:"},{"line_number":3875,"context_line":"        key \u003d _rp_rc_key(arr.resource_provider, arr.resource_class)"},{"line_number":3876,"context_line":"        psum_res \u003d psum_res_by_rp_rc[key]"},{"line_number":3877,"context_line":"        if psum_res.used + arr.amount \u003e psum_res.capacity:"},{"line_number":3878,"context_line":"            return True"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_2009562b","line":3875,"range":{"start_line":3875,"start_character":8,"end_line":3875,"end_character":67},"in_reply_to":"5f7c97a3_5a2b23ea","updated":"2018-05-08 16:53:54.000000000","message":"see above.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3931,"context_line":"        for psum in psums:"},{"line_number":3932,"context_line":"            all_psums.append(psum)"},{"line_number":3933,"context_line":"            for psum_res in psum.resources:"},{"line_number":3934,"context_line":"                key \u003d _rp_rc_key("},{"line_number":3935,"context_line":"                        psum.resource_provider, psum_res.resource_class)"},{"line_number":3936,"context_line":"                psum_res_by_rp_rc[key] \u003d psum_res"},{"line_number":3937,"context_line":""},{"line_number":3938,"context_line":"    # Create all combinations picking one AllocationRequest from each list"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_7af37f74","line":3935,"range":{"start_line":3934,"start_character":16,"end_line":3935,"end_character":72},"updated":"2018-05-08 15:47:40.000000000","message":"key \u003d (psum.resource_provider.uuid, psum_res.resource_class)","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3931,"context_line":"        for psum in psums:"},{"line_number":3932,"context_line":"            all_psums.append(psum)"},{"line_number":3933,"context_line":"            for psum_res in psum.resources:"},{"line_number":3934,"context_line":"                key \u003d _rp_rc_key("},{"line_number":3935,"context_line":"                        psum.resource_provider, psum_res.resource_class)"},{"line_number":3936,"context_line":"                psum_res_by_rp_rc[key] \u003d psum_res"},{"line_number":3937,"context_line":""},{"line_number":3938,"context_line":"    # Create all combinations picking one AllocationRequest from each list"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_6028ae85","line":3935,"range":{"start_line":3934,"start_character":16,"end_line":3935,"end_character":72},"in_reply_to":"5f7c97a3_7af37f74","updated":"2018-05-08 16:53:54.000000000","message":"see above.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":3988,"context_line":"            # *independent* queries, it\u0027s possible that the combined result"},{"line_number":3989,"context_line":"            # now exceeds capacity where amounts of the same RP+RC were"},{"line_number":3990,"context_line":"            # folded together.  So do a final capacity check/filter."},{"line_number":3991,"context_line":"            if _exceeds_capacity(areq, psum_res_by_rp_rc):"},{"line_number":3992,"context_line":"                continue"},{"line_number":3993,"context_line":"            areqs.append(areq)"},{"line_number":3994,"context_line":""}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_baa6f752","line":3991,"updated":"2018-05-08 15:47:40.000000000","message":"Might be worth jamming a LOG.debug() line in here indicating that this particular resource class exceeded the capacity when considered as a consolidated amount across all request groups.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":3988,"context_line":"            # *independent* queries, it\u0027s possible that the combined result"},{"line_number":3989,"context_line":"            # now exceeds capacity where amounts of the same RP+RC were"},{"line_number":3990,"context_line":"            # folded together.  So do a final capacity check/filter."},{"line_number":3991,"context_line":"            if _exceeds_capacity(areq, psum_res_by_rp_rc):"},{"line_number":3992,"context_line":"                continue"},{"line_number":3993,"context_line":"            areqs.append(areq)"},{"line_number":3994,"context_line":""}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_e0aefee5","line":3991,"in_reply_to":"5f7c97a3_baa6f752","updated":"2018-05-08 16:53:54.000000000","message":"I considered that (and adding moar debug logs throughout).  In most cases including this one, what stopped me was how to display the allocation request.  Right now, str() produces not-very-helpful output.  Can I, in a followon, add __str__ methods to some of these quasi-ovos and add the debug logs then?","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ab030d65eda5b332b0c32678b103dd3f94364e7","unresolved":false,"context_lines":[{"line_number":3988,"context_line":"            # *independent* queries, it\u0027s possible that the combined result"},{"line_number":3989,"context_line":"            # now exceeds capacity where amounts of the same RP+RC were"},{"line_number":3990,"context_line":"            # folded together.  So do a final capacity check/filter."},{"line_number":3991,"context_line":"            if _exceeds_capacity(areq, psum_res_by_rp_rc):"},{"line_number":3992,"context_line":"                continue"},{"line_number":3993,"context_line":"            areqs.append(areq)"},{"line_number":3994,"context_line":""}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_eeb65a3e","line":3991,"in_reply_to":"5f7c97a3_d4ace78d","updated":"2018-05-15 22:31:18.000000000","message":"See https://review.openstack.org/568712","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4769f15df6937ae4cfea48969918306522439a50","unresolved":false,"context_lines":[{"line_number":3988,"context_line":"            # *independent* queries, it\u0027s possible that the combined result"},{"line_number":3989,"context_line":"            # now exceeds capacity where amounts of the same RP+RC were"},{"line_number":3990,"context_line":"            # folded together.  So do a final capacity check/filter."},{"line_number":3991,"context_line":"            if _exceeds_capacity(areq, psum_res_by_rp_rc):"},{"line_number":3992,"context_line":"                continue"},{"line_number":3993,"context_line":"            areqs.append(areq)"},{"line_number":3994,"context_line":""}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_d4ace78d","line":3991,"in_reply_to":"5f7c97a3_e0aefee5","updated":"2018-05-08 17:10:36.000000000","message":"yeah, totes.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":4098,"context_line":""},{"line_number":4099,"context_line":"    @staticmethod"},{"line_number":4100,"context_line":"    def _get_by_one_request(context, request):"},{"line_number":4101,"context_line":"        \"\"\"Get allocation candidates for one RequestGroup."},{"line_number":4102,"context_line":""},{"line_number":4103,"context_line":"        Must be called from within an api_context_manager.reader (or writer)"},{"line_number":4104,"context_line":"        context."},{"line_number":4105,"context_line":""},{"line_number":4106,"context_line":"        :param context: Nova RequestContext."},{"line_number":4107,"context_line":"        :param request: One nova.api.openstack.placement.util.RequestGroup"},{"line_number":4108,"context_line":"        :return: A tuple of (allocation_requests, provider_summaries)"},{"line_number":4109,"context_line":"                 satisfying `request`."},{"line_number":4110,"context_line":"        \"\"\""},{"line_number":4111,"context_line":"        # Transform resource string names to internal integer IDs"},{"line_number":4112,"context_line":"        resources \u003d {"},{"line_number":4113,"context_line":"            _RC_CACHE.id_from_string(key): value"},{"line_number":4114,"context_line":"            for key, value in request.resources.items()"},{"line_number":4115,"context_line":"        }"},{"line_number":4116,"context_line":""},{"line_number":4117,"context_line":"        # maps the trait name to the trait internal ID"},{"line_number":4118,"context_line":"        required_trait_map \u003d {}"},{"line_number":4119,"context_line":"        forbidden_trait_map \u003d {}"},{"line_number":4120,"context_line":"        for trait_map, traits in ("},{"line_number":4121,"context_line":"                (required_trait_map, request.required_traits),"},{"line_number":4122,"context_line":"                (forbidden_trait_map, request.forbidden_traits)):"},{"line_number":4123,"context_line":"            if traits:"},{"line_number":4124,"context_line":"                trait_map.update(_trait_ids_from_names(context, traits))"},{"line_number":4125,"context_line":"                # Double-check that we found a trait ID for each requested name"},{"line_number":4126,"context_line":"                if len(trait_map) !\u003d len(traits):"},{"line_number":4127,"context_line":"                    missing \u003d traits - set(trait_map)"},{"line_number":4128,"context_line":"                    raise exception.TraitNotFound(names\u003d\u0027, \u0027.join(missing))"},{"line_number":4129,"context_line":""},{"line_number":4130,"context_line":"        # Microversions prior to 1.21 will not have \u0027member_of\u0027 in the groups."},{"line_number":4131,"context_line":"        # This allows earlier microversions to continue to work."},{"line_number":4132,"context_line":"        member_of \u003d getattr(request, \"member_of\", \"\")"},{"line_number":4133,"context_line":""},{"line_number":4134,"context_line":"        if not request.use_same_provider:"},{"line_number":4135,"context_line":"            # TODO(jaypipes): The check/callout to handle trees goes here."},{"line_number":4136,"context_line":"            # Build a dict, keyed by resource class internal ID, of lists of"},{"line_number":4137,"context_line":"            # internal IDs of resource providers that share some inventory for"},{"line_number":4138,"context_line":"            # each resource class requested."},{"line_number":4139,"context_line":"            # TODO(jaypipes): Consider caching this for some amount of time"},{"line_number":4140,"context_line":"            # since sharing providers generally don\u0027t change often and here we"},{"line_number":4141,"context_line":"            # aren\u0027t concerned with how *much* inventory/capacity the sharing"},{"line_number":4142,"context_line":"            # provider has, only that it is sharing *some* inventory of a"},{"line_number":4143,"context_line":"            # particular resource class."},{"line_number":4144,"context_line":"            sharing_providers \u003d {"},{"line_number":4145,"context_line":"                rc_id: _get_providers_with_shared_capacity(context, rc_id,"},{"line_number":4146,"context_line":"                                                           amount)"},{"line_number":4147,"context_line":"                for rc_id, amount in resources.items()"},{"line_number":4148,"context_line":"            }"},{"line_number":4149,"context_line":"            # We check this here as an optimization: if we have no sharing"},{"line_number":4150,"context_line":"            # providers, we fall through to the (simpler, more efficient)"},{"line_number":4151,"context_line":"            # algorithm below."},{"line_number":4152,"context_line":"            if any(sharing_providers.values()):"},{"line_number":4153,"context_line":"                # Okay, we have to do it the hard way: the request may be"},{"line_number":4154,"context_line":"                # satisfied by one or more sharing providers as well as (maybe)"},{"line_number":4155,"context_line":"                # the non-sharing provider."},{"line_number":4156,"context_line":"                if required_trait_map:"},{"line_number":4157,"context_line":"                    # TODO(cdent): Now that there is also a forbidden_trait_map"},{"line_number":4158,"context_line":"                    # it should be possible to further optimize this attempt at"},{"line_number":4159,"context_line":"                    # a quick return, but we leave that to future patches for"},{"line_number":4160,"context_line":"                    # now."},{"line_number":4161,"context_line":"                    trait_rps \u003d _get_provider_ids_having_any_trait("},{"line_number":4162,"context_line":"                        context, required_trait_map)"},{"line_number":4163,"context_line":"                    if not trait_rps:"},{"line_number":4164,"context_line":"                        # If there aren\u0027t any providers that have any of the"},{"line_number":4165,"context_line":"                        # required traits, just exit early..."},{"line_number":4166,"context_line":"                        return [], []"},{"line_number":4167,"context_line":""},{"line_number":4168,"context_line":"                # rp_ids contains a list of resource provider IDs that EITHER"},{"line_number":4169,"context_line":"                # have all the requested resources themselves OR have some"},{"line_number":4170,"context_line":"                # resources and are related to a provider that is sharing some"},{"line_number":4171,"context_line":"                # resources with it. In other words, this is the list of"},{"line_number":4172,"context_line":"                # resource provider IDs that are NOT sharing resources."},{"line_number":4173,"context_line":"                rps \u003d _get_all_with_shared(context, resources, member_of)"},{"line_number":4174,"context_line":"                rp_ids \u003d set([r[0] for r in rps])"},{"line_number":4175,"context_line":"                return _alloc_candidates_with_shared("},{"line_number":4176,"context_line":"                    context, resources, required_trait_map,"},{"line_number":4177,"context_line":"                    forbidden_trait_map, rp_ids, sharing_providers)"},{"line_number":4178,"context_line":""},{"line_number":4179,"context_line":"        # Either we are processing a single-RP request group, or there are no"},{"line_number":4180,"context_line":"        # sharing providers that (help) satisfy the request.  Get a list of"},{"line_number":4181,"context_line":"        # resource provider IDs that have ALL the requested resources and more"},{"line_number":4182,"context_line":"        # efficiently construct the allocation requests."},{"line_number":4183,"context_line":"        # NOTE(jaypipes): When we start handling nested providers, we may"},{"line_number":4184,"context_line":"        # add new code paths or modify this code path to return root"},{"line_number":4185,"context_line":"        # provider IDs of provider trees instead of the resource provider"},{"line_number":4186,"context_line":"        # IDs."},{"line_number":4187,"context_line":"        rp_ids \u003d _get_provider_ids_matching(context, resources,"},{"line_number":4188,"context_line":"                                            required_trait_map,"},{"line_number":4189,"context_line":"                                            forbidden_trait_map, member_of)"},{"line_number":4190,"context_line":"        return _alloc_candidates_single_provider(context, resources, rp_ids)"},{"line_number":4191,"context_line":""},{"line_number":4192,"context_line":"    @classmethod"},{"line_number":4193,"context_line":"    # TODO(efried): This is only a writer context because it accesses the"},{"line_number":4194,"context_line":"    # resource_providers table via ResourceProvider.get_by_uuid, which does"},{"line_number":4195,"context_line":"    # data migration to populate the root_provider_uuid.  Change this back to a"},{"line_number":4196,"context_line":"    # reader when that migration is no longer happening."},{"line_number":4197,"context_line":"    @db_api.api_context_manager.writer"},{"line_number":4198,"context_line":"    def _get_by_requests(cls, context, requests, limit\u003dNone,"},{"line_number":4199,"context_line":"                         group_policy\u003dNone):"},{"line_number":4200,"context_line":"        candidates \u003d {}"},{"line_number":4201,"context_line":"        for suffix, request in requests.items():"},{"line_number":4202,"context_line":"            alloc_reqs, summaries \u003d cls._get_by_one_request(context, request)"},{"line_number":4203,"context_line":"            if not alloc_reqs:"},{"line_number":4204,"context_line":"                # Shortcut: If any one request resulted in no candidates, the"},{"line_number":4205,"context_line":"                # whole operation is shot."},{"line_number":4206,"context_line":"                return [], []"},{"line_number":4207,"context_line":"            # Mark each allocation request according to whether its"},{"line_number":4208,"context_line":"            # corresponding RequestGroup required it to be restricted to a"},{"line_number":4209,"context_line":"            # single provider.  We\u0027ll need this later to evaluate group_policy."},{"line_number":4210,"context_line":"            for areq in alloc_reqs:"},{"line_number":4211,"context_line":"                areq.use_same_provider \u003d request.use_same_provider"},{"line_number":4212,"context_line":"            candidates[suffix] \u003d alloc_reqs, summaries"},{"line_number":4213,"context_line":""},{"line_number":4214,"context_line":"        # At this point, each (alloc_requests, summary_obj) in `candidates` is"},{"line_number":4215,"context_line":"        # independent of the others. We need to fold them together such that"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_1a3b6beb","line":4212,"range":{"start_line":4101,"start_character":0,"end_line":4212,"end_character":54},"updated":"2018-05-08 15:47:40.000000000","message":"would have been nice to put the above code into a separate patch, just to cut down on reviewer load here.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":4098,"context_line":""},{"line_number":4099,"context_line":"    @staticmethod"},{"line_number":4100,"context_line":"    def _get_by_one_request(context, request):"},{"line_number":4101,"context_line":"        \"\"\"Get allocation candidates for one RequestGroup."},{"line_number":4102,"context_line":""},{"line_number":4103,"context_line":"        Must be called from within an api_context_manager.reader (or writer)"},{"line_number":4104,"context_line":"        context."},{"line_number":4105,"context_line":""},{"line_number":4106,"context_line":"        :param context: Nova RequestContext."},{"line_number":4107,"context_line":"        :param request: One nova.api.openstack.placement.util.RequestGroup"},{"line_number":4108,"context_line":"        :return: A tuple of (allocation_requests, provider_summaries)"},{"line_number":4109,"context_line":"                 satisfying `request`."},{"line_number":4110,"context_line":"        \"\"\""},{"line_number":4111,"context_line":"        # Transform resource string names to internal integer IDs"},{"line_number":4112,"context_line":"        resources \u003d {"},{"line_number":4113,"context_line":"            _RC_CACHE.id_from_string(key): value"},{"line_number":4114,"context_line":"            for key, value in request.resources.items()"},{"line_number":4115,"context_line":"        }"},{"line_number":4116,"context_line":""},{"line_number":4117,"context_line":"        # maps the trait name to the trait internal ID"},{"line_number":4118,"context_line":"        required_trait_map \u003d {}"},{"line_number":4119,"context_line":"        forbidden_trait_map \u003d {}"},{"line_number":4120,"context_line":"        for trait_map, traits in ("},{"line_number":4121,"context_line":"                (required_trait_map, request.required_traits),"},{"line_number":4122,"context_line":"                (forbidden_trait_map, request.forbidden_traits)):"},{"line_number":4123,"context_line":"            if traits:"},{"line_number":4124,"context_line":"                trait_map.update(_trait_ids_from_names(context, traits))"},{"line_number":4125,"context_line":"                # Double-check that we found a trait ID for each requested name"},{"line_number":4126,"context_line":"                if len(trait_map) !\u003d len(traits):"},{"line_number":4127,"context_line":"                    missing \u003d traits - set(trait_map)"},{"line_number":4128,"context_line":"                    raise exception.TraitNotFound(names\u003d\u0027, \u0027.join(missing))"},{"line_number":4129,"context_line":""},{"line_number":4130,"context_line":"        # Microversions prior to 1.21 will not have \u0027member_of\u0027 in the groups."},{"line_number":4131,"context_line":"        # This allows earlier microversions to continue to work."},{"line_number":4132,"context_line":"        member_of \u003d getattr(request, \"member_of\", \"\")"},{"line_number":4133,"context_line":""},{"line_number":4134,"context_line":"        if not request.use_same_provider:"},{"line_number":4135,"context_line":"            # TODO(jaypipes): The check/callout to handle trees goes here."},{"line_number":4136,"context_line":"            # Build a dict, keyed by resource class internal ID, of lists of"},{"line_number":4137,"context_line":"            # internal IDs of resource providers that share some inventory for"},{"line_number":4138,"context_line":"            # each resource class requested."},{"line_number":4139,"context_line":"            # TODO(jaypipes): Consider caching this for some amount of time"},{"line_number":4140,"context_line":"            # since sharing providers generally don\u0027t change often and here we"},{"line_number":4141,"context_line":"            # aren\u0027t concerned with how *much* inventory/capacity the sharing"},{"line_number":4142,"context_line":"            # provider has, only that it is sharing *some* inventory of a"},{"line_number":4143,"context_line":"            # particular resource class."},{"line_number":4144,"context_line":"            sharing_providers \u003d {"},{"line_number":4145,"context_line":"                rc_id: _get_providers_with_shared_capacity(context, rc_id,"},{"line_number":4146,"context_line":"                                                           amount)"},{"line_number":4147,"context_line":"                for rc_id, amount in resources.items()"},{"line_number":4148,"context_line":"            }"},{"line_number":4149,"context_line":"            # We check this here as an optimization: if we have no sharing"},{"line_number":4150,"context_line":"            # providers, we fall through to the (simpler, more efficient)"},{"line_number":4151,"context_line":"            # algorithm below."},{"line_number":4152,"context_line":"            if any(sharing_providers.values()):"},{"line_number":4153,"context_line":"                # Okay, we have to do it the hard way: the request may be"},{"line_number":4154,"context_line":"                # satisfied by one or more sharing providers as well as (maybe)"},{"line_number":4155,"context_line":"                # the non-sharing provider."},{"line_number":4156,"context_line":"                if required_trait_map:"},{"line_number":4157,"context_line":"                    # TODO(cdent): Now that there is also a forbidden_trait_map"},{"line_number":4158,"context_line":"                    # it should be possible to further optimize this attempt at"},{"line_number":4159,"context_line":"                    # a quick return, but we leave that to future patches for"},{"line_number":4160,"context_line":"                    # now."},{"line_number":4161,"context_line":"                    trait_rps \u003d _get_provider_ids_having_any_trait("},{"line_number":4162,"context_line":"                        context, required_trait_map)"},{"line_number":4163,"context_line":"                    if not trait_rps:"},{"line_number":4164,"context_line":"                        # If there aren\u0027t any providers that have any of the"},{"line_number":4165,"context_line":"                        # required traits, just exit early..."},{"line_number":4166,"context_line":"                        return [], []"},{"line_number":4167,"context_line":""},{"line_number":4168,"context_line":"                # rp_ids contains a list of resource provider IDs that EITHER"},{"line_number":4169,"context_line":"                # have all the requested resources themselves OR have some"},{"line_number":4170,"context_line":"                # resources and are related to a provider that is sharing some"},{"line_number":4171,"context_line":"                # resources with it. In other words, this is the list of"},{"line_number":4172,"context_line":"                # resource provider IDs that are NOT sharing resources."},{"line_number":4173,"context_line":"                rps \u003d _get_all_with_shared(context, resources, member_of)"},{"line_number":4174,"context_line":"                rp_ids \u003d set([r[0] for r in rps])"},{"line_number":4175,"context_line":"                return _alloc_candidates_with_shared("},{"line_number":4176,"context_line":"                    context, resources, required_trait_map,"},{"line_number":4177,"context_line":"                    forbidden_trait_map, rp_ids, sharing_providers)"},{"line_number":4178,"context_line":""},{"line_number":4179,"context_line":"        # Either we are processing a single-RP request group, or there are no"},{"line_number":4180,"context_line":"        # sharing providers that (help) satisfy the request.  Get a list of"},{"line_number":4181,"context_line":"        # resource provider IDs that have ALL the requested resources and more"},{"line_number":4182,"context_line":"        # efficiently construct the allocation requests."},{"line_number":4183,"context_line":"        # NOTE(jaypipes): When we start handling nested providers, we may"},{"line_number":4184,"context_line":"        # add new code paths or modify this code path to return root"},{"line_number":4185,"context_line":"        # provider IDs of provider trees instead of the resource provider"},{"line_number":4186,"context_line":"        # IDs."},{"line_number":4187,"context_line":"        rp_ids \u003d _get_provider_ids_matching(context, resources,"},{"line_number":4188,"context_line":"                                            required_trait_map,"},{"line_number":4189,"context_line":"                                            forbidden_trait_map, member_of)"},{"line_number":4190,"context_line":"        return _alloc_candidates_single_provider(context, resources, rp_ids)"},{"line_number":4191,"context_line":""},{"line_number":4192,"context_line":"    @classmethod"},{"line_number":4193,"context_line":"    # TODO(efried): This is only a writer context because it accesses the"},{"line_number":4194,"context_line":"    # resource_providers table via ResourceProvider.get_by_uuid, which does"},{"line_number":4195,"context_line":"    # data migration to populate the root_provider_uuid.  Change this back to a"},{"line_number":4196,"context_line":"    # reader when that migration is no longer happening."},{"line_number":4197,"context_line":"    @db_api.api_context_manager.writer"},{"line_number":4198,"context_line":"    def _get_by_requests(cls, context, requests, limit\u003dNone,"},{"line_number":4199,"context_line":"                         group_policy\u003dNone):"},{"line_number":4200,"context_line":"        candidates \u003d {}"},{"line_number":4201,"context_line":"        for suffix, request in requests.items():"},{"line_number":4202,"context_line":"            alloc_reqs, summaries \u003d cls._get_by_one_request(context, request)"},{"line_number":4203,"context_line":"            if not alloc_reqs:"},{"line_number":4204,"context_line":"                # Shortcut: If any one request resulted in no candidates, the"},{"line_number":4205,"context_line":"                # whole operation is shot."},{"line_number":4206,"context_line":"                return [], []"},{"line_number":4207,"context_line":"            # Mark each allocation request according to whether its"},{"line_number":4208,"context_line":"            # corresponding RequestGroup required it to be restricted to a"},{"line_number":4209,"context_line":"            # single provider.  We\u0027ll need this later to evaluate group_policy."},{"line_number":4210,"context_line":"            for areq in alloc_reqs:"},{"line_number":4211,"context_line":"                areq.use_same_provider \u003d request.use_same_provider"},{"line_number":4212,"context_line":"            candidates[suffix] \u003d alloc_reqs, summaries"},{"line_number":4213,"context_line":""},{"line_number":4214,"context_line":"        # At this point, each (alloc_requests, summary_obj) in `candidates` is"},{"line_number":4215,"context_line":"        # independent of the others. We need to fold them together such that"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_4081f249","line":4212,"range":{"start_line":4101,"start_character":0,"end_line":4212,"end_character":54},"in_reply_to":"5f7c97a3_1a3b6beb","updated":"2018-05-08 16:53:54.000000000","message":"ack.  But not at this point, right?","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4769f15df6937ae4cfea48969918306522439a50","unresolved":false,"context_lines":[{"line_number":4098,"context_line":""},{"line_number":4099,"context_line":"    @staticmethod"},{"line_number":4100,"context_line":"    def _get_by_one_request(context, request):"},{"line_number":4101,"context_line":"        \"\"\"Get allocation candidates for one RequestGroup."},{"line_number":4102,"context_line":""},{"line_number":4103,"context_line":"        Must be called from within an api_context_manager.reader (or writer)"},{"line_number":4104,"context_line":"        context."},{"line_number":4105,"context_line":""},{"line_number":4106,"context_line":"        :param context: Nova RequestContext."},{"line_number":4107,"context_line":"        :param request: One nova.api.openstack.placement.util.RequestGroup"},{"line_number":4108,"context_line":"        :return: A tuple of (allocation_requests, provider_summaries)"},{"line_number":4109,"context_line":"                 satisfying `request`."},{"line_number":4110,"context_line":"        \"\"\""},{"line_number":4111,"context_line":"        # Transform resource string names to internal integer IDs"},{"line_number":4112,"context_line":"        resources \u003d {"},{"line_number":4113,"context_line":"            _RC_CACHE.id_from_string(key): value"},{"line_number":4114,"context_line":"            for key, value in request.resources.items()"},{"line_number":4115,"context_line":"        }"},{"line_number":4116,"context_line":""},{"line_number":4117,"context_line":"        # maps the trait name to the trait internal ID"},{"line_number":4118,"context_line":"        required_trait_map \u003d {}"},{"line_number":4119,"context_line":"        forbidden_trait_map \u003d {}"},{"line_number":4120,"context_line":"        for trait_map, traits in ("},{"line_number":4121,"context_line":"                (required_trait_map, request.required_traits),"},{"line_number":4122,"context_line":"                (forbidden_trait_map, request.forbidden_traits)):"},{"line_number":4123,"context_line":"            if traits:"},{"line_number":4124,"context_line":"                trait_map.update(_trait_ids_from_names(context, traits))"},{"line_number":4125,"context_line":"                # Double-check that we found a trait ID for each requested name"},{"line_number":4126,"context_line":"                if len(trait_map) !\u003d len(traits):"},{"line_number":4127,"context_line":"                    missing \u003d traits - set(trait_map)"},{"line_number":4128,"context_line":"                    raise exception.TraitNotFound(names\u003d\u0027, \u0027.join(missing))"},{"line_number":4129,"context_line":""},{"line_number":4130,"context_line":"        # Microversions prior to 1.21 will not have \u0027member_of\u0027 in the groups."},{"line_number":4131,"context_line":"        # This allows earlier microversions to continue to work."},{"line_number":4132,"context_line":"        member_of \u003d getattr(request, \"member_of\", \"\")"},{"line_number":4133,"context_line":""},{"line_number":4134,"context_line":"        if not request.use_same_provider:"},{"line_number":4135,"context_line":"            # TODO(jaypipes): The check/callout to handle trees goes here."},{"line_number":4136,"context_line":"            # Build a dict, keyed by resource class internal ID, of lists of"},{"line_number":4137,"context_line":"            # internal IDs of resource providers that share some inventory for"},{"line_number":4138,"context_line":"            # each resource class requested."},{"line_number":4139,"context_line":"            # TODO(jaypipes): Consider caching this for some amount of time"},{"line_number":4140,"context_line":"            # since sharing providers generally don\u0027t change often and here we"},{"line_number":4141,"context_line":"            # aren\u0027t concerned with how *much* inventory/capacity the sharing"},{"line_number":4142,"context_line":"            # provider has, only that it is sharing *some* inventory of a"},{"line_number":4143,"context_line":"            # particular resource class."},{"line_number":4144,"context_line":"            sharing_providers \u003d {"},{"line_number":4145,"context_line":"                rc_id: _get_providers_with_shared_capacity(context, rc_id,"},{"line_number":4146,"context_line":"                                                           amount)"},{"line_number":4147,"context_line":"                for rc_id, amount in resources.items()"},{"line_number":4148,"context_line":"            }"},{"line_number":4149,"context_line":"            # We check this here as an optimization: if we have no sharing"},{"line_number":4150,"context_line":"            # providers, we fall through to the (simpler, more efficient)"},{"line_number":4151,"context_line":"            # algorithm below."},{"line_number":4152,"context_line":"            if any(sharing_providers.values()):"},{"line_number":4153,"context_line":"                # Okay, we have to do it the hard way: the request may be"},{"line_number":4154,"context_line":"                # satisfied by one or more sharing providers as well as (maybe)"},{"line_number":4155,"context_line":"                # the non-sharing provider."},{"line_number":4156,"context_line":"                if required_trait_map:"},{"line_number":4157,"context_line":"                    # TODO(cdent): Now that there is also a forbidden_trait_map"},{"line_number":4158,"context_line":"                    # it should be possible to further optimize this attempt at"},{"line_number":4159,"context_line":"                    # a quick return, but we leave that to future patches for"},{"line_number":4160,"context_line":"                    # now."},{"line_number":4161,"context_line":"                    trait_rps \u003d _get_provider_ids_having_any_trait("},{"line_number":4162,"context_line":"                        context, required_trait_map)"},{"line_number":4163,"context_line":"                    if not trait_rps:"},{"line_number":4164,"context_line":"                        # If there aren\u0027t any providers that have any of the"},{"line_number":4165,"context_line":"                        # required traits, just exit early..."},{"line_number":4166,"context_line":"                        return [], []"},{"line_number":4167,"context_line":""},{"line_number":4168,"context_line":"                # rp_ids contains a list of resource provider IDs that EITHER"},{"line_number":4169,"context_line":"                # have all the requested resources themselves OR have some"},{"line_number":4170,"context_line":"                # resources and are related to a provider that is sharing some"},{"line_number":4171,"context_line":"                # resources with it. In other words, this is the list of"},{"line_number":4172,"context_line":"                # resource provider IDs that are NOT sharing resources."},{"line_number":4173,"context_line":"                rps \u003d _get_all_with_shared(context, resources, member_of)"},{"line_number":4174,"context_line":"                rp_ids \u003d set([r[0] for r in rps])"},{"line_number":4175,"context_line":"                return _alloc_candidates_with_shared("},{"line_number":4176,"context_line":"                    context, resources, required_trait_map,"},{"line_number":4177,"context_line":"                    forbidden_trait_map, rp_ids, sharing_providers)"},{"line_number":4178,"context_line":""},{"line_number":4179,"context_line":"        # Either we are processing a single-RP request group, or there are no"},{"line_number":4180,"context_line":"        # sharing providers that (help) satisfy the request.  Get a list of"},{"line_number":4181,"context_line":"        # resource provider IDs that have ALL the requested resources and more"},{"line_number":4182,"context_line":"        # efficiently construct the allocation requests."},{"line_number":4183,"context_line":"        # NOTE(jaypipes): When we start handling nested providers, we may"},{"line_number":4184,"context_line":"        # add new code paths or modify this code path to return root"},{"line_number":4185,"context_line":"        # provider IDs of provider trees instead of the resource provider"},{"line_number":4186,"context_line":"        # IDs."},{"line_number":4187,"context_line":"        rp_ids \u003d _get_provider_ids_matching(context, resources,"},{"line_number":4188,"context_line":"                                            required_trait_map,"},{"line_number":4189,"context_line":"                                            forbidden_trait_map, member_of)"},{"line_number":4190,"context_line":"        return _alloc_candidates_single_provider(context, resources, rp_ids)"},{"line_number":4191,"context_line":""},{"line_number":4192,"context_line":"    @classmethod"},{"line_number":4193,"context_line":"    # TODO(efried): This is only a writer context because it accesses the"},{"line_number":4194,"context_line":"    # resource_providers table via ResourceProvider.get_by_uuid, which does"},{"line_number":4195,"context_line":"    # data migration to populate the root_provider_uuid.  Change this back to a"},{"line_number":4196,"context_line":"    # reader when that migration is no longer happening."},{"line_number":4197,"context_line":"    @db_api.api_context_manager.writer"},{"line_number":4198,"context_line":"    def _get_by_requests(cls, context, requests, limit\u003dNone,"},{"line_number":4199,"context_line":"                         group_policy\u003dNone):"},{"line_number":4200,"context_line":"        candidates \u003d {}"},{"line_number":4201,"context_line":"        for suffix, request in requests.items():"},{"line_number":4202,"context_line":"            alloc_reqs, summaries \u003d cls._get_by_one_request(context, request)"},{"line_number":4203,"context_line":"            if not alloc_reqs:"},{"line_number":4204,"context_line":"                # Shortcut: If any one request resulted in no candidates, the"},{"line_number":4205,"context_line":"                # whole operation is shot."},{"line_number":4206,"context_line":"                return [], []"},{"line_number":4207,"context_line":"            # Mark each allocation request according to whether its"},{"line_number":4208,"context_line":"            # corresponding RequestGroup required it to be restricted to a"},{"line_number":4209,"context_line":"            # single provider.  We\u0027ll need this later to evaluate group_policy."},{"line_number":4210,"context_line":"            for areq in alloc_reqs:"},{"line_number":4211,"context_line":"                areq.use_same_provider \u003d request.use_same_provider"},{"line_number":4212,"context_line":"            candidates[suffix] \u003d alloc_reqs, summaries"},{"line_number":4213,"context_line":""},{"line_number":4214,"context_line":"        # At this point, each (alloc_requests, summary_obj) in `candidates` is"},{"line_number":4215,"context_line":"        # independent of the others. We need to fold them together such that"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_54b217e8","line":4212,"range":{"start_line":4101,"start_character":0,"end_line":4212,"end_character":54},"in_reply_to":"5f7c97a3_4081f249","updated":"2018-05-08 17:10:36.000000000","message":"not at this point. I do it in my refactor series anyway.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"}],"nova/api/openstack/placement/rest_api_version_history.rst":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5193b662f348f4f59ef71054b6951bda8a821215","unresolved":false,"context_lines":[{"line_number":264,"context_line":""},{"line_number":265,"context_line":"1.__MICROVERSION__ Granular resource requests to ``GET /allocation_candidates``"},{"line_number":266,"context_line":"-----------------------------------------------------------------"},{"line_number":267,"context_line":"In version 1.__MICROVERSION__ the ``GET /allocation_candidates`` API is enhanced to accept"},{"line_number":268,"context_line":"numbered groupings of resource and required trait requests.  A ``resources``"},{"line_number":269,"context_line":"query parameter key with a positive integer suffix (e.g. ``resources42``) will"},{"line_number":270,"context_line":"be logically associated with a ``required`` query parameter key with the same"}],"source_content_type":"text/x-rst","patch_set":2,"id":"bf659307_33f603d9","line":267,"updated":"2018-04-03 18:26:42.000000000","message":"for consistency, extra newline here.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[{"line_number":264,"context_line":""},{"line_number":265,"context_line":"1.__MICROVERSION__ Granular resource requests to ``GET /allocation_candidates``"},{"line_number":266,"context_line":"-----------------------------------------------------------------"},{"line_number":267,"context_line":"In version 1.__MICROVERSION__ the ``GET /allocation_candidates`` API is enhanced to accept"},{"line_number":268,"context_line":"numbered groupings of resource and required trait requests.  A ``resources``"},{"line_number":269,"context_line":"query parameter key with a positive integer suffix (e.g. ``resources42``) will"},{"line_number":270,"context_line":"be logically associated with a ``required`` query parameter key with the same"}],"source_content_type":"text/x-rst","patch_set":2,"id":"bf659307_72ec1ff3","line":267,"in_reply_to":"bf659307_33f603d9","updated":"2018-04-16 18:33:40.000000000","message":"Done","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5193b662f348f4f59ef71054b6951bda8a821215","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"bf659307_530db7e5","line":283,"updated":"2018-04-03 18:26:42.000000000","message":"Mention relationship between/among different groups.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"bf659307_12bb63e5","line":283,"in_reply_to":"bf659307_530db7e5","updated":"2018-04-16 18:33:40.000000000","message":"Done","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":303,"context_line":"``member_of`` query parameter keys with the same suffix (e.g. ``required42``,"},{"line_number":304,"context_line":"``member_of42``). The resources, required/forbidden traits, and aggregate"},{"line_number":305,"context_line":"associations in that group will be satisfied by the same resource provider in"},{"line_number":306,"context_line":"the response. When more than one numbered grouping is supplied, the"},{"line_number":307,"context_line":"``group_policy`` query parameter is required to indicate how the groups should"},{"line_number":308,"context_line":"interact. With ``group_policy\u003dnone``, separate groupings - numbered or"},{"line_number":309,"context_line":"unnumbered - may or may not be satisfied by the same provider. With"},{"line_number":310,"context_line":"``group_policy\u003disolate``, numbered groups are guaranteed to be satisfied by"},{"line_number":311,"context_line":"*different* providers - though there may still be overlap with the unnumbered"},{"line_number":312,"context_line":"group."},{"line_number":313,"context_line":""},{"line_number":314,"context_line":"The ``required`` and ``member_of`` query parameters for a given group are"},{"line_number":315,"context_line":"optional.  That is, you may specify ``resources42\u003dXXX`` without a corresponding"}],"source_content_type":"text/x-rst","patch_set":37,"id":"5f7c97a3_65ff6001","line":312,"range":{"start_line":306,"start_character":14,"end_line":312,"end_character":6},"updated":"2018-05-08 15:47:40.000000000","message":"good explanation, though see my note in the gabbit about not mentioning \"anchor providers\" and why that might be confusing to the reader of this note.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":303,"context_line":"``member_of`` query parameter keys with the same suffix (e.g. ``required42``,"},{"line_number":304,"context_line":"``member_of42``). The resources, required/forbidden traits, and aggregate"},{"line_number":305,"context_line":"associations in that group will be satisfied by the same resource provider in"},{"line_number":306,"context_line":"the response. When more than one numbered grouping is supplied, the"},{"line_number":307,"context_line":"``group_policy`` query parameter is required to indicate how the groups should"},{"line_number":308,"context_line":"interact. With ``group_policy\u003dnone``, separate groupings - numbered or"},{"line_number":309,"context_line":"unnumbered - may or may not be satisfied by the same provider. With"},{"line_number":310,"context_line":"``group_policy\u003disolate``, numbered groups are guaranteed to be satisfied by"},{"line_number":311,"context_line":"*different* providers - though there may still be overlap with the unnumbered"},{"line_number":312,"context_line":"group."},{"line_number":313,"context_line":""},{"line_number":314,"context_line":"The ``required`` and ``member_of`` query parameters for a given group are"},{"line_number":315,"context_line":"optional.  That is, you may specify ``resources42\u003dXXX`` without a corresponding"}],"source_content_type":"text/x-rst","patch_set":37,"id":"5f7c97a3_c04ae2aa","line":312,"range":{"start_line":306,"start_character":14,"end_line":312,"end_character":6},"in_reply_to":"5f7c97a3_65ff6001","updated":"2018-05-08 16:53:54.000000000","message":"Done","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4769f15df6937ae4cfea48969918306522439a50","unresolved":false,"context_lines":[{"line_number":310,"context_line":"``group_policy\u003disolate``, numbered groups are guaranteed to be satisfied by"},{"line_number":311,"context_line":"*different* providers - though there may still be overlap with the unnumbered"},{"line_number":312,"context_line":"group. In all cases, each ``allocation_request`` will be satisfied by providers"},{"line_number":313,"context_line":"in a single non-sharing provider tree and/or sharing providers associated via"},{"line_number":314,"context_line":"aggregate with any of the providers in that tree."},{"line_number":315,"context_line":""},{"line_number":316,"context_line":"The ``required`` and ``member_of`` query parameters for a given group are"},{"line_number":317,"context_line":"optional.  That is, you may specify ``resources42\u003dXXX`` without a corresponding"}],"source_content_type":"text/x-rst","patch_set":38,"id":"5f7c97a3_54e777e5","line":314,"range":{"start_line":313,"start_character":5,"end_line":314,"end_character":49},"updated":"2018-05-08 17:10:36.000000000","message":"bingo!","commit_id":"9af073384cca305565e741c1dfbb359c1e562a4e"}],"nova/api/openstack/placement/schemas/allocation_candidate.py":[{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"928327a6ba560a0f35462bca67ed97c6205bda6f","unresolved":false,"context_lines":[{"line_number":24,"context_line":"        },"},{"line_number":25,"context_line":"    },"},{"line_number":26,"context_line":"    \"required\": ["},{"line_number":27,"context_line":"        \"resources\","},{"line_number":28,"context_line":"    ],"},{"line_number":29,"context_line":"    \"additionalProperties\": False,"},{"line_number":30,"context_line":"}"}],"source_content_type":"text/x-python","patch_set":13,"id":"9f6a8fd7_0aa9ab22","line":27,"range":{"start_line":27,"start_character":8,"end_line":27,"end_character":19},"updated":"2018-04-20 02:48:12.000000000","message":"you should remove this in the new version?","commit_id":"d0ffd0196ac7b9958132be3f336702c3bcdfd96f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"df17734b771387f2624e284920a6fdea474cbac0","unresolved":false,"context_lines":[{"line_number":24,"context_line":"        },"},{"line_number":25,"context_line":"    },"},{"line_number":26,"context_line":"    \"required\": ["},{"line_number":27,"context_line":"        \"resources\","},{"line_number":28,"context_line":"    ],"},{"line_number":29,"context_line":"    \"additionalProperties\": False,"},{"line_number":30,"context_line":"}"}],"source_content_type":"text/x-python","patch_set":13,"id":"9f6a8fd7_242ffb8e","line":27,"range":{"start_line":27,"start_character":8,"end_line":27,"end_character":19},"in_reply_to":"9f6a8fd7_0aa9ab22","updated":"2018-04-20 12:04:10.000000000","message":"Ah, yes, thank you.","commit_id":"d0ffd0196ac7b9958132be3f336702c3bcdfd96f"},{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"928327a6ba560a0f35462bca67ed97c6205bda6f","unresolved":false,"context_lines":[{"line_number":67,"context_line":"        \"type\": \"string\","},{"line_number":68,"context_line":"    },"},{"line_number":69,"context_line":"}"},{"line_number":70,"context_line":"GET_SCHEMA_1_23[\"properties\"][\"group_policy\"] \u003d {"},{"line_number":71,"context_line":"    \"type\": \"string\","},{"line_number":72,"context_line":"    \"enum\": [\"none\", \"isolate\"],"},{"line_number":73,"context_line":"}"}],"source_content_type":"text/x-python","patch_set":13,"id":"9f6a8fd7_aa6f5ffa","line":70,"range":{"start_line":70,"start_character":31,"end_line":70,"end_character":43},"updated":"2018-04-20 02:48:12.000000000","message":"this is required properites?","commit_id":"d0ffd0196ac7b9958132be3f336702c3bcdfd96f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"df17734b771387f2624e284920a6fdea474cbac0","unresolved":false,"context_lines":[{"line_number":67,"context_line":"        \"type\": \"string\","},{"line_number":68,"context_line":"    },"},{"line_number":69,"context_line":"}"},{"line_number":70,"context_line":"GET_SCHEMA_1_23[\"properties\"][\"group_policy\"] \u003d {"},{"line_number":71,"context_line":"    \"type\": \"string\","},{"line_number":72,"context_line":"    \"enum\": [\"none\", \"isolate\"],"},{"line_number":73,"context_line":"}"}],"source_content_type":"text/x-python","patch_set":13,"id":"9f6a8fd7_a43a2bc9","line":70,"range":{"start_line":70,"start_character":31,"end_line":70,"end_character":43},"in_reply_to":"9f6a8fd7_aa6f5ffa","updated":"2018-04-20 12:04:10.000000000","message":"Only if \u003e1 resourcesN group is used.  (Which I can\u0027t validate via schema afaik.)\n\n...and whoops, I forgot to add that check in the alloc cand handler.  Thanks!","commit_id":"d0ffd0196ac7b9958132be3f336702c3bcdfd96f"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"bd80013bbaaccea7ee0fc734999705cb8e19177f","unresolved":false,"context_lines":[{"line_number":56,"context_line":"GET_SCHEMA_1_24 \u003d copy.deepcopy(GET_SCHEMA_1_21)"},{"line_number":57,"context_line":"# We\u0027re going to *replace* \u0027resources\u0027 and \u0027required\u0027."},{"line_number":58,"context_line":"del GET_SCHEMA_1_24[\"properties\"][\"resources\"]"},{"line_number":59,"context_line":"del GET_SCHEMA_1_24[\"required\"]"},{"line_number":60,"context_line":"del GET_SCHEMA_1_24[\"properties\"][\"required\"]"},{"line_number":61,"context_line":"# Pattern property key format for a numbered or un-numbered grouping"},{"line_number":62,"context_line":"_GROUP_PAT_FMT \u003d \"^%s([1-9][0-9]*)?$\""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_a26bf6b4","line":59,"updated":"2018-04-20 17:04:47.000000000","message":"This is not restored below so the schema now allows a request without any \u0027resources\u0027 key","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1dcb270a69d27fd6f52bda0c0f6f9d9c72b05545","unresolved":false,"context_lines":[{"line_number":56,"context_line":"GET_SCHEMA_1_24 \u003d copy.deepcopy(GET_SCHEMA_1_21)"},{"line_number":57,"context_line":"# We\u0027re going to *replace* \u0027resources\u0027 and \u0027required\u0027."},{"line_number":58,"context_line":"del GET_SCHEMA_1_24[\"properties\"][\"resources\"]"},{"line_number":59,"context_line":"del GET_SCHEMA_1_24[\"required\"]"},{"line_number":60,"context_line":"del GET_SCHEMA_1_24[\"properties\"][\"required\"]"},{"line_number":61,"context_line":"# Pattern property key format for a numbered or un-numbered grouping"},{"line_number":62,"context_line":"_GROUP_PAT_FMT \u003d \"^%s([1-9][0-9]*)?$\""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_7ef552ec","line":59,"in_reply_to":"9f6a8fd7_03209a47","updated":"2018-04-23 18:43:26.000000000","message":"ack","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"b1c8df0a8e821eb3912f8d17c5a15897beb76180","unresolved":false,"context_lines":[{"line_number":56,"context_line":"GET_SCHEMA_1_24 \u003d copy.deepcopy(GET_SCHEMA_1_21)"},{"line_number":57,"context_line":"# We\u0027re going to *replace* \u0027resources\u0027 and \u0027required\u0027."},{"line_number":58,"context_line":"del GET_SCHEMA_1_24[\"properties\"][\"resources\"]"},{"line_number":59,"context_line":"del GET_SCHEMA_1_24[\"required\"]"},{"line_number":60,"context_line":"del GET_SCHEMA_1_24[\"properties\"][\"required\"]"},{"line_number":61,"context_line":"# Pattern property key format for a numbered or un-numbered grouping"},{"line_number":62,"context_line":"_GROUP_PAT_FMT \u003d \"^%s([1-9][0-9]*)?$\""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_03209a47","line":59,"in_reply_to":"9f6a8fd7_1baec497","updated":"2018-04-21 14:45:50.000000000","message":"I think there is no way to make a patternProperties required. So this needs to be checked in code.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f82c4d55a2186e2c0ab6bd1a254aaab1695d75df","unresolved":false,"context_lines":[{"line_number":56,"context_line":"GET_SCHEMA_1_24 \u003d copy.deepcopy(GET_SCHEMA_1_21)"},{"line_number":57,"context_line":"# We\u0027re going to *replace* \u0027resources\u0027 and \u0027required\u0027."},{"line_number":58,"context_line":"del GET_SCHEMA_1_24[\"properties\"][\"resources\"]"},{"line_number":59,"context_line":"del GET_SCHEMA_1_24[\"required\"]"},{"line_number":60,"context_line":"del GET_SCHEMA_1_24[\"properties\"][\"required\"]"},{"line_number":61,"context_line":"# Pattern property key format for a numbered or un-numbered grouping"},{"line_number":62,"context_line":"_GROUP_PAT_FMT \u003d \"^%s([1-9][0-9]*)?$\""}],"source_content_type":"text/x-python","patch_set":15,"id":"9f6a8fd7_1baec497","line":59,"in_reply_to":"9f6a8fd7_a26bf6b4","updated":"2018-04-20 23:11:11.000000000","message":"That\u0027s correct, because you are allowed to use just numbered groups if you wish.  Is there a way for me to designate one of the patternProperties entries is required (without naming it)?\n\nBut good call, I had forgotten to add a code-based check for that.  Will fix.","commit_id":"06ae125c5827dc5e42b6559e292b63634d059455"}],"nova/api/openstack/placement/util.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"786848d187016c574f0d4164152cc2eb787dd1bb","unresolved":false,"context_lines":[{"line_number":501,"context_line":"                \u0027resources. Found the following orphaned member_of \u0027"},{"line_number":502,"context_line":"                \u0027 values: %s\u0027)"},{"line_number":503,"context_line":"        raise webob.exc.HTTPBadRequest(msg % \u0027, \u0027.join(orphans))"},{"line_number":504,"context_line":"    # All request groups must have resources (which is almost, but not quite,"},{"line_number":505,"context_line":"    # verified by the orphan checks above)."},{"line_number":506,"context_line":"    if not all(grp.resources for grp in by_suffix.values()):"},{"line_number":507,"context_line":"        msg \u003d _(\"All request groups must specify resources.\")"},{"line_number":508,"context_line":"        raise webob.exc.HTTPBadRequest("},{"line_number":509,"context_line":"                msg, comment\u003derrors.RESOURCES_REQUIRED_IN_REQUEST_GROUP)"},{"line_number":510,"context_line":"    # The above would still pass if there were no request groups"},{"line_number":511,"context_line":"    if not by_suffix:"},{"line_number":512,"context_line":"        msg \u003d _(\"At least one request group (`resources` or `resources{N}`) \""}],"source_content_type":"text/x-python","patch_set":25,"id":"9f6a8fd7_c57c5822","line":509,"range":{"start_line":504,"start_character":0,"end_line":509,"end_character":72},"updated":"2018-04-28 19:40:50.000000000","message":"Yeah, I don\u0027t think this is reachable.","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"18176bd4e72423a033ff28fc9dc4d7dc3fea8c75","unresolved":false,"context_lines":[{"line_number":452,"context_line":"                  \"HW_CPU_X86_VMX\","},{"line_number":453,"context_line":"                  \"CUSTOM_STORAGE_RAID\","},{"line_number":454,"context_line":"              ],"},{"line_number":455,"context_line":"              member_of\u003d["},{"line_number":456,"context_line":"                9323b2b1-82c9-4e91-bdff-e95e808ef954,"},{"line_number":457,"context_line":"                8592a199-7d73-4465-8df6-ab00a6243c82,"},{"line_number":458,"context_line":"              ],"},{"line_number":459,"context_line":"          ),"},{"line_number":460,"context_line":"      \u00271\u0027: RequestGroup("},{"line_number":461,"context_line":"              use_same_provider\u003dTrue,"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_baba7707","line":458,"range":{"start_line":455,"start_character":0,"end_line":458,"end_character":16},"updated":"2018-05-08 14:59:38.000000000","message":"This could be a bit more complex now with multiple member_of qparams","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":452,"context_line":"                  \"HW_CPU_X86_VMX\","},{"line_number":453,"context_line":"                  \"CUSTOM_STORAGE_RAID\","},{"line_number":454,"context_line":"              ],"},{"line_number":455,"context_line":"              member_of\u003d["},{"line_number":456,"context_line":"                9323b2b1-82c9-4e91-bdff-e95e808ef954,"},{"line_number":457,"context_line":"                8592a199-7d73-4465-8df6-ab00a6243c82,"},{"line_number":458,"context_line":"              ],"},{"line_number":459,"context_line":"          ),"},{"line_number":460,"context_line":"      \u00271\u0027: RequestGroup("},{"line_number":461,"context_line":"              use_same_provider\u003dTrue,"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_20eab674","line":458,"range":{"start_line":455,"start_character":0,"end_line":458,"end_character":16},"in_reply_to":"5f7c97a3_05654ce1","updated":"2018-05-08 16:53:54.000000000","message":"I went ahead and corrected it here.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":452,"context_line":"                  \"HW_CPU_X86_VMX\","},{"line_number":453,"context_line":"                  \"CUSTOM_STORAGE_RAID\","},{"line_number":454,"context_line":"              ],"},{"line_number":455,"context_line":"              member_of\u003d["},{"line_number":456,"context_line":"                9323b2b1-82c9-4e91-bdff-e95e808ef954,"},{"line_number":457,"context_line":"                8592a199-7d73-4465-8df6-ab00a6243c82,"},{"line_number":458,"context_line":"              ],"},{"line_number":459,"context_line":"          ),"},{"line_number":460,"context_line":"      \u00271\u0027: RequestGroup("},{"line_number":461,"context_line":"              use_same_provider\u003dTrue,"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_05654ce1","line":458,"range":{"start_line":455,"start_character":0,"end_line":458,"end_character":16},"in_reply_to":"5f7c97a3_baba7707","updated":"2018-05-08 15:47:40.000000000","message":"Right, this should have been changed to:\n\n member_of\u003d[\n     [\n         AGG1_UUID,\n         AGG2_UUID,\n     ],\n ]\n\nI can fix that later.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2c794cf2eff6eb252f0d44b1a67de9d8494a0ad2","unresolved":false,"context_lines":[{"line_number":452,"context_line":"                  \"HW_CPU_X86_VMX\","},{"line_number":453,"context_line":"                  \"CUSTOM_STORAGE_RAID\","},{"line_number":454,"context_line":"              ],"},{"line_number":455,"context_line":"              member_of\u003d["},{"line_number":456,"context_line":"                9323b2b1-82c9-4e91-bdff-e95e808ef954,"},{"line_number":457,"context_line":"                8592a199-7d73-4465-8df6-ab00a6243c82,"},{"line_number":458,"context_line":"              ],"},{"line_number":459,"context_line":"          ),"},{"line_number":460,"context_line":"      \u00271\u0027: RequestGroup("},{"line_number":461,"context_line":"              use_same_provider\u003dTrue,"}],"source_content_type":"text/x-python","patch_set":37,"id":"5f7c97a3_da6c1338","line":458,"range":{"start_line":455,"start_character":0,"end_line":458,"end_character":16},"in_reply_to":"5f7c97a3_baba7707","updated":"2018-05-08 15:13:15.000000000","message":"True, but should have been changed as part of that series.  We can twiddle it in a followup.\n\nNote that I did add a gabbi test covering multiple member_of...","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"}],"nova/tests/functional/api/openstack/placement/fixtures.py":[{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"68168401c80f54eba41fa24b7a18d7949bee8032","unresolved":false,"context_lines":[{"line_number":446,"context_line":"|DISK_GB: 1000          |         :"},{"line_number":447,"context_line":"|traits: MISC_SHARES... +.........+"},{"line_number":448,"context_line":"+\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d+"},{"line_number":449,"context_line":"    \"\"\""},{"line_number":450,"context_line":"    def _create_provider(self, name, *aggs, **kwargs):"},{"line_number":451,"context_line":"        # TODO(efried): Common with test_allocation_candidates.ProviderDBBase"},{"line_number":452,"context_line":"        parent \u003d kwargs.get(\u0027parent\u0027)"}],"source_content_type":"text/x-python","patch_set":34,"id":"5f7c97a3_b453b9e2","line":449,"updated":"2018-05-03 11:28:20.000000000","message":"It is a really helpful drawing","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"}],"nova/tests/functional/api/openstack/placement/gabbits/granular.yaml":[{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"68168401c80f54eba41fa24b7a18d7949bee8032","unresolved":false,"context_lines":[{"line_number":41,"context_line":"# |shr_disk_2             +...+     :"},{"line_number":42,"context_line":"# |DISK_GB: 1000          |         :"},{"line_number":43,"context_line":"# |traits: MISC_SHARES... +.........+"},{"line_number":44,"context_line":"# +\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d+"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"defaults:"},{"line_number":47,"context_line":"    request_headers:"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_34ffa968","line":44,"updated":"2018-05-03 11:28:20.000000000","message":"I would not duplicate the picture as the two copies can diverge. I think here it is enough to refer to the picture in the fixture.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":41,"context_line":"# |shr_disk_2             +...+     :"},{"line_number":42,"context_line":"# |DISK_GB: 1000          |         :"},{"line_number":43,"context_line":"# |traits: MISC_SHARES... +.........+"},{"line_number":44,"context_line":"# +\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d+"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"defaults:"},{"line_number":47,"context_line":"    request_headers:"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_9219ed89","line":44,"in_reply_to":"5f7c97a3_34ffa968","updated":"2018-05-04 14:48:31.000000000","message":"Yes, good point.  I wanted the reader to be able to refer to it without having to have two files open, but I guess that\u0027s actually easier than having to scroll up and down.  Will remove.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"68168401c80f54eba41fa24b7a18d7949bee8032","unresolved":false,"context_lines":[{"line_number":230,"context_line":""},{"line_number":231,"context_line":"- name: multiple disks, multiple networks"},{"line_number":232,"context_line":"  GET: /allocation_candidates?resources1\u003dVCPU:1\u0026resources2\u003dVGPU:1\u0026required2\u003dHW_GPU_API_DXVA\u0026resources3\u003dMEMORY_MB:1024\u0026resources4\u003dDISK_GB:100\u0026required4\u003dCUSTOM_DISK_SSD\u0026resources5\u003dDISK_GB:50\u0026required5\u003d!CUSTOM_DISK_SSD\u0026resources6\u003dSRIOV_NET_VF:1,CUSTOM_NET_MBPS:1000\u0026resources7\u003dSRIOV_NET_VF:2,CUSTOM_NET_MBPS:2000\u0026group_policy\u003dnone"},{"line_number":233,"context_line":"  # Let\u0027s make that more readable, shall we?"},{"line_number":234,"context_line":"  # /allocation_candidates"},{"line_number":235,"context_line":"  #   \u003d\u003e These could come from cn_left, cn_middle, or cn_right"},{"line_number":236,"context_line":"  #     ?resources1\u003dVCPU:1"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_14d70dc2","line":233,"updated":"2018-05-03 11:28:20.000000000","message":"for the future: Can we change gabbi to accept the more readable form?","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"9d98ea0e9fd0f52da6edbbceaa9b0110b52cf741","unresolved":false,"context_lines":[{"line_number":230,"context_line":""},{"line_number":231,"context_line":"- name: multiple disks, multiple networks"},{"line_number":232,"context_line":"  GET: /allocation_candidates?resources1\u003dVCPU:1\u0026resources2\u003dVGPU:1\u0026required2\u003dHW_GPU_API_DXVA\u0026resources3\u003dMEMORY_MB:1024\u0026resources4\u003dDISK_GB:100\u0026required4\u003dCUSTOM_DISK_SSD\u0026resources5\u003dDISK_GB:50\u0026required5\u003d!CUSTOM_DISK_SSD\u0026resources6\u003dSRIOV_NET_VF:1,CUSTOM_NET_MBPS:1000\u0026resources7\u003dSRIOV_NET_VF:2,CUSTOM_NET_MBPS:2000\u0026group_policy\u003dnone"},{"line_number":233,"context_line":"  # Let\u0027s make that more readable, shall we?"},{"line_number":234,"context_line":"  # /allocation_candidates"},{"line_number":235,"context_line":"  #   \u003d\u003e These could come from cn_left, cn_middle, or cn_right"},{"line_number":236,"context_line":"  #     ?resources1\u003dVCPU:1"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_9a077b1d","line":233,"in_reply_to":"5f7c97a3_14d70dc2","updated":"2018-05-08 15:24:12.000000000","message":"For something as complex as this it might make sense to make use of gabbi\u0027s `query_parameters` key (see https://gabbi.readthedocs.io/en/latest/format.html#request-parameters ) which would allow something like:\n\n    GET: /allocation_candidates\n    query_parameters:\n        resources1: \"VCPU:1\" # quotes _may_ not be needed but the double : might hork stuff\n        resources2: \"VGPU:1\"","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":230,"context_line":""},{"line_number":231,"context_line":"- name: multiple disks, multiple networks"},{"line_number":232,"context_line":"  GET: /allocation_candidates?resources1\u003dVCPU:1\u0026resources2\u003dVGPU:1\u0026required2\u003dHW_GPU_API_DXVA\u0026resources3\u003dMEMORY_MB:1024\u0026resources4\u003dDISK_GB:100\u0026required4\u003dCUSTOM_DISK_SSD\u0026resources5\u003dDISK_GB:50\u0026required5\u003d!CUSTOM_DISK_SSD\u0026resources6\u003dSRIOV_NET_VF:1,CUSTOM_NET_MBPS:1000\u0026resources7\u003dSRIOV_NET_VF:2,CUSTOM_NET_MBPS:2000\u0026group_policy\u003dnone"},{"line_number":233,"context_line":"  # Let\u0027s make that more readable, shall we?"},{"line_number":234,"context_line":"  # /allocation_candidates"},{"line_number":235,"context_line":"  #   \u003d\u003e These could come from cn_left, cn_middle, or cn_right"},{"line_number":236,"context_line":"  #     ?resources1\u003dVCPU:1"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_4d565409","line":233,"in_reply_to":"5f7c97a3_14d70dc2","updated":"2018-05-04 14:48:31.000000000","message":"I was going to ask cdent if it was possible to, like, backslash escape to do continued lines, but he\u0027s on vacation this week :)  I did search the gabbi docs and couldn\u0027t find anything promising.  Though it\u0027s possible there\u0027s a standard yaml syntax that would work.\n\n[Later]\n\nIndeed, it looks like I can double-quote and use backslashes - see [1] second answer.  I\u0027ll reformat.\n\n[1] https://stackoverflow.com/questions/3790454/in-yaml-how-do-i-break-a-string-over-multiple-lines","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"18176bd4e72423a033ff28fc9dc4d7dc3fea8c75","unresolved":false,"context_lines":[{"line_number":230,"context_line":""},{"line_number":231,"context_line":"- name: multiple disks, multiple networks"},{"line_number":232,"context_line":"  GET: /allocation_candidates?resources1\u003dVCPU:1\u0026resources2\u003dVGPU:1\u0026required2\u003dHW_GPU_API_DXVA\u0026resources3\u003dMEMORY_MB:1024\u0026resources4\u003dDISK_GB:100\u0026required4\u003dCUSTOM_DISK_SSD\u0026resources5\u003dDISK_GB:50\u0026required5\u003d!CUSTOM_DISK_SSD\u0026resources6\u003dSRIOV_NET_VF:1,CUSTOM_NET_MBPS:1000\u0026resources7\u003dSRIOV_NET_VF:2,CUSTOM_NET_MBPS:2000\u0026group_policy\u003dnone"},{"line_number":233,"context_line":"  # Let\u0027s make that more readable, shall we?"},{"line_number":234,"context_line":"  # /allocation_candidates"},{"line_number":235,"context_line":"  #   \u003d\u003e These could come from cn_left, cn_middle, or cn_right"},{"line_number":236,"context_line":"  #     ?resources1\u003dVCPU:1"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_fa6eaf94","line":233,"in_reply_to":"5f7c97a3_4d565409","updated":"2018-05-08 14:59:38.000000000","message":"awesome","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2dfb48f95b9ca4197c8fec77c2aa04f5b55f43e","unresolved":false,"context_lines":[{"line_number":230,"context_line":""},{"line_number":231,"context_line":"- name: multiple disks, multiple networks"},{"line_number":232,"context_line":"  GET: /allocation_candidates?resources1\u003dVCPU:1\u0026resources2\u003dVGPU:1\u0026required2\u003dHW_GPU_API_DXVA\u0026resources3\u003dMEMORY_MB:1024\u0026resources4\u003dDISK_GB:100\u0026required4\u003dCUSTOM_DISK_SSD\u0026resources5\u003dDISK_GB:50\u0026required5\u003d!CUSTOM_DISK_SSD\u0026resources6\u003dSRIOV_NET_VF:1,CUSTOM_NET_MBPS:1000\u0026resources7\u003dSRIOV_NET_VF:2,CUSTOM_NET_MBPS:2000\u0026group_policy\u003dnone"},{"line_number":233,"context_line":"  # Let\u0027s make that more readable, shall we?"},{"line_number":234,"context_line":"  # /allocation_candidates"},{"line_number":235,"context_line":"  #   \u003d\u003e These could come from cn_left, cn_middle, or cn_right"},{"line_number":236,"context_line":"  #     ?resources1\u003dVCPU:1"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_45aee498","line":233,"in_reply_to":"5f7c97a3_859e3cb6","updated":"2018-05-08 15:39:41.000000000","message":"Turns out I only need to quote the ones starting with ! (i.e. forbidden traits).  Working this change in a followon.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1947c1ff3d5dac60f02f30ab928c1725a44ccc89","unresolved":false,"context_lines":[{"line_number":230,"context_line":""},{"line_number":231,"context_line":"- name: multiple disks, multiple networks"},{"line_number":232,"context_line":"  GET: /allocation_candidates?resources1\u003dVCPU:1\u0026resources2\u003dVGPU:1\u0026required2\u003dHW_GPU_API_DXVA\u0026resources3\u003dMEMORY_MB:1024\u0026resources4\u003dDISK_GB:100\u0026required4\u003dCUSTOM_DISK_SSD\u0026resources5\u003dDISK_GB:50\u0026required5\u003d!CUSTOM_DISK_SSD\u0026resources6\u003dSRIOV_NET_VF:1,CUSTOM_NET_MBPS:1000\u0026resources7\u003dSRIOV_NET_VF:2,CUSTOM_NET_MBPS:2000\u0026group_policy\u003dnone"},{"line_number":233,"context_line":"  # Let\u0027s make that more readable, shall we?"},{"line_number":234,"context_line":"  # /allocation_candidates"},{"line_number":235,"context_line":"  #   \u003d\u003e These could come from cn_left, cn_middle, or cn_right"},{"line_number":236,"context_line":"  #     ?resources1\u003dVCPU:1"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_859e3cb6","line":233,"in_reply_to":"5f7c97a3_9a077b1d","updated":"2018-05-08 15:28:08.000000000","message":"Ah, nice!\n\nSee latest PS, I split lines using double quotes and backslashes, but this would be even prettier.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":73,"context_line":"  status: 200"},{"line_number":74,"context_line":"  response_json_paths:"},{"line_number":75,"context_line":"      $.allocation_requests.`len`: 0"},{"line_number":76,"context_line":"      $.provider_summaries.`len`: 0"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"- name: resources combine"},{"line_number":79,"context_line":"  GET: \"/allocation_candidates\\"}],"source_content_type":"text/x-yaml","patch_set":37,"id":"5f7c97a3_65bc40dc","line":76,"updated":"2018-05-08 15:47:40.000000000","message":"From the API microversion description:\n\n With\n``group_policy\u003disolate``, numbered groups are guaranteed to be satisfied by\n *different* providers - though there may still be overlap with the unnumbered\n group.\n\nThis doesn\u0027t return allocation requests that have VCPU coming from one compute node provider and MEMORY_MB coming from a different compute node provider due to the \"anchor provider\" thing.\n\nHowever, from the description of the microversion, there\u0027s no mention of anchor providers and so a reasonable person might conclude that this particular request should return the allocation requests look like this, right?\n\n allocation_requests:\n    - allocations:\n        cn_left:\n            resources:\n                VCPU: 1\n        cn_middle:\n            resources:\n                MEMORY_MB: 1024\n    - allocations:\n        cn_left:\n            resources:\n                VCPU: 1\n        cn_right:\n            resources:\n                MEMORY_MB: 1024\n    - allocations:\n        cn_middle:\n            resources:\n                VCPU: 1\n        cn_right:\n            resources:\n                MEMORY_MB: 1024\n    - allocations:\n        cn_middle:\n            resources:\n                VCPU: 1\n        cn_left:\n            resources:\n                MEMORY_MB: 1024\n      ... etc\n\nAgain, I know that the anchor provider stuff is what keeps the above from being returned, but reading the REST API notes would give the user no clue that is the case.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":73,"context_line":"  status: 200"},{"line_number":74,"context_line":"  response_json_paths:"},{"line_number":75,"context_line":"      $.allocation_requests.`len`: 0"},{"line_number":76,"context_line":"      $.provider_summaries.`len`: 0"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"- name: resources combine"},{"line_number":79,"context_line":"  GET: \"/allocation_candidates\\"}],"source_content_type":"text/x-yaml","patch_set":37,"id":"5f7c97a3_d491479b","line":76,"in_reply_to":"5f7c97a3_65bc40dc","updated":"2018-05-08 16:53:54.000000000","message":"Okay, I added comments here...","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c9103f672f6f95353b3081210950cd993dee58b7","unresolved":false,"context_lines":[{"line_number":102,"context_line":"      $.allocation_requests.`len`: 3"},{"line_number":103,"context_line":"      $.provider_summaries.`len`: 3"},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"- name: disk sharing isolated"},{"line_number":106,"context_line":"  GET: \"/allocation_candidates\\"},{"line_number":107,"context_line":"      ?resources1\u003dVCPU:1,MEMORY_MB:1024\\"},{"line_number":108,"context_line":"      \u0026resources2\u003dDISK_GB:100\\"},{"line_number":109,"context_line":"      \u0026group_policy\u003disolate\""},{"line_number":110,"context_line":"  status: 200"},{"line_number":111,"context_line":"  response_json_paths:"},{"line_number":112,"context_line":"      $.allocation_requests.`len`: 5"}],"source_content_type":"text/x-yaml","patch_set":37,"id":"5f7c97a3_45ea64ac","line":109,"range":{"start_line":105,"start_character":0,"end_line":109,"end_character":28},"updated":"2018-05-08 15:47:40.000000000","message":"Add a # comment above here explaining why *this* request returns allocation requests and the request from line 68 doesn\u0027t. *This* request involves resources that are provided by *sharing providers* and therefore the \"anchor provider\" constraints that filter out all allocation requests from line 68 do *not* filter out allocation requests for the shared disk provider.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8ba2fbcae793228c7ef56674299c53ef85d371a1","unresolved":false,"context_lines":[{"line_number":102,"context_line":"      $.allocation_requests.`len`: 3"},{"line_number":103,"context_line":"      $.provider_summaries.`len`: 3"},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"- name: disk sharing isolated"},{"line_number":106,"context_line":"  GET: \"/allocation_candidates\\"},{"line_number":107,"context_line":"      ?resources1\u003dVCPU:1,MEMORY_MB:1024\\"},{"line_number":108,"context_line":"      \u0026resources2\u003dDISK_GB:100\\"},{"line_number":109,"context_line":"      \u0026group_policy\u003disolate\""},{"line_number":110,"context_line":"  status: 200"},{"line_number":111,"context_line":"  response_json_paths:"},{"line_number":112,"context_line":"      $.allocation_requests.`len`: 5"}],"source_content_type":"text/x-yaml","patch_set":37,"id":"5f7c97a3_f48c8380","line":109,"range":{"start_line":105,"start_character":0,"end_line":109,"end_character":28},"in_reply_to":"5f7c97a3_45ea64ac","updated":"2018-05-08 16:53:54.000000000","message":"...and here which, taken together with the history/reno addition, should make things clear.","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2c794cf2eff6eb252f0d44b1a67de9d8494a0ad2","unresolved":false,"context_lines":[{"line_number":235,"context_line":"      $.provider_summaries[\"$ENVIRON[\u0027CN_RIGHT\u0027]\"].resources[DISK_GB][capacity]: 500"},{"line_number":236,"context_line":"      $.provider_summaries[\"$ENVIRON[\u0027SHR_DISK_1\u0027]\"].resources[DISK_GB][capacity]: 1000"},{"line_number":237,"context_line":""},{"line_number":238,"context_line":"- name: multiple member_of"},{"line_number":239,"context_line":"  GET: \"/allocation_candidates\\"},{"line_number":240,"context_line":"      ?resources1\u003dVCPU:1\\"},{"line_number":241,"context_line":"      \u0026resources2\u003dDISK_GB:100\\"}],"source_content_type":"text/x-yaml","patch_set":37,"id":"5f7c97a3_3a8667dd","line":238,"updated":"2018-05-08 15:13:15.000000000","message":"...here","commit_id":"b0e09fdd6fb240a632f10fa435895201360ee605"}],"placement-api-ref/source/allocation_candidates.inc":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5193b662f348f4f59ef71054b6951bda8a821215","unresolved":false,"context_lines":[{"line_number":31,"context_line":""},{"line_number":32,"context_line":"  - resources: resources_query_required"},{"line_number":33,"context_line":"  - resourcesN: resources_query_granular"},{"line_number":34,"context_line":"  - required: required_traits_unnumbered"},{"line_number":35,"context_line":"  - requiredN: required_traits_granular"},{"line_number":36,"context_line":"  - limit: allocation_candidates_limit"},{"line_number":37,"context_line":"  - member_of: member_of"}],"source_content_type":"text/x-c++src","patch_set":2,"id":"bf659307_73cd5bb5","line":34,"range":{"start_line":34,"start_character":0,"end_line":34,"end_character":40},"updated":"2018-04-03 18:26:42.000000000","message":"This should probably go right after \u0027resources\u0027.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[{"line_number":31,"context_line":""},{"line_number":32,"context_line":"  - resources: resources_query_required"},{"line_number":33,"context_line":"  - resourcesN: resources_query_granular"},{"line_number":34,"context_line":"  - required: required_traits_unnumbered"},{"line_number":35,"context_line":"  - requiredN: required_traits_granular"},{"line_number":36,"context_line":"  - limit: allocation_candidates_limit"},{"line_number":37,"context_line":"  - member_of: member_of"}],"source_content_type":"text/x-c++src","patch_set":2,"id":"bf659307_d2b40bf5","line":34,"range":{"start_line":34,"start_character":0,"end_line":34,"end_character":40},"in_reply_to":"bf659307_73cd5bb5","updated":"2018-04-16 18:33:40.000000000","message":"Done","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5193b662f348f4f59ef71054b6951bda8a821215","unresolved":false,"context_lines":[{"line_number":33,"context_line":"  - resourcesN: resources_query_granular"},{"line_number":34,"context_line":"  - required: required_traits_unnumbered"},{"line_number":35,"context_line":"  - requiredN: required_traits_granular"},{"line_number":36,"context_line":"  - limit: allocation_candidates_limit"},{"line_number":37,"context_line":"  - member_of: member_of"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"Response (microversions 1.12 - )"}],"source_content_type":"text/x-c++src","patch_set":2,"id":"bf659307_73423b11","line":36,"range":{"start_line":36,"start_character":0,"end_line":36,"end_character":38},"updated":"2018-04-03 18:26:42.000000000","message":"Is it important that these go in order of microversion availability?  That would put \u0027limit\u0027 in front of \u0027required\u0027, which makes less logical sense IMO.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[{"line_number":33,"context_line":"  - resourcesN: resources_query_granular"},{"line_number":34,"context_line":"  - required: required_traits_unnumbered"},{"line_number":35,"context_line":"  - requiredN: required_traits_granular"},{"line_number":36,"context_line":"  - limit: allocation_candidates_limit"},{"line_number":37,"context_line":"  - member_of: member_of"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"Response (microversions 1.12 - )"}],"source_content_type":"text/x-c++src","patch_set":2,"id":"bf659307_f2b90fe9","line":36,"range":{"start_line":36,"start_character":0,"end_line":36,"end_character":38},"in_reply_to":"bf659307_73423b11","updated":"2018-04-16 18:33:40.000000000","message":"Leaving it alone for now.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"68168401c80f54eba41fa24b7a18d7949bee8032","unresolved":false,"context_lines":[{"line_number":29,"context_line":""},{"line_number":30,"context_line":".. rest_parameters:: parameters.yaml"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"  - resources: resources_query_ac"},{"line_number":33,"context_line":"  - required: required_traits_unnumbered"},{"line_number":34,"context_line":"  - member_of: member_of_1_21"},{"line_number":35,"context_line":"  - resourcesN: resources_query_granular"}],"source_content_type":"text/x-c++src","patch_set":34,"id":"5f7c97a3_5e88441e","line":32,"range":{"start_line":32,"start_character":31,"end_line":32,"end_character":33},"updated":"2018-05-03 11:28:20.000000000","message":"super small nit: maybe resource_query_unnumbered is better like in case of traits below","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":29,"context_line":""},{"line_number":30,"context_line":".. rest_parameters:: parameters.yaml"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"  - resources: resources_query_ac"},{"line_number":33,"context_line":"  - required: required_traits_unnumbered"},{"line_number":34,"context_line":"  - member_of: member_of_1_21"},{"line_number":35,"context_line":"  - resourcesN: resources_query_granular"}],"source_content_type":"text/x-c++src","patch_set":34,"id":"5f7c97a3_8d754c9b","line":32,"range":{"start_line":32,"start_character":31,"end_line":32,"end_character":33},"in_reply_to":"5f7c97a3_5e88441e","updated":"2018-05-04 14:48:31.000000000","message":"The \u0027ac\u0027 is for \u0027allocation candidates\u0027, to distinguish from its counterpart in GET /resource_providers.  I guess which name makes more sense depends on whether you\u0027re reading this file or parameters.yaml :)","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"}],"placement-api-ref/source/parameters.yaml":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5193b662f348f4f59ef71054b6951bda8a821215","unresolved":false,"context_lines":[{"line_number":82,"context_line":"    positive integer suffix corresponding with a ``resourcesN`` parameter."},{"line_number":83,"context_line":"    The value format is the same as for the (unnumbered) ``required``"},{"line_number":84,"context_line":"    parameter; but all of the resources and traits specified in a numbered"},{"line_number":85,"context_line":"    grouping will always be satisfied by the same resource provider."},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    It is an error to specify a ``requiredN`` parameter without a corresponding"},{"line_number":88,"context_line":"    ``resourcesN`` parameter with the same suffix."}],"source_content_type":"text/x-yaml","patch_set":2,"id":"bf659307_d36b0782","line":85,"updated":"2018-04-03 18:26:42.000000000","message":"Mention relationship between/among different groups.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[{"line_number":82,"context_line":"    positive integer suffix corresponding with a ``resourcesN`` parameter."},{"line_number":83,"context_line":"    The value format is the same as for the (unnumbered) ``required``"},{"line_number":84,"context_line":"    parameter; but all of the resources and traits specified in a numbered"},{"line_number":85,"context_line":"    grouping will always be satisfied by the same resource provider."},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    It is an error to specify a ``requiredN`` parameter without a corresponding"},{"line_number":88,"context_line":"    ``resourcesN`` parameter with the same suffix."}],"source_content_type":"text/x-yaml","patch_set":2,"id":"bf659307_f2aeef96","line":85,"in_reply_to":"bf659307_d36b0782","updated":"2018-04-16 18:33:40.000000000","message":"Done","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5193b662f348f4f59ef71054b6951bda8a821215","unresolved":false,"context_lines":[{"line_number":153,"context_line":"    The parameter key is ``resourcesN``, where ``N`` represents a unique"},{"line_number":154,"context_line":"    positive integer suffix.  The value format is the same as for the"},{"line_number":155,"context_line":"    (unnumbered) ``resources`` parameter, but the resources specified in a"},{"line_number":156,"context_line":"    ``resourcesN`` parameter will always be satisfied by a single provider."},{"line_number":157,"context_line":"min_version: 1.__MICROVERSION__"},{"line_number":158,"context_line":"resources_query_required:"},{"line_number":159,"context_line":"  type: string"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"bf659307_b30a13cf","line":156,"updated":"2018-04-03 18:26:42.000000000","message":"Mention relationship between/among different groups.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[{"line_number":153,"context_line":"    The parameter key is ``resourcesN``, where ``N`` represents a unique"},{"line_number":154,"context_line":"    positive integer suffix.  The value format is the same as for the"},{"line_number":155,"context_line":"    (unnumbered) ``resources`` parameter, but the resources specified in a"},{"line_number":156,"context_line":"    ``resourcesN`` parameter will always be satisfied by a single provider."},{"line_number":157,"context_line":"min_version: 1.__MICROVERSION__"},{"line_number":158,"context_line":"resources_query_required:"},{"line_number":159,"context_line":"  type: string"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"bf659307_529d5b64","line":156,"in_reply_to":"bf659307_b30a13cf","updated":"2018-04-16 18:33:40.000000000","message":"Done","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"15c2388ca7d023da6953fac9843cb2d9a330e3ad","unresolved":false,"context_lines":[{"line_number":163,"context_line":"    ``resourcesN`` parameter will always be satisfied by a single provider."},{"line_number":164,"context_line":"    Separate groupings - numbered or unnumbered - may or may not be satisfied"},{"line_number":165,"context_line":"    by the same provider."},{"line_number":166,"context_line":"min_version: 1.22"},{"line_number":167,"context_line":"resources_query_required:"},{"line_number":168,"context_line":"  type: string"},{"line_number":169,"context_line":"  in: query"}],"source_content_type":"text/x-yaml","patch_set":13,"id":"9f6a8fd7_3f1f02b8","line":166,"updated":"2018-04-20 13:03:25.000000000","message":"Whoops! :)","commit_id":"d0ffd0196ac7b9958132be3f336702c3bcdfd96f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"118630331041781938742cf9d4c0dd9f705db2ad","unresolved":false,"context_lines":[{"line_number":163,"context_line":"    ``resourcesN`` parameter will always be satisfied by a single provider."},{"line_number":164,"context_line":"    Separate groupings - numbered or unnumbered - may or may not be satisfied"},{"line_number":165,"context_line":"    by the same provider."},{"line_number":166,"context_line":"min_version: 1.22"},{"line_number":167,"context_line":"resources_query_required:"},{"line_number":168,"context_line":"  type: string"},{"line_number":169,"context_line":"  in: query"}],"source_content_type":"text/x-yaml","patch_set":13,"id":"9f6a8fd7_7f781ac3","line":166,"in_reply_to":"9f6a8fd7_3f1f02b8","updated":"2018-04-20 13:18:15.000000000","message":"Thanks Stephen.  It would have taken me a month of Sundays to spot this.","commit_id":"d0ffd0196ac7b9958132be3f336702c3bcdfd96f"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"fe8cfea0c138ce15a08619da394e4a932886b4b6","unresolved":false,"context_lines":[{"line_number":178,"context_line":"    (unnumbered) ``resources`` parameter, but the resources specified in a"},{"line_number":179,"context_line":"    ``resourcesN`` parameter will always be satisfied by a single provider."},{"line_number":180,"context_line":"    Separate groupings - numbered or unnumbered - may or may not be satisfied"},{"line_number":181,"context_line":"    by the same provider."},{"line_number":182,"context_line":"  min_version: 1.24"},{"line_number":183,"context_line":"resources_query_required:"},{"line_number":184,"context_line":"  type: string"}],"source_content_type":"text/x-yaml","patch_set":25,"id":"9f6a8fd7_9d6b4384","line":181,"updated":"2018-04-26 12:04:09.000000000","message":"Is it worth saying \"depending on the group_policy parameter\"?","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0558995f5d9452d3d1d044cd15dde687fd7d2777","unresolved":false,"context_lines":[{"line_number":178,"context_line":"    (unnumbered) ``resources`` parameter, but the resources specified in a"},{"line_number":179,"context_line":"    ``resourcesN`` parameter will always be satisfied by a single provider."},{"line_number":180,"context_line":"    Separate groupings - numbered or unnumbered - may or may not be satisfied"},{"line_number":181,"context_line":"    by the same provider."},{"line_number":182,"context_line":"  min_version: 1.24"},{"line_number":183,"context_line":"resources_query_required:"},{"line_number":184,"context_line":"  type: string"}],"source_content_type":"text/x-yaml","patch_set":25,"id":"9f6a8fd7_8663f4b1","line":181,"in_reply_to":"9f6a8fd7_9d6b4384","updated":"2018-04-26 13:51:58.000000000","message":"Totally.","commit_id":"44c7227f03bd7fc6948459efa7ff87cb89ebac1a"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"68168401c80f54eba41fa24b7a18d7949bee8032","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    ``group_policy`` parameter."},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"    It is an error to specify a ``member_ofN`` parameter without a"},{"line_number":98,"context_line":"    corresponding ``resourcesN`` parameter with the same suffix."},{"line_number":99,"context_line":"  min_version: 1.24"},{"line_number":100,"context_line":"project_id: \u0026project_id"},{"line_number":101,"context_line":"  type: string"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_3e98e868","line":98,"range":{"start_line":98,"start_character":43,"end_line":98,"end_character":63},"updated":"2018-05-03 11:28:20.000000000","message":"\"with the same N suffix.\"\nAlso I would define that N could be any positive integer as you did in the other descriptions.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"602e5d9b0569cf20804929d79e142e718e0db804","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    ``group_policy`` parameter."},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"    It is an error to specify a ``member_ofN`` parameter without a"},{"line_number":98,"context_line":"    corresponding ``resourcesN`` parameter with the same suffix."},{"line_number":99,"context_line":"  min_version: 1.24"},{"line_number":100,"context_line":"project_id: \u0026project_id"},{"line_number":101,"context_line":"  type: string"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_4d6f34c5","line":98,"range":{"start_line":98,"start_character":43,"end_line":98,"end_character":63},"in_reply_to":"5f7c97a3_3e98e868","updated":"2018-05-04 14:48:31.000000000","message":"Will do.","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"68168401c80f54eba41fa24b7a18d7949bee8032","unresolved":false,"context_lines":[{"line_number":137,"context_line":"    Allocation requests in the response will be for resource providers that"},{"line_number":138,"context_line":"    have capacity for all requested resources and the set of those resource"},{"line_number":139,"context_line":"    providers will *collectively* contain all of the required traits. These"},{"line_number":140,"context_line":"    traits may be satisfied by any provider in the same non-sharing tree or"},{"line_number":141,"context_line":"    associated via aggregate. **Starting from microversion 1.22** traits which"},{"line_number":142,"context_line":"    are forbidden from any resource provider may be expressed by prefixing a"},{"line_number":143,"context_line":"    trait with a ``!``."}],"source_content_type":"text/x-yaml","patch_set":34,"id":"5f7c97a3_c158f557","line":140,"range":{"start_line":140,"start_character":18,"end_line":140,"end_character":43},"updated":"2018-05-03 11:28:20.000000000","message":"any provided that provides resources for the request","commit_id":"826dd560ad99cf80ebfa5be980c9b4e60ea01ee5"}],"releasenotes/notes/placement-granular-resource-requests-944f9b73f306429f.yaml":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5193b662f348f4f59ef71054b6951bda8a821215","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":"    TODO(efried): Is this supposed to talk about the placement side, the"},{"line_number":5,"context_line":"    operator side (flavor extra_specs syntax), or both??"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"    In version 1.__MICROVERSION__ the ``GET /allocation_candidates`` API is enhanced to"},{"line_number":8,"context_line":"    accept numbered groupings of resource and required trait requests.  A"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"bf659307_93626fad","line":5,"range":{"start_line":4,"start_character":18,"end_line":5,"end_character":56},"updated":"2018-04-03 18:26:42.000000000","message":"This patch should talk about the placement side, since it\u0027s enabling the placement side.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","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":"    TODO(efried): Is this supposed to talk about the placement side, the"},{"line_number":5,"context_line":"    operator side (flavor extra_specs syntax), or both??"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"    In version 1.__MICROVERSION__ the ``GET /allocation_candidates`` API is enhanced to"},{"line_number":8,"context_line":"    accept numbered groupings of resource and required trait requests.  A"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"bf659307_729adf6e","line":5,"range":{"start_line":4,"start_character":18,"end_line":5,"end_character":56},"in_reply_to":"bf659307_93626fad","updated":"2018-04-16 18:33:40.000000000","message":"Done","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"5193b662f348f4f59ef71054b6951bda8a821215","unresolved":false,"context_lines":[{"line_number":16,"context_line":"    you may specify ``resources42\u003dXXX`` without a corresponding"},{"line_number":17,"context_line":"    ``required42\u003dYYY``. However, the reverse (specifying ``required42\u003dYYY``"},{"line_number":18,"context_line":"    without ``resources42\u003dXXX``) will result in an error."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"    The semantic of the (unnumbered) ``resources`` and ``required`` query"},{"line_number":21,"context_line":"    parameters is unchanged: the resources and traits specified thereby may be"},{"line_number":22,"context_line":"    satisfied by any provider in the same non-sharing tree or associated via"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"bf659307_13765f71","line":19,"updated":"2018-04-03 18:26:42.000000000","message":"Mention relationship between/among different groups.","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"f7c1766a8ec320affc268e78bb22826f45a476e8","unresolved":false,"context_lines":[{"line_number":16,"context_line":"    you may specify ``resources42\u003dXXX`` without a corresponding"},{"line_number":17,"context_line":"    ``required42\u003dYYY``. However, the reverse (specifying ``required42\u003dYYY``"},{"line_number":18,"context_line":"    without ``resources42\u003dXXX``) will result in an error."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"    The semantic of the (unnumbered) ``resources`` and ``required`` query"},{"line_number":21,"context_line":"    parameters is unchanged: the resources and traits specified thereby may be"},{"line_number":22,"context_line":"    satisfied by any provider in the same non-sharing tree or associated via"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"bf659307_328ea72e","line":19,"in_reply_to":"bf659307_13765f71","updated":"2018-04-16 18:33:40.000000000","message":"Done","commit_id":"16aca6cea2578525d1adbac0559bd20296bb9542"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"33b0106555c006ba7e9b3ba42d0eca8f8f5c6afa","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":"    In version 1.22 the ``GET /allocation_candidates`` API is enhanced to"},{"line_number":5,"context_line":"    accept numbered groupings of resource and required trait requests. A"},{"line_number":6,"context_line":"    ``resources`` query parameter key with a positive integer suffix (e.g."},{"line_number":7,"context_line":"    ``resources42``) will be logically associated with a ``required`` query"}],"source_content_type":"text/x-yaml","patch_set":14,"id":"9f6a8fd7_59577127","line":4,"range":{"start_line":4,"start_character":17,"end_line":4,"end_character":20},"updated":"2018-04-20 14:33:39.000000000","message":"23","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d2e27cbdd25914c29b1000f60d3f72d588115bde","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":"    In version 1.22 the ``GET /allocation_candidates`` API is enhanced to"},{"line_number":5,"context_line":"    accept numbered groupings of resource and required trait requests. A"},{"line_number":6,"context_line":"    ``resources`` query parameter key with a positive integer suffix (e.g."},{"line_number":7,"context_line":"    ``resources42``) will be logically associated with a ``required`` query"}],"source_content_type":"text/x-yaml","patch_set":14,"id":"9f6a8fd7_fc8513d0","line":4,"range":{"start_line":4,"start_character":17,"end_line":4,"end_character":20},"in_reply_to":"9f6a8fd7_59577127","updated":"2018-04-20 14:52:06.000000000","message":"Yeah, I effed that up in a number of places when I went from 22 to 23.  Fixed in the next PS.\n\nWhen I started this, I was actually using a __MICROVERSION__ macro throughout so I could just do a recursive sed -i.  But I had to go real numbering when I started needing tests to run.\n\nI\u0027m considering taking a Leafe from Ed\u0027s book and using some high number so I only have to re-change it once.","commit_id":"1ee9cce7d74cfc18257b92e36d341b545a2266f8"}]}
