)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"e00ab42c3e061ec7947344beeff0deb5e84dda67","unresolved":false,"context_lines":[{"line_number":19,"context_line":"that have *any* of those aggregate UUIDs associated with them."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Change-Id: Ib4f1955f06f2159dfb221f3d2bc8ff7bfce71ee2"},{"line_number":22,"context_line":"blueprint: allocation-candidates-member-of"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"bf659307_cf504535","line":22,"range":{"start_line":22,"start_character":11,"end_line":22,"end_character":42},"updated":"2018-04-13 19:58:51.000000000","message":"alloc-candidates-member-of","commit_id":"f8ec83f1694c81cb2b42f8d5afc5b4230f0c408e"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"ee0b5bbe65109d15862c5fbf7328ba9d5e1292d4","unresolved":false,"context_lines":[{"line_number":19,"context_line":"that have *any* of those aggregate UUIDs associated with them."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Change-Id: Ib4f1955f06f2159dfb221f3d2bc8ff7bfce71ee2"},{"line_number":22,"context_line":"blueprint: allocation-candidates-member-of"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"bf659307_af32b10e","line":22,"range":{"start_line":22,"start_character":11,"end_line":22,"end_character":42},"in_reply_to":"bf659307_cf504535","updated":"2018-04-13 20:00:02.000000000","message":"heh, fixed","commit_id":"f8ec83f1694c81cb2b42f8d5afc5b4230f0c408e"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":4,"context_line":"Commit:     Jay Pipes \u003cjaypipes@gmail.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2018-04-13 16:02:19 -0400"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"support multiple member_of qparams for GET /r-ps"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Adds a new placement API microversion that supports specifying multiple"},{"line_number":10,"context_line":"member_of parameters to the GET /resource_providers endpoint. When"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"bf659307_004daac2","line":7,"range":{"start_line":7,"start_character":39,"end_line":7,"end_character":48},"updated":"2018-04-13 22:06:47.000000000","message":"Per the spec, we\u0027re going to do this for both GET /resource_providers and GET /allocation_candidates.  Were you planning to do the latter in a different change set?\n\nIf so, please mention at the bottom of the commit message that that\u0027s forthcoming.\n\nPersonally, my preference would be to do both in the same microversion, since they\u0027re the same feature.","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":12,"context_line":""},{"line_number":13,"context_line":"When multiple member_of parameters are found, they are passed down to"},{"line_number":14,"context_line":"the ResourceProviderList.get_by_filters() method as a list. Items in"},{"line_number":15,"context_line":"this list are either an aggregate UUID or a list of aggregate UUIDs."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"The list of member_of items is evaluated so that resource providers"},{"line_number":18,"context_line":"matching ALL of the member_of constraints are returned."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"9f6a8fd7_f140350a","line":15,"range":{"start_line":15,"start_character":14,"end_line":15,"end_character":41},"updated":"2018-04-17 17:32:48.000000000","message":"x","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":12,"context_line":""},{"line_number":13,"context_line":"When multiple member_of parameters are found, they are passed down to"},{"line_number":14,"context_line":"the ResourceProviderList.get_by_filters() method as a list. Items in"},{"line_number":15,"context_line":"this list are either an aggregate UUID or a list of aggregate UUIDs."},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"The list of member_of items is evaluated so that resource providers"},{"line_number":18,"context_line":"matching ALL of the member_of constraints are returned."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"9f6a8fd7_7dc6346a","line":15,"range":{"start_line":15,"start_character":14,"end_line":15,"end_character":41},"in_reply_to":"9f6a8fd7_f140350a","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":17,"context_line":"The list of member_of items is evaluated so that resource providers"},{"line_number":18,"context_line":"matching ALL of the member_of constraints are returned."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"When a member_of item is a list of UUIDs, we look up resource providers"},{"line_number":21,"context_line":"that have *any* of those aggregate UUIDs associated with them."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"Change-Id: Ib4f1955f06f2159dfb221f3d2bc8ff7bfce71ee2"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"9f6a8fd7_e4087529","line":20,"range":{"start_line":20,"start_character":22,"end_line":20,"end_character":34},"updated":"2018-04-17 17:32:48.000000000","message":"contains multiple","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":17,"context_line":"The list of member_of items is evaluated so that resource providers"},{"line_number":18,"context_line":"matching ALL of the member_of constraints are returned."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"When a member_of item is a list of UUIDs, we look up resource providers"},{"line_number":21,"context_line":"that have *any* of those aggregate UUIDs associated with them."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"Change-Id: Ib4f1955f06f2159dfb221f3d2bc8ff7bfce71ee2"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"9f6a8fd7_1d8a981a","line":20,"range":{"start_line":20,"start_character":22,"end_line":20,"end_character":34},"in_reply_to":"9f6a8fd7_e4087529","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"}],"nova/api/openstack/placement/handlers/resource_provider.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b500136153c5d682c117d0e21cce09c2da046b43","unresolved":false,"context_lines":[{"line_number":194,"context_line":"    util.validate_query_params(req, schema)"},{"line_number":195,"context_line":""},{"line_number":196,"context_line":"    filters \u003d {}"},{"line_number":197,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":198,"context_line":"    # params at microversion 1.22."},{"line_number":199,"context_line":"    multi_member_of \u003d want_version.matches((1, 22))"},{"line_number":200,"context_line":"    if \u0027member_of\u0027 in req.GET:"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_155c0a17","line":197,"updated":"2018-04-13 20:50:05.000000000","message":"Golden opportunity to pull this out into a normalize_member_of_qs_param method and call it in the conditional sequence at L229-232.","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b500136153c5d682c117d0e21cce09c2da046b43","unresolved":false,"context_lines":[{"line_number":205,"context_line":"        for value in req.GET.getall(\u0027member_of\u0027):"},{"line_number":206,"context_line":"            if value.startswith(\u0027in:\u0027):"},{"line_number":207,"context_line":"                values.append(value[3:].split(\u0027,\u0027))"},{"line_number":208,"context_line":"            else:"},{"line_number":209,"context_line":"                values.append(value)"},{"line_number":210,"context_line":"        filters[\u0027member_of\u0027] \u003d values"},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"        # Make sure the values are actually UUIDs."}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_95f33a09","line":209,"range":{"start_line":208,"start_character":12,"end_line":209,"end_character":36},"updated":"2018-04-13 20:50:05.000000000","message":"Having not yet looked at how this is processed, why not have the value always be a list?  I assume the SQL will be `IN`, which works with one value (and can\u0027t be THAT much less efficient than \u003d\u003d).  And it will mean you don\u0027t have to do isinstance(list) below (and, I\u0027m assuming, in your SQL builder).","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c47954e05a725640e94222ec7fadaea90ec0ddc3","unresolved":false,"context_lines":[{"line_number":205,"context_line":"        for value in req.GET.getall(\u0027member_of\u0027):"},{"line_number":206,"context_line":"            if value.startswith(\u0027in:\u0027):"},{"line_number":207,"context_line":"                values.append(value[3:].split(\u0027,\u0027))"},{"line_number":208,"context_line":"            else:"},{"line_number":209,"context_line":"                values.append(value)"},{"line_number":210,"context_line":"        filters[\u0027member_of\u0027] \u003d values"},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"        # Make sure the values are actually UUIDs."}],"source_content_type":"text/x-python","patch_set":3,"id":"9f6a8fd7_b24bc485","line":209,"range":{"start_line":208,"start_character":12,"end_line":209,"end_character":36},"in_reply_to":"bf659307_95f33a09","updated":"2018-04-16 13:52:54.000000000","message":"ack, that\u0027s a good point.","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":196,"context_line":"    util.validate_query_params(req, schema)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_d11e510b","line":200,"range":{"start_line":199,"start_character":43,"end_line":200,"end_character":34},"updated":"2018-04-17 17:32:48.000000000","message":"It\u0027s not just that; the handling for making the value a list was relevant before this microversion.\n\nYou could remove this comment without harm, especially if you change the below.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1348876968f31eeece8200e98e1ec5a5fd3a4a1e","unresolved":false,"context_lines":[{"line_number":196,"context_line":"    util.validate_query_params(req, schema)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_3889aa74","line":200,"range":{"start_line":199,"start_character":43,"end_line":200,"end_character":34},"in_reply_to":"9f6a8fd7_7dc2b435","updated":"2018-04-17 20:27:53.000000000","message":"Right; what I\u0027m saying is that we had \"special handling\" before 1.23 anyway (for in:) so the comment doesn\u0027t tell the whole story.  And since the special handling for that and the new stuff is all within the method you\u0027re calling, it probably makes sense for any of that to be described therein anyway.\n\n[Later] Ohh, now it clicks; the comment is explaining why this isn\u0027t in the main loop below.  Okay, so yeah, this is good as is.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":196,"context_line":"    util.validate_query_params(req, schema)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_7dc2b435","line":200,"range":{"start_line":199,"start_character":43,"end_line":200,"end_character":34},"in_reply_to":"9f6a8fd7_d11e510b","updated":"2018-04-17 20:03:30.000000000","message":"It\u0027s true that we allowed the value element of a single member_of k/v pair to contain multiple UUIDs before. But we didn\u0027t allow multiple k/v pairs for the member_of qstring param.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"    qpkeys \u003d (\u0027uuid\u0027, \u0027name\u0027, \u0027in_tree\u0027, \u0027resources\u0027, \u0027required\u0027)"},{"line_number":205,"context_line":"    for attr in qpkeys:"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_51c1e153","line":202,"range":{"start_line":201,"start_character":0,"end_line":202,"end_character":70},"updated":"2018-04-17 17:32:48.000000000","message":"I think this would flow better as a new elif in the switch on L208-212.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"    qpkeys \u003d (\u0027uuid\u0027, \u0027name\u0027, \u0027in_tree\u0027, \u0027resources\u0027, \u0027required\u0027)"},{"line_number":205,"context_line":"    for attr in qpkeys:"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_9da2289a","line":202,"range":{"start_line":201,"start_character":0,"end_line":202,"end_character":70},"in_reply_to":"9f6a8fd7_51c1e153","updated":"2018-04-17 20:03:30.000000000","message":"Unfortunately, that doesn\u0027t work because value is the last item in req.GET[key]. For the member_of parameter, we need to look at all the instances of the member_of\u003dval k/v pairs in the multi-dict.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1348876968f31eeece8200e98e1ec5a5fd3a4a1e","unresolved":false,"context_lines":[{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""},{"line_number":204,"context_line":"    qpkeys \u003d (\u0027uuid\u0027, \u0027name\u0027, \u0027in_tree\u0027, \u0027resources\u0027, \u0027required\u0027)"},{"line_number":205,"context_line":"    for attr in qpkeys:"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_f8d01253","line":202,"range":{"start_line":201,"start_character":0,"end_line":202,"end_character":70},"in_reply_to":"9f6a8fd7_9da2289a","updated":"2018-04-17 20:27:53.000000000","message":"Oh, right, that makes sense.\n\nWe could change the loop below to use getall() and then just use the last item for the ones that aren\u0027t member_of.  Better yet, to throw 400 if there\u0027s more than one entry for those.  But that\u0027s technically a behavior change, so we can\u0027t do that without a microversion.  Sigh.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_e352f434","line":200,"range":{"start_line":200,"start_character":31,"end_line":200,"end_character":33},"updated":"2018-04-25 19:30:44.000000000","message":"24","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_c19d5567","line":200,"range":{"start_line":200,"start_character":29,"end_line":200,"end_character":34},"updated":"2018-05-03 10:22:16.000000000","message":"1.24","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"bd43ee0a46175b3d12ef16a4f04d5f1699c9b985","unresolved":false,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    filters \u003d {}"},{"line_number":199,"context_line":"    # special handling of member_of qparam since we allow multiple member_of"},{"line_number":200,"context_line":"    # params at microversion 1.23."},{"line_number":201,"context_line":"    if \u0027member_of\u0027 in req.GET:"},{"line_number":202,"context_line":"        filters[\u0027member_of\u0027] \u003d util.normalize_member_of_qs_params(req)"},{"line_number":203,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_12215d4e","line":200,"range":{"start_line":200,"start_character":29,"end_line":200,"end_character":34},"in_reply_to":"5f7c97a3_c19d5567","updated":"2018-05-03 13:02:43.000000000","message":"Done","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"}],"nova/api/openstack/placement/microversion.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":61,"context_line":"    \u00271.20\u0027,  # Return 200 with provider payload from POST /resource_providers"},{"line_number":62,"context_line":"    \u00271.21\u0027,  # Support ?member_of\u003d\u003cagg UUIDs\u003e queryparam on"},{"line_number":63,"context_line":"             # GET /allocation_candidates"},{"line_number":64,"context_line":"    \u00271.22\u0027,  # Support multiple ?member_of\u003d\u003cagg UUIDs\u003e queryparams on"},{"line_number":65,"context_line":"             # GET /resource_providers"},{"line_number":66,"context_line":"]"},{"line_number":67,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_a0f39e08","line":64,"range":{"start_line":64,"start_character":4,"end_line":64,"end_character":10},"updated":"2018-04-13 22:06:47.000000000","message":"alas, you\u0027re prolly gonna lose to https://review.openstack.org/#/c/556820/","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"}],"nova/api/openstack/placement/objects/resource_provider.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_c0d3325f","line":658,"range":{"start_line":658,"start_character":59,"end_line":658,"end_character":63},"updated":"2018-04-13 22:06:47.000000000","message":"lists","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_20df8e66","line":658,"range":{"start_line":658,"start_character":18,"end_line":658,"end_character":20},"updated":"2018-04-13 22:06:47.000000000","message":"of","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c47954e05a725640e94222ec7fadaea90ec0ddc3","unresolved":false,"context_lines":[{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9f6a8fd7_923fa0d5","line":658,"range":{"start_line":658,"start_character":18,"end_line":658,"end_character":20},"in_reply_to":"bf659307_20df8e66","updated":"2018-04-16 13:52:54.000000000","message":"Done","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"c47954e05a725640e94222ec7fadaea90ec0ddc3","unresolved":false,"context_lines":[{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9f6a8fd7_322494c6","line":658,"range":{"start_line":658,"start_character":59,"end_line":658,"end_character":63},"in_reply_to":"bf659307_c0d3325f","updated":"2018-04-16 13:52:54.000000000","message":"Done","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""},{"line_number":662,"context_line":"                      For example, if member_of is:"},{"line_number":663,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_80c9baac","line":660,"range":{"start_line":660,"start_character":45,"end_line":660,"end_character":50},"updated":"2018-04-13 22:06:47.000000000","message":"its members are","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":667,"context_line":"                      ]"},{"line_number":668,"context_line":""},{"line_number":669,"context_line":"                      we will return all the resource providers that are"},{"line_number":670,"context_line":"                      associated with agg1 as well as either (agg2 or agg3)"},{"line_number":671,"context_line":""},{"line_number":672,"context_line":"    :returns: A list of internal resource provider IDs having all required"},{"line_number":673,"context_line":"              aggregate associations"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_00bdaa00","line":670,"range":{"start_line":670,"start_character":54,"end_line":670,"end_character":75},"updated":"2018-04-13 22:06:47.000000000","message":"either/or implies xor (see release note comment).  For this docstring, suggest `in (agg2, agg3)`","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":711,"context_line":"        r[0]: r[1] for r in context.session.execute(agg_sel).fetchall()"},{"line_number":712,"context_line":"    }"},{"line_number":713,"context_line":""},{"line_number":714,"context_line":"    # If the length of agg_uuid_map isn\u0027t equal to the length of requested"},{"line_number":715,"context_line":"    # aggregates in member_of, that means the user requested a non-existent"},{"line_number":716,"context_line":"    # aggregate UUID. In this case, simply return an empty list."},{"line_number":717,"context_line":"    if len(agg_uuids) !\u003d len(agg_uuid_map):"},{"line_number":718,"context_line":"        return []"},{"line_number":719,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_404c0241","line":716,"range":{"start_line":714,"start_character":0,"end_line":716,"end_character":64},"updated":"2018-04-13 22:06:47.000000000","message":"If I say in:agg1,agg2 and there\u0027s no agg2, but there are providers in agg1, I should still get \u0027em.\n\nOr it should be an error to specify any agg that doesn\u0027t exist.  /me looks at spec...\n\nOkay, the spec doesn\u0027t say.  But I think returning no hits isn\u0027t the right thing here.\n\n[later] Oh, yeah, it should be that first thing (no error, keep looking) since agg UUIDs are ephemeral, and we don\u0027t currently clean them up when their last member is deleted.","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":721,"context_line":"    rp_tbl \u003d sa.alias(_RP_TBL, name\u003d\u0027rp\u0027)"},{"line_number":722,"context_line":"    rpa_tbl \u003d sa.alias(_RP_AGG_TBL, name\u003d\u0027rpa%d\u0027 % rpa_alias_num)"},{"line_number":723,"context_line":"    members \u003d member_of.pop(0)"},{"line_number":724,"context_line":"    if isinstance(members, list):"},{"line_number":725,"context_line":"        agg_ids \u003d [agg_uuid_map[member] for member in members]"},{"line_number":726,"context_line":"        join_cond \u003d sa.and_("},{"line_number":727,"context_line":"            rp_tbl.c.id \u003d\u003d rpa_tbl.c.resource_provider_id,"},{"line_number":728,"context_line":"            rpa_tbl.c.aggregate_id.in_(agg_ids))"},{"line_number":729,"context_line":"    else:"},{"line_number":730,"context_line":"        agg_id \u003d agg_uuid_map[members]"},{"line_number":731,"context_line":"        join_cond \u003d sa.and_("}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_20146ee8","line":728,"range":{"start_line":724,"start_character":0,"end_line":728,"end_character":48},"updated":"2018-04-13 22:06:47.000000000","message":"Yeah, so if members was always a list, you could just have this condition, and if it was a list of one, you would happily construct `AND rp.id \u003d\u003d rpa.rp_id AND rpa.aggregate_id IN (that_one_agg)`","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":733,"context_line":"            rpa_tbl.c.aggregate_id \u003d\u003d agg_id)"},{"line_number":734,"context_line":"    join_chain \u003d sa.join(rp_tbl, rpa_tbl, join_cond)"},{"line_number":735,"context_line":""},{"line_number":736,"context_line":"    for members in member_of:"},{"line_number":737,"context_line":"        rpa_alias_num +\u003d 1"},{"line_number":738,"context_line":"        rpa_tbl \u003d sa.alias(_RP_AGG_TBL, name\u003d\u0027rpa%d\u0027 % rpa_alias_num)"},{"line_number":739,"context_line":"        if isinstance(members, list):"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_20c22e54","line":736,"range":{"start_line":736,"start_character":4,"end_line":736,"end_character":29},"updated":"2018-04-13 22:06:47.000000000","message":"Sorry, I may not be looking closely enough, but why do you have to do the first one special before you enter this loop?  If you assign\n\n join_chain \u003d rp_tbl\n\nbefore you start the loop...?","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":1596,"context_line":"            rps_in_aggregates \u003d _provider_ids_matching_aggregates("},{"line_number":1597,"context_line":"                context, member_of)"},{"line_number":1598,"context_line":"            if not rps_in_aggregates:"},{"line_number":1599,"context_line":"                # Short-circuit. The user either asked for a non-existing"},{"line_number":1600,"context_line":"                # aggregate or there were no resource providers that matched"},{"line_number":1601,"context_line":"                # the requirements..."},{"line_number":1602,"context_line":"                return []"},{"line_number":1603,"context_line":"            query \u003d query.where(rp.c.id.in_(rps_in_aggregates))"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_0075aa31","line":1600,"range":{"start_line":1599,"start_character":61,"end_line":1600,"end_character":27},"updated":"2018-04-13 22:06:47.000000000","message":"see above.","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":652,"context_line":""},{"line_number":653,"context_line":""},{"line_number":654,"context_line":"def _provider_ids_matching_aggregates(context, member_of):"},{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_11612937","line":655,"range":{"start_line":655,"start_character":27,"end_line":655,"end_character":46},"updated":"2018-04-17 17:32:48.000000000","message":"x","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":652,"context_line":""},{"line_number":653,"context_line":""},{"line_number":654,"context_line":"def _provider_ids_matching_aggregates(context, member_of):"},{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_914c59c8","line":655,"range":{"start_line":655,"start_character":13,"end_line":655,"end_character":16},"updated":"2018-04-17 17:32:48.000000000","message":"x","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":652,"context_line":""},{"line_number":653,"context_line":""},{"line_number":654,"context_line":"def _provider_ids_matching_aggregates(context, member_of):"},{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_dde660e9","line":655,"range":{"start_line":655,"start_character":13,"end_line":655,"end_character":16},"in_reply_to":"9f6a8fd7_914c59c8","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_5167a14e","line":658,"range":{"start_line":658,"start_character":40,"end_line":658,"end_character":72},"updated":"2018-04-17 17:32:48.000000000","message":"lists of aggregate UUIDs","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":655,"context_line":"    \"\"\"Given the a list of aggregate UUIDs or lists of aggregate UUIDs, return"},{"line_number":656,"context_line":"    the internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_bdf60c8f","line":658,"range":{"start_line":658,"start_character":40,"end_line":658,"end_character":72},"in_reply_to":"9f6a8fd7_5167a14e","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""},{"line_number":662,"context_line":"                      For example, if member_of is:"},{"line_number":663,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_d1697125","line":660,"range":{"start_line":660,"start_character":27,"end_line":660,"end_character":50},"updated":"2018-04-17 17:32:48.000000000","message":"has multiple values, they are","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing aggregate UUIDs or sets of UUIDs. Each"},{"line_number":659,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":660,"context_line":"                      item is itself a list, it is OR\u0027d together."},{"line_number":661,"context_line":""},{"line_number":662,"context_line":"                      For example, if member_of is:"},{"line_number":663,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_fd39e440","line":660,"range":{"start_line":660,"start_character":27,"end_line":660,"end_character":50},"in_reply_to":"9f6a8fd7_d1697125","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":662,"context_line":"                      For example, if member_of is:"},{"line_number":663,"context_line":""},{"line_number":664,"context_line":"                      ["},{"line_number":665,"context_line":"                        \u0027agg1\u0027,"},{"line_number":666,"context_line":"                        [\u0027agg2\u0027, \u0027agg3\u0027],"},{"line_number":667,"context_line":"                      ]"},{"line_number":668,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_7192e5f8","line":665,"range":{"start_line":665,"start_character":24,"end_line":665,"end_character":31},"updated":"2018-04-17 17:32:48.000000000","message":"[\u0027agg1\u0027],","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":662,"context_line":"                      For example, if member_of is:"},{"line_number":663,"context_line":""},{"line_number":664,"context_line":"                      ["},{"line_number":665,"context_line":"                        \u0027agg1\u0027,"},{"line_number":666,"context_line":"                        [\u0027agg2\u0027, \u0027agg3\u0027],"},{"line_number":667,"context_line":"                      ]"},{"line_number":668,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_bd3b6c36","line":665,"range":{"start_line":665,"start_character":24,"end_line":665,"end_character":31},"in_reply_to":"9f6a8fd7_7192e5f8","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":675,"context_line":"    # Given a request for the following:"},{"line_number":676,"context_line":"    #"},{"line_number":677,"context_line":"    # member_of \u003d ["},{"line_number":678,"context_line":"    #   agg1,"},{"line_number":679,"context_line":"    #   agg2,"},{"line_number":680,"context_line":"    #   [agg3, agg4]"},{"line_number":681,"context_line":"    # ]"},{"line_number":682,"context_line":"    #"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_51c321ee","line":679,"range":{"start_line":678,"start_character":0,"end_line":679,"end_character":13},"updated":"2018-04-17 17:32:48.000000000","message":"[agg1],\n[agg2],","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":675,"context_line":"    # Given a request for the following:"},{"line_number":676,"context_line":"    #"},{"line_number":677,"context_line":"    # member_of \u003d ["},{"line_number":678,"context_line":"    #   agg1,"},{"line_number":679,"context_line":"    #   agg2,"},{"line_number":680,"context_line":"    #   [agg3, agg4]"},{"line_number":681,"context_line":"    # ]"},{"line_number":682,"context_line":"    #"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_1d14d89f","line":679,"range":{"start_line":678,"start_character":0,"end_line":679,"end_character":13},"in_reply_to":"9f6a8fd7_51c321ee","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":687,"context_line":"    # FROM resource_providers AS rp"},{"line_number":688,"context_line":"    # JOIN resource_provider_aggregates AS rpa1"},{"line_number":689,"context_line":"    #   ON rp.id \u003d rpa1.resource_provider_id"},{"line_number":690,"context_line":"    #   AND rpa1.aggregate_id \u003d $AGG1_ID"},{"line_number":691,"context_line":"    # JOIN resource_provider_aggregates AS rpa2"},{"line_number":692,"context_line":"    #   ON rp.id \u003d rpa2.resource_provider_id"},{"line_number":693,"context_line":"    #   AND rpa2.aggregate_id \u003d $AGG2_ID"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_31b8edc6","line":690,"range":{"start_line":690,"start_character":30,"end_line":690,"end_character":40},"updated":"2018-04-17 17:32:48.000000000","message":"IN ($AGG1_ID)","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":687,"context_line":"    # FROM resource_providers AS rp"},{"line_number":688,"context_line":"    # JOIN resource_provider_aggregates AS rpa1"},{"line_number":689,"context_line":"    #   ON rp.id \u003d rpa1.resource_provider_id"},{"line_number":690,"context_line":"    #   AND rpa1.aggregate_id \u003d $AGG1_ID"},{"line_number":691,"context_line":"    # JOIN resource_provider_aggregates AS rpa2"},{"line_number":692,"context_line":"    #   ON rp.id \u003d rpa2.resource_provider_id"},{"line_number":693,"context_line":"    #   AND rpa2.aggregate_id \u003d $AGG2_ID"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_dd0d0091","line":690,"range":{"start_line":690,"start_character":30,"end_line":690,"end_character":40},"in_reply_to":"9f6a8fd7_31b8edc6","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":690,"context_line":"    #   AND rpa1.aggregate_id \u003d $AGG1_ID"},{"line_number":691,"context_line":"    # JOIN resource_provider_aggregates AS rpa2"},{"line_number":692,"context_line":"    #   ON rp.id \u003d rpa2.resource_provider_id"},{"line_number":693,"context_line":"    #   AND rpa2.aggregate_id \u003d $AGG2_ID"},{"line_number":694,"context_line":"    # JOIN resource_provider_aggregates AS rpa3"},{"line_number":695,"context_line":"    #   ON rp.id \u003d rpa3.resource_provider_id"},{"line_number":696,"context_line":"    #   AND rpa3.aggregate_id IN ($AGG3_ID, $AGG4_ID)"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_51bd61b5","line":693,"range":{"start_line":693,"start_character":30,"end_line":693,"end_character":40},"updated":"2018-04-17 17:32:48.000000000","message":"IN ($AGG2_ID)","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":690,"context_line":"    #   AND rpa1.aggregate_id \u003d $AGG1_ID"},{"line_number":691,"context_line":"    # JOIN resource_provider_aggregates AS rpa2"},{"line_number":692,"context_line":"    #   ON rp.id \u003d rpa2.resource_provider_id"},{"line_number":693,"context_line":"    #   AND rpa2.aggregate_id \u003d $AGG2_ID"},{"line_number":694,"context_line":"    # JOIN resource_provider_aggregates AS rpa3"},{"line_number":695,"context_line":"    #   ON rp.id \u003d rpa3.resource_provider_id"},{"line_number":696,"context_line":"    #   AND rpa3.aggregate_id IN ($AGG3_ID, $AGG4_ID)"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_fd1244b1","line":693,"range":{"start_line":693,"start_character":30,"end_line":693,"end_character":40},"in_reply_to":"9f6a8fd7_51bd61b5","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":698,"context_line":"    # First things first, get a map of all the aggregate UUID to internal"},{"line_number":699,"context_line":"    # aggregate IDs"},{"line_number":700,"context_line":"    agg_uuids \u003d set()"},{"line_number":701,"context_line":"    for members in member_of:"},{"line_number":702,"context_line":"        for member in members:"},{"line_number":703,"context_line":"            agg_uuids.add(member)"},{"line_number":704,"context_line":"    agg_tbl \u003d sa.alias(_AGG_TBL, name\u003d\u0027aggs\u0027)"},{"line_number":705,"context_line":"    agg_sel \u003d sa.select([agg_tbl.c.uuid, agg_tbl.c.id])"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_3106ad88","line":702,"range":{"start_line":701,"start_character":4,"end_line":702,"end_character":30},"updated":"2018-04-17 17:32:48.000000000","message":"Could use itertools.chain here\n\n(or not)","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":714,"context_line":"    for x, members in enumerate(member_of):"},{"line_number":715,"context_line":"        rpa_tbl \u003d sa.alias(_RP_AGG_TBL, name\u003d\u0027rpa%d\u0027 % x)"},{"line_number":716,"context_line":""},{"line_number":717,"context_line":"        agg_ids \u003d [agg_uuid_map.get(member) for member in members"},{"line_number":718,"context_line":"                   if member in agg_uuid_map]"},{"line_number":719,"context_line":"        if not agg_ids:"},{"line_number":720,"context_line":"            # This member_of list contains only non-existent aggregate UUIDs"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_f134b54c","line":717,"range":{"start_line":717,"start_character":31,"end_line":717,"end_character":43},"updated":"2018-04-17 17:32:48.000000000","message":"[member] since you\u0027re validating that the entry exists.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":714,"context_line":"    for x, members in enumerate(member_of):"},{"line_number":715,"context_line":"        rpa_tbl \u003d sa.alias(_RP_AGG_TBL, name\u003d\u0027rpa%d\u0027 % x)"},{"line_number":716,"context_line":""},{"line_number":717,"context_line":"        agg_ids \u003d [agg_uuid_map.get(member) for member in members"},{"line_number":718,"context_line":"                   if member in agg_uuid_map]"},{"line_number":719,"context_line":"        if not agg_ids:"},{"line_number":720,"context_line":"            # This member_of list contains only non-existent aggregate UUIDs"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_1d7938fb","line":717,"range":{"start_line":717,"start_character":31,"end_line":717,"end_character":43},"in_reply_to":"9f6a8fd7_f134b54c","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":727,"context_line":"        join_chain \u003d sa.join(join_chain, rpa_tbl, join_cond)"},{"line_number":728,"context_line":""},{"line_number":729,"context_line":"    sel \u003d sa.select([rp_tbl.c.id]).select_from(join_chain)"},{"line_number":730,"context_line":"    return [r[0] for r in context.session.execute(sel).fetchall()]"},{"line_number":731,"context_line":""},{"line_number":732,"context_line":""},{"line_number":733,"context_line":"@db_api.api_context_manager.writer"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_11bda964","line":730,"updated":"2018-04-17 17:32:48.000000000","message":"++ I like this method much better now, thank you.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":727,"context_line":"        join_chain \u003d sa.join(join_chain, rpa_tbl, join_cond)"},{"line_number":728,"context_line":""},{"line_number":729,"context_line":"    sel \u003d sa.select([rp_tbl.c.id]).select_from(join_chain)"},{"line_number":730,"context_line":"    return [r[0] for r in context.session.execute(sel).fetchall()]"},{"line_number":731,"context_line":""},{"line_number":732,"context_line":""},{"line_number":733,"context_line":"@db_api.api_context_manager.writer"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_3d7e7ce4","line":730,"in_reply_to":"9f6a8fd7_11bda964","updated":"2018-04-17 20:03:30.000000000","message":"I aim to please.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1348876968f31eeece8200e98e1ec5a5fd3a4a1e","unresolved":false,"context_lines":[{"line_number":652,"context_line":""},{"line_number":653,"context_line":""},{"line_number":654,"context_line":"def _provider_ids_matching_aggregates(context, member_of):"},{"line_number":655,"context_line":"    \"\"\"Given a list of aggregate UUIDs or lists of aggregate UUIDs, return the"},{"line_number":656,"context_line":"    internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing lists of aggregate UUIDs. Each"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_f813320c","line":655,"range":{"start_line":655,"start_character":23,"end_line":655,"end_character":41},"updated":"2018-04-17 20:27:53.000000000","message":"x","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"0093fda55ac94fc1504b09117acfcfd27e72ef4a","unresolved":false,"context_lines":[{"line_number":652,"context_line":""},{"line_number":653,"context_line":""},{"line_number":654,"context_line":"def _provider_ids_matching_aggregates(context, member_of):"},{"line_number":655,"context_line":"    \"\"\"Given a list of aggregate UUIDs or lists of aggregate UUIDs, return the"},{"line_number":656,"context_line":"    internal IDs of all resource providers associated with the aggregates."},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    :param member_or: A list containing lists of aggregate UUIDs. Each"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_830f7d86","line":655,"range":{"start_line":655,"start_character":23,"end_line":655,"end_character":41},"in_reply_to":"9f6a8fd7_f813320c","updated":"2018-04-25 16:07:19.000000000","message":"Done","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":25625,"name":"Tetsuro Nakamura","email":"tetsuro.nakamura.bc@hco.ntt.co.jp","username":"tetsuro0907"},"change_message_id":"b14538cc3d432532739cc8c5d7d8ff35ea5e3404","unresolved":false,"context_lines":[{"line_number":3691,"context_line":"        # has, only that it is sharing *some* inventory of a particular"},{"line_number":3692,"context_line":"        # resource class."},{"line_number":3693,"context_line":"        sharing_providers \u003d {"},{"line_number":3694,"context_line":"            rc_id: _get_providers_with_shared_capacity(context, rc_id, amount)"},{"line_number":3695,"context_line":"            for rc_id, amount in resources.items()"},{"line_number":3696,"context_line":"        }"},{"line_number":3697,"context_line":"        have_sharing \u003d any(sharing_providers.values())"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_bbdb53eb","line":3694,"range":{"start_line":3694,"start_character":19,"end_line":3694,"end_character":54},"updated":"2018-04-19 01:46:55.000000000","message":"optional: This might be a good time to change this function to accept member_of parameter. (Or can we do this in a separate patch?)\nhttps://bugs.launchpad.net/nova/+bug/1763907","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"0093fda55ac94fc1504b09117acfcfd27e72ef4a","unresolved":false,"context_lines":[{"line_number":3691,"context_line":"        # has, only that it is sharing *some* inventory of a particular"},{"line_number":3692,"context_line":"        # resource class."},{"line_number":3693,"context_line":"        sharing_providers \u003d {"},{"line_number":3694,"context_line":"            rc_id: _get_providers_with_shared_capacity(context, rc_id, amount)"},{"line_number":3695,"context_line":"            for rc_id, amount in resources.items()"},{"line_number":3696,"context_line":"        }"},{"line_number":3697,"context_line":"        have_sharing \u003d any(sharing_providers.values())"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_236f912b","line":3694,"range":{"start_line":3694,"start_character":19,"end_line":3694,"end_character":54},"in_reply_to":"9f6a8fd7_bbdb53eb","updated":"2018-04-25 16:07:19.000000000","message":"Separate patch, for sure.","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":657,"context_line":"    \"\"\"Given a list of lists of aggregate UUIDs, return the internal IDs of all"},{"line_number":658,"context_line":"    resource providers associated with the aggregates."},{"line_number":659,"context_line":""},{"line_number":660,"context_line":"    :param member_or: A list containing lists of aggregate UUIDs. Each"},{"line_number":661,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":662,"context_line":"                      item contains multiple values, they are OR\u0027d together."},{"line_number":663,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_a18e192c","line":660,"range":{"start_line":660,"start_character":11,"end_line":660,"end_character":20},"updated":"2018-05-03 10:22:16.000000000","message":"member_of","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"bd43ee0a46175b3d12ef16a4f04d5f1699c9b985","unresolved":false,"context_lines":[{"line_number":657,"context_line":"    \"\"\"Given a list of lists of aggregate UUIDs, return the internal IDs of all"},{"line_number":658,"context_line":"    resource providers associated with the aggregates."},{"line_number":659,"context_line":""},{"line_number":660,"context_line":"    :param member_or: A list containing lists of aggregate UUIDs. Each"},{"line_number":661,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":662,"context_line":"                      item contains multiple values, they are OR\u0027d together."},{"line_number":663,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_d21a0516","line":660,"range":{"start_line":660,"start_character":11,"end_line":660,"end_character":20},"in_reply_to":"5f7c97a3_a18e192c","updated":"2018-05-03 13:02:43.000000000","message":"Done","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":658,"context_line":"    resource providers associated with the aggregates."},{"line_number":659,"context_line":""},{"line_number":660,"context_line":"    :param member_or: A list containing lists of aggregate UUIDs. Each"},{"line_number":661,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":662,"context_line":"                      item contains multiple values, they are OR\u0027d together."},{"line_number":663,"context_line":""},{"line_number":664,"context_line":"                      For example, if member_of is:"},{"line_number":665,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_e173b14c","line":662,"range":{"start_line":661,"start_character":0,"end_line":662,"end_character":76},"updated":"2018-05-03 10:22:16.000000000","message":"nit: I find this indentation style really difficult to parse (it\u0027s too narrow). It doesn\u0027t have to change now, but could you consider simply indenting subsequent lines by 4 spaces instead?\n\n   :param member_of: blah blah blah...\n       continues down here...\n       and here and here and here.","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"bd43ee0a46175b3d12ef16a4f04d5f1699c9b985","unresolved":false,"context_lines":[{"line_number":658,"context_line":"    resource providers associated with the aggregates."},{"line_number":659,"context_line":""},{"line_number":660,"context_line":"    :param member_or: A list containing lists of aggregate UUIDs. Each"},{"line_number":661,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":662,"context_line":"                      item contains multiple values, they are OR\u0027d together."},{"line_number":663,"context_line":""},{"line_number":664,"context_line":"                      For example, if member_of is:"},{"line_number":665,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_72e1b1fe","line":662,"range":{"start_line":661,"start_character":0,"end_line":662,"end_character":76},"in_reply_to":"5f7c97a3_e173b14c","updated":"2018-05-03 13:02:43.000000000","message":"Done","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":661,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":662,"context_line":"                      item contains multiple values, they are OR\u0027d together."},{"line_number":663,"context_line":""},{"line_number":664,"context_line":"                      For example, if member_of is:"},{"line_number":665,"context_line":""},{"line_number":666,"context_line":"                      ["},{"line_number":667,"context_line":"                        [\u0027agg1\u0027],"},{"line_number":668,"context_line":"                        [\u0027agg2\u0027, \u0027agg3\u0027],"},{"line_number":669,"context_line":"                      ]"},{"line_number":670,"context_line":""},{"line_number":671,"context_line":"                      we will return all the resource providers that are"},{"line_number":672,"context_line":"                      associated with agg1 as well as either (agg2 or agg3)"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_a193794f","line":669,"range":{"start_line":664,"start_character":50,"end_line":669,"end_character":23},"updated":"2018-05-03 10:22:16.000000000","message":"nit: Don\u0027t think we\u0027re outputting this anywhere, but the colon should be a double colon (\u0027::\u0027) and the block indented for this to display correctly","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"bd43ee0a46175b3d12ef16a4f04d5f1699c9b985","unresolved":false,"context_lines":[{"line_number":661,"context_line":"                      item in the outer list is to be AND\u0027d together. If that"},{"line_number":662,"context_line":"                      item contains multiple values, they are OR\u0027d together."},{"line_number":663,"context_line":""},{"line_number":664,"context_line":"                      For example, if member_of is:"},{"line_number":665,"context_line":""},{"line_number":666,"context_line":"                      ["},{"line_number":667,"context_line":"                        [\u0027agg1\u0027],"},{"line_number":668,"context_line":"                        [\u0027agg2\u0027, \u0027agg3\u0027],"},{"line_number":669,"context_line":"                      ]"},{"line_number":670,"context_line":""},{"line_number":671,"context_line":"                      we will return all the resource providers that are"},{"line_number":672,"context_line":"                      associated with agg1 as well as either (agg2 or agg3)"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_f21701ed","line":669,"range":{"start_line":664,"start_character":50,"end_line":669,"end_character":23},"in_reply_to":"5f7c97a3_a193794f","updated":"2018-05-03 13:02:43.000000000","message":"Done","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":684,"context_line":"    #"},{"line_number":685,"context_line":"    # we need to produce the following SQL expression:"},{"line_number":686,"context_line":"    #"},{"line_number":687,"context_line":"    # SELECT"},{"line_number":688,"context_line":"    #   rp.id"},{"line_number":689,"context_line":"    # FROM resource_providers AS rp"},{"line_number":690,"context_line":"    # JOIN resource_provider_aggregates AS rpa1"},{"line_number":691,"context_line":"    #   ON rp.id \u003d rpa1.resource_provider_id"},{"line_number":692,"context_line":"    #   AND rpa1.aggregate_id IN ($AGG1_ID)"},{"line_number":693,"context_line":"    # JOIN resource_provider_aggregates AS rpa2"},{"line_number":694,"context_line":"    #   ON rp.id \u003d rpa2.resource_provider_id"},{"line_number":695,"context_line":"    #   AND rpa2.aggregate_id IN ($AGG2_ID)"},{"line_number":696,"context_line":"    # JOIN resource_provider_aggregates AS rpa3"},{"line_number":697,"context_line":"    #   ON rp.id \u003d rpa3.resource_provider_id"},{"line_number":698,"context_line":"    #   AND rpa3.aggregate_id IN ($AGG3_ID, $AGG4_ID)"},{"line_number":699,"context_line":""},{"line_number":700,"context_line":"    # First things first, get a map of all the aggregate UUID to internal"},{"line_number":701,"context_line":"    # aggregate IDs"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_e1c17130","line":698,"range":{"start_line":687,"start_character":0,"end_line":698,"end_character":53},"updated":"2018-05-03 10:22:16.000000000","message":"Wouldn\u0027t this just equate to the below?\n\n  SELECT\n    rp.id\n  FROM resource_providers AS rp\n  JOIN resource_provider_aggregates AS rpa\n    ON rp.id \u003d rpa1.resource_provider_id\n    AND rpa1.aggregate_id IN ($AGG1_ID, $AGG2_ID, $AGG3_ID, $AGG4_ID)\n\n(I imagine I\u0027m missing some nuance)","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5bf9f360ef03bc653dad4ff2a9ffbad67d9d8cb9","unresolved":false,"context_lines":[{"line_number":684,"context_line":"    #"},{"line_number":685,"context_line":"    # we need to produce the following SQL expression:"},{"line_number":686,"context_line":"    #"},{"line_number":687,"context_line":"    # SELECT"},{"line_number":688,"context_line":"    #   rp.id"},{"line_number":689,"context_line":"    # FROM resource_providers AS rp"},{"line_number":690,"context_line":"    # JOIN resource_provider_aggregates AS rpa1"},{"line_number":691,"context_line":"    #   ON rp.id \u003d rpa1.resource_provider_id"},{"line_number":692,"context_line":"    #   AND rpa1.aggregate_id IN ($AGG1_ID)"},{"line_number":693,"context_line":"    # JOIN resource_provider_aggregates AS rpa2"},{"line_number":694,"context_line":"    #   ON rp.id \u003d rpa2.resource_provider_id"},{"line_number":695,"context_line":"    #   AND rpa2.aggregate_id IN ($AGG2_ID)"},{"line_number":696,"context_line":"    # JOIN resource_provider_aggregates AS rpa3"},{"line_number":697,"context_line":"    #   ON rp.id \u003d rpa3.resource_provider_id"},{"line_number":698,"context_line":"    #   AND rpa3.aggregate_id IN ($AGG3_ID, $AGG4_ID)"},{"line_number":699,"context_line":""},{"line_number":700,"context_line":"    # First things first, get a map of all the aggregate UUID to internal"},{"line_number":701,"context_line":"    # aggregate IDs"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_f70cd343","line":698,"range":{"start_line":687,"start_character":0,"end_line":698,"end_character":53},"in_reply_to":"5f7c97a3_977a3f86","updated":"2018-05-03 12:31:20.000000000","message":"Right. That makes sense. Thanks for the clarification","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"70e983089e764431c169fd41382ea9d4ef18bb82","unresolved":false,"context_lines":[{"line_number":684,"context_line":"    #"},{"line_number":685,"context_line":"    # we need to produce the following SQL expression:"},{"line_number":686,"context_line":"    #"},{"line_number":687,"context_line":"    # SELECT"},{"line_number":688,"context_line":"    #   rp.id"},{"line_number":689,"context_line":"    # FROM resource_providers AS rp"},{"line_number":690,"context_line":"    # JOIN resource_provider_aggregates AS rpa1"},{"line_number":691,"context_line":"    #   ON rp.id \u003d rpa1.resource_provider_id"},{"line_number":692,"context_line":"    #   AND rpa1.aggregate_id IN ($AGG1_ID)"},{"line_number":693,"context_line":"    # JOIN resource_provider_aggregates AS rpa2"},{"line_number":694,"context_line":"    #   ON rp.id \u003d rpa2.resource_provider_id"},{"line_number":695,"context_line":"    #   AND rpa2.aggregate_id IN ($AGG2_ID)"},{"line_number":696,"context_line":"    # JOIN resource_provider_aggregates AS rpa3"},{"line_number":697,"context_line":"    #   ON rp.id \u003d rpa3.resource_provider_id"},{"line_number":698,"context_line":"    #   AND rpa3.aggregate_id IN ($AGG3_ID, $AGG4_ID)"},{"line_number":699,"context_line":""},{"line_number":700,"context_line":"    # First things first, get a map of all the aggregate UUID to internal"},{"line_number":701,"context_line":"    # aggregate IDs"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_977a3f86","line":698,"range":{"start_line":687,"start_character":0,"end_line":698,"end_character":53},"in_reply_to":"5f7c97a3_e1c17130","updated":"2018-05-03 11:46:11.000000000","message":"Each join represents an AND condition. Each IN represents an OR condition.\n\nTherefore this:\n\n  SELECT\n    rp.id\n  FROM resource_providers AS rp\n  JOIN resource_provider_aggregates AS rpa\n    ON rp.id \u003d rpa1.resource_provider_id\n    AND rpa1.aggregate_id IN ($AGG1_ID, $AGG2_ID, $AGG3_ID, $AGG4_ID)\n\nmeans \"get all providers that are members of agg1 OR agg2 OR agg3 OR agg4\".\n\nHowever, what we want to express is actually \"get all providers that are members of both agg1 AND agg2 AND (either agg3 or agg4)\"","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"}],"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":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":262,"context_line":"will be those in one of the specified aggregates that meet the other parts of"},{"line_number":263,"context_line":"the request."},{"line_number":264,"context_line":""},{"line_number":265,"context_line":"1.22 Support multiple ?member_of\u003d\u003caggregates\u003e queryparams on GET /resource_providers"},{"line_number":266,"context_line":"------------------------------------------------------------------------------------"},{"line_number":267,"context_line":""},{"line_number":268,"context_line":"Add support for specifying multiple `member_of` query parameters to the `GET"}],"source_content_type":"text/x-rst","patch_set":3,"id":"bf659307_c0901246","line":265,"range":{"start_line":265,"start_character":66,"end_line":265,"end_character":84},"updated":"2018-04-13 22:06:47.000000000","message":"wrap","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":272,"context_line":"providers that are associated with BOTH agg1 and agg2. Issuing a request for"},{"line_number":273,"context_line":"`GET /resource_providers?member_of\u003din:agg1,agg2\u0026member_of\u003dagg3` means get the"},{"line_number":274,"context_line":"resource providers that are associated with agg3 and are also associated with"},{"line_number":275,"context_line":"*either* agg1 or agg2."}],"source_content_type":"text/x-rst","patch_set":3,"id":"bf659307_00aa8a6f","line":275,"range":{"start_line":275,"start_character":0,"end_line":275,"end_character":16},"updated":"2018-04-13 22:06:47.000000000","message":"eithor/or implies xor (see release note comment)","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":271,"context_line":"prefixed by a ``!``. For example ``required\u003d!STORAGE_DISK_SSD`` asks that the"},{"line_number":272,"context_line":"results not include any resource providers that provide solid state disk."},{"line_number":273,"context_line":""},{"line_number":274,"context_line":"1.23 Support multiple ?member_of\u003d\u003caggregates\u003e queryparams on GET /resource_providers"},{"line_number":275,"context_line":"------------------------------------------------------------------------------------"},{"line_number":276,"context_line":""},{"line_number":277,"context_line":"Add support for specifying multiple `member_of` query parameters to the `GET"}],"source_content_type":"text/x-rst","patch_set":4,"id":"9f6a8fd7_c43d31bc","line":274,"range":{"start_line":274,"start_character":66,"end_line":274,"end_character":84},"updated":"2018-04-17 17:32:48.000000000","message":"does this need to wrap?","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":271,"context_line":"prefixed by a ``!``. For example ``required\u003d!STORAGE_DISK_SSD`` asks that the"},{"line_number":272,"context_line":"results not include any resource providers that provide solid state disk."},{"line_number":273,"context_line":""},{"line_number":274,"context_line":"1.23 Support multiple ?member_of\u003d\u003caggregates\u003e queryparams on GET /resource_providers"},{"line_number":275,"context_line":"------------------------------------------------------------------------------------"},{"line_number":276,"context_line":""},{"line_number":277,"context_line":"Add support for specifying multiple `member_of` query parameters to the `GET"}],"source_content_type":"text/x-rst","patch_set":4,"id":"9f6a8fd7_3d675c50","line":274,"range":{"start_line":274,"start_character":66,"end_line":274,"end_character":84},"in_reply_to":"9f6a8fd7_c43d31bc","updated":"2018-04-17 20:03:30.000000000","message":"reworded to include alloc cands anyway","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":281,"context_line":"providers that are associated with BOTH agg1 and agg2. Issuing a request for"},{"line_number":282,"context_line":"`GET /resource_providers?member_of\u003din:agg1,agg2\u0026member_of\u003dagg3` means get the"},{"line_number":283,"context_line":"resource providers that are associated with agg3 and are also associated with"},{"line_number":284,"context_line":"*either* agg1 or agg2."}],"source_content_type":"text/x-rst","patch_set":4,"id":"9f6a8fd7_e46f15c3","line":284,"range":{"start_line":284,"start_character":0,"end_line":284,"end_character":21},"updated":"2018-04-17 17:32:48.000000000","message":"Am I the only one who thinks this implies XOR?","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":281,"context_line":"providers that are associated with BOTH agg1 and agg2. Issuing a request for"},{"line_number":282,"context_line":"`GET /resource_providers?member_of\u003din:agg1,agg2\u0026member_of\u003dagg3` means get the"},{"line_number":283,"context_line":"resource providers that are associated with agg3 and are also associated with"},{"line_number":284,"context_line":"*either* agg1 or agg2."}],"source_content_type":"text/x-rst","patch_set":4,"id":"9f6a8fd7_3dcc3c34","line":284,"range":{"start_line":284,"start_character":0,"end_line":284,"end_character":21},"in_reply_to":"9f6a8fd7_e46f15c3","updated":"2018-04-17 20:03:30.000000000","message":"forgot to fix that. changed to read \"any of\"","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":284,"context_line":"1.24 Support multiple ?member_of queryparams"},{"line_number":285,"context_line":"--------------------------------------------"},{"line_number":286,"context_line":""},{"line_number":287,"context_line":"Add support for specifying multiple `member_of` query parameters to the `GET"},{"line_number":288,"context_line":"/resource_providers` API. When multiple `member_of` query parameters are found,"},{"line_number":289,"context_line":"they are AND\u0027d together in the final query. For example, issuing a request for"},{"line_number":290,"context_line":"`GET /resource_providers?member_of\u003dagg1\u0026member_of\u003dagg2` means get the resource"}],"source_content_type":"text/x-rst","patch_set":15,"id":"5f7c97a3_a10a9987","line":287,"range":{"start_line":287,"start_character":37,"end_line":287,"end_character":46},"updated":"2018-05-03 10:22:16.000000000","message":"``member_of``?","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"bd43ee0a46175b3d12ef16a4f04d5f1699c9b985","unresolved":false,"context_lines":[{"line_number":284,"context_line":"1.24 Support multiple ?member_of queryparams"},{"line_number":285,"context_line":"--------------------------------------------"},{"line_number":286,"context_line":""},{"line_number":287,"context_line":"Add support for specifying multiple `member_of` query parameters to the `GET"},{"line_number":288,"context_line":"/resource_providers` API. When multiple `member_of` query parameters are found,"},{"line_number":289,"context_line":"they are AND\u0027d together in the final query. For example, issuing a request for"},{"line_number":290,"context_line":"`GET /resource_providers?member_of\u003dagg1\u0026member_of\u003dagg2` means get the resource"}],"source_content_type":"text/x-rst","patch_set":15,"id":"5f7c97a3_32e33908","line":287,"range":{"start_line":287,"start_character":37,"end_line":287,"end_character":46},"in_reply_to":"5f7c97a3_a10a9987","updated":"2018-05-03 13:02:43.000000000","message":"Done","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"}],"nova/api/openstack/placement/util.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":334,"context_line":"    return ret"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":""},{"line_number":337,"context_line":"def normalize_member_of_qs_params(req, suffix\u003d\u0027\u0027):"},{"line_number":338,"context_line":"    \"\"\"Given a webob.Request object, validate that the member_of querystring"},{"line_number":339,"context_line":"    parameters are correct. We begin supporting multiple member_of params in"},{"line_number":340,"context_line":"    microversion 1.23."}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_a44a7d24","line":337,"range":{"start_line":337,"start_character":37,"end_line":337,"end_character":48},"updated":"2018-04-17 17:32:48.000000000","message":"Nix this.  We don\u0027t support e.g. member_of1\u003d...,member_of2\u003d...","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1348876968f31eeece8200e98e1ec5a5fd3a4a1e","unresolved":false,"context_lines":[{"line_number":334,"context_line":"    return ret"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":""},{"line_number":337,"context_line":"def normalize_member_of_qs_params(req, suffix\u003d\u0027\u0027):"},{"line_number":338,"context_line":"    \"\"\"Given a webob.Request object, validate that the member_of querystring"},{"line_number":339,"context_line":"    parameters are correct. We begin supporting multiple member_of params in"},{"line_number":340,"context_line":"    microversion 1.23."}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_38a0caf4","line":337,"range":{"start_line":337,"start_character":37,"end_line":337,"end_character":48},"in_reply_to":"9f6a8fd7_9d030843","updated":"2018-04-17 20:27:53.000000000","message":"Hmph, I stand corrected.  (I didn\u0027t look, but I probably wrote that code too.)  It won\u0027t get by the schema.  But I guess since we\u0027re allowing it across the board at this level, I guess we ought to keep doing that.\n\nYou know what, actually, we never thought through the implications of granular member_of, because GET /a_c never had member_of before this bp.  We shall have to do that...","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":334,"context_line":"    return ret"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":""},{"line_number":337,"context_line":"def normalize_member_of_qs_params(req, suffix\u003d\u0027\u0027):"},{"line_number":338,"context_line":"    \"\"\"Given a webob.Request object, validate that the member_of querystring"},{"line_number":339,"context_line":"    parameters are correct. We begin supporting multiple member_of params in"},{"line_number":340,"context_line":"    microversion 1.23."}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_9d030843","line":337,"range":{"start_line":337,"start_character":37,"end_line":337,"end_character":48},"in_reply_to":"9f6a8fd7_a44a7d24","updated":"2018-04-17 20:03:30.000000000","message":"errr, apparently yes, we do:\n\nhttps://github.com/openstack/nova/blob/master/nova/api/openstack/placement/util.py#L35-L37\n\nhttps://github.com/openstack/nova/blob/master/nova/api/openstack/placement/util.py#L375\n\nhttps://github.com/openstack/nova/blob/master/nova/api/openstack/placement/util.py#L471","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":350,"context_line":"    microversion \u003d nova.api.openstack.placement.microversion"},{"line_number":351,"context_line":"    want_version \u003d req.environ[microversion.MICROVERSION_ENVIRON]"},{"line_number":352,"context_line":"    multi_member_of \u003d want_version.matches((1, 23))"},{"line_number":353,"context_line":"    if not multi_member_of and len(req.GET.getall(\u0027member_of\u0027)) \u003e 1:"},{"line_number":354,"context_line":"        raise webob.exc.HTTPBadRequest("},{"line_number":355,"context_line":"            _(\u0027Multiple member_of parameters are not supported\u0027))"},{"line_number":356,"context_line":"    values \u003d []"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_c4e3f104","line":353,"range":{"start_line":353,"start_character":35,"end_line":353,"end_character":62},"updated":"2018-04-17 17:32:48.000000000","message":"may as well save this off","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":354,"context_line":"        raise webob.exc.HTTPBadRequest("},{"line_number":355,"context_line":"            _(\u0027Multiple member_of parameters are not supported\u0027))"},{"line_number":356,"context_line":"    values \u003d []"},{"line_number":357,"context_line":"    for value in req.GET.getall(\u0027member_of\u0027 + suffix):"},{"line_number":358,"context_line":"        values.append(normalize_member_of_qs_param(value))"},{"line_number":359,"context_line":"    return values"},{"line_number":360,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_845179db","line":357,"range":{"start_line":357,"start_character":43,"end_line":357,"end_character":52},"updated":"2018-04-17 17:32:48.000000000","message":"x","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":498,"context_line":"        # special handling of member_of qparam since we allow multiple"},{"line_number":499,"context_line":"        # member_of params at microversion 1.23."},{"line_number":500,"context_line":"        elif prefix \u003d\u003d _QS_MEMBER_OF:"},{"line_number":501,"context_line":"            request_group.member_of \u003d normalize_member_of_qs_params("},{"line_number":502,"context_line":"                req, suffix or \u0027\u0027)"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    # Ensure any group with \u0027required\u0027 or \u0027member_of\u0027 also has \u0027resources\u0027."}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_e4dcf547","line":501,"range":{"start_line":501,"start_character":12,"end_line":501,"end_character":35},"updated":"2018-04-17 17:32:48.000000000","message":"Since you\u0027re in a loop over req.GET.items() (which is a MultiDict, right?), and normalize_member_of_qs_params itself iterates over req.GET.getall(\u0027member_of\u0027), you\u0027ll at best wind up creating/assigning this multiple times.  (At worst, you could potentially mess up the GET iterator.)\n\nI\u0027m thinking it might be best to use a separate loop to process qparams for which we support multiples.  Makes even more sense for this one, since it can\u0027t have numeric suffixes, so we don\u0027t actually need to find it (it\u0027s always the same) or parse it.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":498,"context_line":"        # special handling of member_of qparam since we allow multiple"},{"line_number":499,"context_line":"        # member_of params at microversion 1.23."},{"line_number":500,"context_line":"        elif prefix \u003d\u003d _QS_MEMBER_OF:"},{"line_number":501,"context_line":"            request_group.member_of \u003d normalize_member_of_qs_params("},{"line_number":502,"context_line":"                req, suffix or \u0027\u0027)"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    # Ensure any group with \u0027required\u0027 or \u0027member_of\u0027 also has \u0027resources\u0027."}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_1d95b8e4","line":501,"range":{"start_line":501,"start_character":12,"end_line":501,"end_character":35},"in_reply_to":"9f6a8fd7_e4dcf547","updated":"2018-04-17 20:03:30.000000000","message":"Done","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":499,"context_line":"        # member_of params at microversion 1.23."},{"line_number":500,"context_line":"        elif prefix \u003d\u003d _QS_MEMBER_OF:"},{"line_number":501,"context_line":"            request_group.member_of \u003d normalize_member_of_qs_params("},{"line_number":502,"context_line":"                req, suffix or \u0027\u0027)"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    # Ensure any group with \u0027required\u0027 or \u0027member_of\u0027 also has \u0027resources\u0027."},{"line_number":505,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_e440750a","line":502,"range":{"start_line":502,"start_character":21,"end_line":502,"end_character":33},"updated":"2018-04-17 17:32:48.000000000","message":"x","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1348876968f31eeece8200e98e1ec5a5fd3a4a1e","unresolved":false,"context_lines":[{"line_number":350,"context_line":"    microversion \u003d nova.api.openstack.placement.microversion"},{"line_number":351,"context_line":"    want_version \u003d req.environ[microversion.MICROVERSION_ENVIRON]"},{"line_number":352,"context_line":"    multi_member_of \u003d want_version.matches((1, 23))"},{"line_number":353,"context_line":"    if not multi_member_of and len(req.GET.getall(\u0027member_of\u0027)) \u003e 1:"},{"line_number":354,"context_line":"        raise webob.exc.HTTPBadRequest("},{"line_number":355,"context_line":"            _(\u0027Multiple member_of parameters are not supported\u0027))"},{"line_number":356,"context_line":"    values \u003d []"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_3833eaad","line":353,"range":{"start_line":353,"start_character":35,"end_line":353,"end_character":62},"updated":"2018-04-17 20:27:53.000000000","message":"...but in that case, you need to be getting the suffixed one here.","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"0093fda55ac94fc1504b09117acfcfd27e72ef4a","unresolved":false,"context_lines":[{"line_number":350,"context_line":"    microversion \u003d nova.api.openstack.placement.microversion"},{"line_number":351,"context_line":"    want_version \u003d req.environ[microversion.MICROVERSION_ENVIRON]"},{"line_number":352,"context_line":"    multi_member_of \u003d want_version.matches((1, 23))"},{"line_number":353,"context_line":"    if not multi_member_of and len(req.GET.getall(\u0027member_of\u0027)) \u003e 1:"},{"line_number":354,"context_line":"        raise webob.exc.HTTPBadRequest("},{"line_number":355,"context_line":"            _(\u0027Multiple member_of parameters are not supported\u0027))"},{"line_number":356,"context_line":"    values \u003d []"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_436ac519","line":353,"range":{"start_line":353,"start_character":35,"end_line":353,"end_character":62},"in_reply_to":"9f6a8fd7_3833eaad","updated":"2018-04-25 16:07:19.000000000","message":"Done","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1348876968f31eeece8200e98e1ec5a5fd3a4a1e","unresolved":false,"context_lines":[{"line_number":498,"context_line":""},{"line_number":499,"context_line":"    # special handling of member_of qparam since we allow multiple"},{"line_number":500,"context_line":"    # member_of params at microversion 1.23."},{"line_number":501,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":502,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    # Ensure any group with \u0027required\u0027 or \u0027member_of\u0027 also has \u0027resources\u0027."}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_58f01eca","line":501,"range":{"start_line":501,"start_character":4,"end_line":501,"end_character":43},"updated":"2018-04-17 20:27:53.000000000","message":"Now we\u0027ll no longer make entries for \"orphans\", so we can\u0027t hit L517.\n\nCan\u0027t win for losing.","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"0093fda55ac94fc1504b09117acfcfd27e72ef4a","unresolved":false,"context_lines":[{"line_number":498,"context_line":""},{"line_number":499,"context_line":"    # special handling of member_of qparam since we allow multiple"},{"line_number":500,"context_line":"    # member_of params at microversion 1.23."},{"line_number":501,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":502,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    # Ensure any group with \u0027required\u0027 or \u0027member_of\u0027 also has \u0027resources\u0027."}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_c367b54c","line":501,"range":{"start_line":501,"start_character":4,"end_line":501,"end_character":43},"in_reply_to":"9f6a8fd7_58f01eca","updated":"2018-04-25 16:07:19.000000000","message":"Done","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":382,"context_line":"                comma-separated string of two or more UUIDs."},{"line_number":383,"context_line":"    :return: A list of UUIDs"},{"line_number":384,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the val parameter is not in the"},{"line_number":385,"context_line":"            expected format."},{"line_number":386,"context_line":"    \"\"\""},{"line_number":387,"context_line":"    # Ensure that multiple values are prefixed with \"in:\""},{"line_number":388,"context_line":"    if \",\" in val and not val.startswith(\"in:\"):"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_034128a9","line":385,"range":{"start_line":385,"start_character":0,"end_line":385,"end_character":28},"updated":"2018-04-25 19:30:44.000000000","message":"bad delete","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"62028af7d8c8144ab486874e13d23b2d98fbba47","unresolved":false,"context_lines":[{"line_number":382,"context_line":"                comma-separated string of two or more UUIDs."},{"line_number":383,"context_line":"    :return: A list of UUIDs"},{"line_number":384,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the val parameter is not in the"},{"line_number":385,"context_line":"            expected format."},{"line_number":386,"context_line":"    \"\"\""},{"line_number":387,"context_line":"    # Ensure that multiple values are prefixed with \"in:\""},{"line_number":388,"context_line":"    if \",\" in val and not val.startswith(\"in:\"):"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_868c6636","line":385,"range":{"start_line":385,"start_character":0,"end_line":385,"end_character":28},"in_reply_to":"9f6a8fd7_034128a9","updated":"2018-04-25 19:55:07.000000000","message":"I\u0027m not following you.","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"c4d250d21967f0792f2d85c79ee3e29297c0d55f","unresolved":false,"context_lines":[{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":519,"context_line":"               if group.required_traits and not group.resources]"},{"line_number":520,"context_line":"    if orphans:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_19d2fa28","line":517,"updated":"2018-04-25 17:01:31.000000000","message":"I think we still want the orphan check for member_of","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"62028af7d8c8144ab486874e13d23b2d98fbba47","unresolved":false,"context_lines":[{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":519,"context_line":"               if group.required_traits and not group.resources]"},{"line_number":520,"context_line":"    if orphans:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_c6c33e37","line":517,"in_reply_to":"9f6a8fd7_03d36805","updated":"2018-04-25 19:55:07.000000000","message":"The code below will prevent any groups that have required but not resources. Lines 514-515 will set member_of only for groups that have either required or resources (since those are the only ones that will have been created in lines 498-510. Therefore there cannot be request groups that have only member_of set.","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"7e05944afa6f3b13e2bf67f97b9442d635f4fde9","unresolved":false,"context_lines":[{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":519,"context_line":"               if group.required_traits and not group.resources]"},{"line_number":520,"context_line":"    if orphans:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_99160aa8","line":517,"in_reply_to":"9f6a8fd7_19d2fa28","updated":"2018-04-25 17:07:10.000000000","message":"You had specifically asked me to remove this in an earlier revision.","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"e2bc9e6386e26b60e2e5ced843cf77b93e28d9d8","unresolved":false,"context_lines":[{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":519,"context_line":"               if group.required_traits and not group.resources]"},{"line_number":520,"context_line":"    if orphans:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_51a60611","line":517,"in_reply_to":"9f6a8fd7_46b64e8c","updated":"2018-04-25 20:18:58.000000000","message":"Gotcha. OK, will re-add.","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"bd16723e91cd2d1ac8065816b700159c0dfd686a","unresolved":false,"context_lines":[{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":519,"context_line":"               if group.required_traits and not group.resources]"},{"line_number":520,"context_line":"    if orphans:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_03d36805","line":517,"in_reply_to":"9f6a8fd7_99160aa8","updated":"2018-04-25 19:11:52.000000000","message":"No, my complaint was that the delta on L500-502 from PS5 to PS6 (which I commented on in PS7) made the orphan check unhittable, because you\u0027re now *only* creating entries for suffixes for which you\u0027ve already seen resources/required.  To check effectively for orphans, you need to create entries for *all* instances of member_of so that the orphan check can identify ones that don\u0027t have resources specified.","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d75d265f83da37e8ac8a5f69b6b4200bd0d5f67c","unresolved":false,"context_lines":[{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":519,"context_line":"               if group.required_traits and not group.resources]"},{"line_number":520,"context_line":"    if orphans:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_46b64e8c","line":517,"in_reply_to":"9f6a8fd7_c6c33e37","updated":"2018-04-25 20:10:28.000000000","message":"That\u0027s my point.  It means the user can specify ?member_of\u003cBogusNumber\u003e\u003dXXX and it\u0027ll be ignored instead of triggering an error.","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":350,"context_line":"def normalize_member_of_qs_params(req, suffix\u003d\u0027\u0027):"},{"line_number":351,"context_line":"    \"\"\"Given a webob.Request object, validate that the member_of querystring"},{"line_number":352,"context_line":"    parameters are correct. We begin supporting multiple member_of params in"},{"line_number":353,"context_line":"    microversion 1.23."},{"line_number":354,"context_line":""},{"line_number":355,"context_line":"    :param req: webob.Request object"},{"line_number":356,"context_line":"    :return: A list containing lists of UUIDs of aggregates to filter on"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_8333f813","line":353,"range":{"start_line":353,"start_character":19,"end_line":353,"end_character":21},"updated":"2018-04-25 19:30:44.000000000","message":"24","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a3c160731cea40e7d2c6be5f2f9f8ecff90d9821","unresolved":false,"context_lines":[{"line_number":350,"context_line":"def normalize_member_of_qs_params(req, suffix\u003d\u0027\u0027):"},{"line_number":351,"context_line":"    \"\"\"Given a webob.Request object, validate that the member_of querystring"},{"line_number":352,"context_line":"    parameters are correct. We begin supporting multiple member_of params in"},{"line_number":353,"context_line":"    microversion 1.23."},{"line_number":354,"context_line":""},{"line_number":355,"context_line":"    :param req: webob.Request object"},{"line_number":356,"context_line":"    :return: A list containing lists of UUIDs of aggregates to filter on"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_c646dec0","line":353,"range":{"start_line":353,"start_character":19,"end_line":353,"end_character":21},"in_reply_to":"9f6a8fd7_8333f813","updated":"2018-04-25 20:00:36.000000000","message":"Done","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":353,"context_line":"    microversion 1.23."},{"line_number":354,"context_line":""},{"line_number":355,"context_line":"    :param req: webob.Request object"},{"line_number":356,"context_line":"    :return: A list containing lists of UUIDs of aggregates to filter on"},{"line_number":357,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the microversion requested is \u003c1.23"},{"line_number":358,"context_line":"            and the request contains multiple member_of querystring params"},{"line_number":359,"context_line":"            expected format."}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_660a7220","line":356,"range":{"start_line":356,"start_character":31,"end_line":356,"end_character":36},"updated":"2018-04-25 19:30:44.000000000","message":"sets","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a3c160731cea40e7d2c6be5f2f9f8ecff90d9821","unresolved":false,"context_lines":[{"line_number":353,"context_line":"    microversion 1.23."},{"line_number":354,"context_line":""},{"line_number":355,"context_line":"    :param req: webob.Request object"},{"line_number":356,"context_line":"    :return: A list containing lists of UUIDs of aggregates to filter on"},{"line_number":357,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the microversion requested is \u003c1.23"},{"line_number":358,"context_line":"            and the request contains multiple member_of querystring params"},{"line_number":359,"context_line":"            expected format."}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_e641a2a7","line":356,"range":{"start_line":356,"start_character":31,"end_line":356,"end_character":36},"in_reply_to":"9f6a8fd7_660a7220","updated":"2018-04-25 20:00:36.000000000","message":"Done","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":356,"context_line":"    :return: A list containing lists of UUIDs of aggregates to filter on"},{"line_number":357,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the microversion requested is \u003c1.23"},{"line_number":358,"context_line":"            and the request contains multiple member_of querystring params"},{"line_number":359,"context_line":"            expected format."},{"line_number":360,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the val parameter is not in the"},{"line_number":361,"context_line":"            expected format."},{"line_number":362,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_436ba0ef","line":359,"range":{"start_line":359,"start_character":12,"end_line":359,"end_character":28},"updated":"2018-04-25 19:30:44.000000000","message":"x","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a3c160731cea40e7d2c6be5f2f9f8ecff90d9821","unresolved":false,"context_lines":[{"line_number":356,"context_line":"    :return: A list containing lists of UUIDs of aggregates to filter on"},{"line_number":357,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the microversion requested is \u003c1.23"},{"line_number":358,"context_line":"            and the request contains multiple member_of querystring params"},{"line_number":359,"context_line":"            expected format."},{"line_number":360,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the val parameter is not in the"},{"line_number":361,"context_line":"            expected format."},{"line_number":362,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_6636f253","line":359,"range":{"start_line":359,"start_character":12,"end_line":359,"end_character":28},"in_reply_to":"9f6a8fd7_436ba0ef","updated":"2018-04-25 20:00:36.000000000","message":"Done","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":380,"context_line":""},{"line_number":381,"context_line":"    :param value: A member_of query parameter of either a single UUID, or a"},{"line_number":382,"context_line":"                  comma-separated string of two or more UUIDs."},{"line_number":383,"context_line":"    :return: A list of UUIDs"},{"line_number":384,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the value parameter is not in the"},{"line_number":385,"context_line":"    \"\"\""},{"line_number":386,"context_line":"    if \",\" in value and not value.startswith(\"in:\"):"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_c31fb0b4","line":383,"range":{"start_line":383,"start_character":15,"end_line":383,"end_character":19},"updated":"2018-04-25 19:30:44.000000000","message":"this is now a set","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a3c160731cea40e7d2c6be5f2f9f8ecff90d9821","unresolved":false,"context_lines":[{"line_number":380,"context_line":""},{"line_number":381,"context_line":"    :param value: A member_of query parameter of either a single UUID, or a"},{"line_number":382,"context_line":"                  comma-separated string of two or more UUIDs."},{"line_number":383,"context_line":"    :return: A list of UUIDs"},{"line_number":384,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the value parameter is not in the"},{"line_number":385,"context_line":"    \"\"\""},{"line_number":386,"context_line":"    if \",\" in value and not value.startswith(\"in:\"):"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_4633ae62","line":383,"range":{"start_line":383,"start_character":15,"end_line":383,"end_character":19},"in_reply_to":"9f6a8fd7_c31fb0b4","updated":"2018-04-25 20:00:36.000000000","message":"Done","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":395,"context_line":"    for aggr_uuid in value:"},{"line_number":396,"context_line":"        if not uuidutils.is_uuid_like(aggr_uuid):"},{"line_number":397,"context_line":"            msg \u003d _(\"Invalid query string parameters: Expected \u0027member_of\u0027 \""},{"line_number":398,"context_line":"                    \"parameter to contain valid UUID(s). Got: %s\") % value"},{"line_number":399,"context_line":"            raise webob.exc.HTTPBadRequest(msg)"},{"line_number":400,"context_line":"    return value"},{"line_number":401,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_a37e3ce1","line":398,"range":{"start_line":398,"start_character":69,"end_line":398,"end_character":74},"updated":"2018-04-25 19:30:44.000000000","message":"Since you unwound the loop, use aggr_uuid here.","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a3c160731cea40e7d2c6be5f2f9f8ecff90d9821","unresolved":false,"context_lines":[{"line_number":395,"context_line":"    for aggr_uuid in value:"},{"line_number":396,"context_line":"        if not uuidutils.is_uuid_like(aggr_uuid):"},{"line_number":397,"context_line":"            msg \u003d _(\"Invalid query string parameters: Expected \u0027member_of\u0027 \""},{"line_number":398,"context_line":"                    \"parameter to contain valid UUID(s). Got: %s\") % value"},{"line_number":399,"context_line":"            raise webob.exc.HTTPBadRequest(msg)"},{"line_number":400,"context_line":"    return value"},{"line_number":401,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_e6ec42bc","line":398,"range":{"start_line":398,"start_character":69,"end_line":398,"end_character":74},"in_reply_to":"9f6a8fd7_a37e3ce1","updated":"2018-04-25 20:00:36.000000000","message":"? I didn\u0027t change anything...\n\nI think you\u0027re confusing which loop was unwound.","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":509,"context_line":"                val, allow_forbidden\u003dallow_forbidden)"},{"line_number":510,"context_line":""},{"line_number":511,"context_line":"    # special handling of member_of qparam since we allow multiple"},{"line_number":512,"context_line":"    # member_of params at microversion 1.23."},{"line_number":513,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":514,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":515,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_a62dea95","line":512,"range":{"start_line":512,"start_character":41,"end_line":512,"end_character":43},"updated":"2018-04-25 19:30:44.000000000","message":"24","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"a3c160731cea40e7d2c6be5f2f9f8ecff90d9821","unresolved":false,"context_lines":[{"line_number":509,"context_line":"                val, allow_forbidden\u003dallow_forbidden)"},{"line_number":510,"context_line":""},{"line_number":511,"context_line":"    # special handling of member_of qparam since we allow multiple"},{"line_number":512,"context_line":"    # member_of params at microversion 1.23."},{"line_number":513,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":514,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":515,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_a6196ad7","line":512,"range":{"start_line":512,"start_character":41,"end_line":512,"end_character":43},"in_reply_to":"9f6a8fd7_a62dea95","updated":"2018-04-25 20:00:36.000000000","message":"Done","commit_id":"6492dbd30334f0ef04330d39b52907e83df18d83"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d75d265f83da37e8ac8a5f69b6b4200bd0d5f67c","unresolved":false,"context_lines":[{"line_number":378,"context_line":"    or more comma-separated UUIDs."},{"line_number":379,"context_line":""},{"line_number":380,"context_line":"    :param value: A member_of query parameter of either a single UUID, or a"},{"line_number":381,"context_line":"                  comma-separated string of two or more UUIDs."},{"line_number":382,"context_line":"    :return: A set of UUIDs"},{"line_number":383,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the value parameter is not in the"},{"line_number":384,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":10,"id":"9f6a8fd7_46440e74","line":381,"updated":"2018-04-25 20:10:28.000000000","message":"This deletion (\u0027, prefixed with the \"in:\" operator\u0027) could also be restored.","commit_id":"f8735939aa655ca889af5741a9934ce53a4144ec"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"04d27d44c4cf521270a4a505d202489d2e1275fb","unresolved":false,"context_lines":[{"line_number":378,"context_line":"    or more comma-separated UUIDs."},{"line_number":379,"context_line":""},{"line_number":380,"context_line":"    :param value: A member_of query parameter of either a single UUID, or a"},{"line_number":381,"context_line":"                  comma-separated string of two or more UUIDs."},{"line_number":382,"context_line":"    :return: A set of UUIDs"},{"line_number":383,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the value parameter is not in the"},{"line_number":384,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":10,"id":"9f6a8fd7_d1b1b645","line":381,"in_reply_to":"9f6a8fd7_46440e74","updated":"2018-04-25 20:22:17.000000000","message":"Done","commit_id":"f8735939aa655ca889af5741a9934ce53a4144ec"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d75d265f83da37e8ac8a5f69b6b4200bd0d5f67c","unresolved":false,"context_lines":[{"line_number":380,"context_line":"    :param value: A member_of query parameter of either a single UUID, or a"},{"line_number":381,"context_line":"                  comma-separated string of two or more UUIDs."},{"line_number":382,"context_line":"    :return: A set of UUIDs"},{"line_number":383,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the value parameter is not in the"},{"line_number":384,"context_line":"    \"\"\""},{"line_number":385,"context_line":"    if \",\" in value and not value.startswith(\"in:\"):"},{"line_number":386,"context_line":"        msg \u003d _(\"Multiple values for \u0027member_of\u0027 must be prefixed with the \""},{"line_number":387,"context_line":"                \"\u0027in:\u0027 keyword. Got: %s\") % value"}],"source_content_type":"text/x-python","patch_set":10,"id":"9f6a8fd7_c6a9fe23","line":384,"range":{"start_line":383,"start_character":0,"end_line":384,"end_character":7},"updated":"2018-04-25 20:10:28.000000000","message":"This is the bad delete I referred to.  The line containing \"expected format\" was removed, and this sentence falls off a cliff of incompleteness.","commit_id":"f8735939aa655ca889af5741a9934ce53a4144ec"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"04d27d44c4cf521270a4a505d202489d2e1275fb","unresolved":false,"context_lines":[{"line_number":380,"context_line":"    :param value: A member_of query parameter of either a single UUID, or a"},{"line_number":381,"context_line":"                  comma-separated string of two or more UUIDs."},{"line_number":382,"context_line":"    :return: A set of UUIDs"},{"line_number":383,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the value parameter is not in the"},{"line_number":384,"context_line":"    \"\"\""},{"line_number":385,"context_line":"    if \",\" in value and not value.startswith(\"in:\"):"},{"line_number":386,"context_line":"        msg \u003d _(\"Multiple values for \u0027member_of\u0027 must be prefixed with the \""},{"line_number":387,"context_line":"                \"\u0027in:\u0027 keyword. Got: %s\") % value"}],"source_content_type":"text/x-python","patch_set":10,"id":"9f6a8fd7_517fe664","line":384,"range":{"start_line":383,"start_character":0,"end_line":384,"end_character":7},"in_reply_to":"9f6a8fd7_c6a9fe23","updated":"2018-04-25 20:22:17.000000000","message":"Done","commit_id":"f8735939aa655ca889af5741a9934ce53a4144ec"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"d75d265f83da37e8ac8a5f69b6b4200bd0d5f67c","unresolved":false,"context_lines":[{"line_number":394,"context_line":"    for aggr_uuid in value:"},{"line_number":395,"context_line":"        if not uuidutils.is_uuid_like(aggr_uuid):"},{"line_number":396,"context_line":"            msg \u003d _(\"Invalid query string parameters: Expected \u0027member_of\u0027 \""},{"line_number":397,"context_line":"                    \"parameter to contain valid UUID(s). Got: %s\") % value"},{"line_number":398,"context_line":"            raise webob.exc.HTTPBadRequest(msg)"},{"line_number":399,"context_line":"    return value"},{"line_number":400,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"9f6a8fd7_c657be25","line":397,"range":{"start_line":397,"start_character":69,"end_line":397,"end_character":74},"updated":"2018-04-25 20:10:28.000000000","message":"yup, okay, you didn\u0027t change anything here.  But this should be aggr_uuid (in a fup if you prefer).","commit_id":"f8735939aa655ca889af5741a9934ce53a4144ec"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"04d27d44c4cf521270a4a505d202489d2e1275fb","unresolved":false,"context_lines":[{"line_number":394,"context_line":"    for aggr_uuid in value:"},{"line_number":395,"context_line":"        if not uuidutils.is_uuid_like(aggr_uuid):"},{"line_number":396,"context_line":"            msg \u003d _(\"Invalid query string parameters: Expected \u0027member_of\u0027 \""},{"line_number":397,"context_line":"                    \"parameter to contain valid UUID(s). Got: %s\") % value"},{"line_number":398,"context_line":"            raise webob.exc.HTTPBadRequest(msg)"},{"line_number":399,"context_line":"    return value"},{"line_number":400,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"9f6a8fd7_b18f6273","line":397,"range":{"start_line":397,"start_character":69,"end_line":397,"end_character":74},"in_reply_to":"9f6a8fd7_c657be25","updated":"2018-04-25 20:22:17.000000000","message":"Done","commit_id":"f8735939aa655ca889af5741a9934ce53a4144ec"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1f69d5f13f659cb85a9044a5a608db38ae98f5db","unresolved":false,"context_lines":[{"line_number":511,"context_line":""},{"line_number":512,"context_line":"    # special handling of member_of qparam since we allow multiple"},{"line_number":513,"context_line":"    # member_of params at microversion 1.24."},{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"}],"source_content_type":"text/x-python","patch_set":11,"id":"9f6a8fd7_b14682bf","line":515,"range":{"start_line":514,"start_character":0,"end_line":515,"end_character":68},"updated":"2018-04-25 20:37:12.000000000","message":"Still need to re-add the orphan member_of\u003cN\u003e check.","commit_id":"327f388152535348cef55088d948f28a9f506173"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2cb27b89d2935796f7f581f5223cef3a821615a1","unresolved":false,"context_lines":[{"line_number":511,"context_line":""},{"line_number":512,"context_line":"    # special handling of member_of qparam since we allow multiple"},{"line_number":513,"context_line":"    # member_of params at microversion 1.24."},{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"}],"source_content_type":"text/x-python","patch_set":11,"id":"9f6a8fd7_8c89e575","line":515,"range":{"start_line":514,"start_character":0,"end_line":515,"end_character":68},"in_reply_to":"9f6a8fd7_b14682bf","updated":"2018-04-25 21:02:10.000000000","message":"Done. Gah!","commit_id":"327f388152535348cef55088d948f28a9f506173"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"59969ef3ef583b14d7ebab487991e7240e6aa6e4","unresolved":false,"context_lines":[{"line_number":511,"context_line":""},{"line_number":512,"context_line":"    # special handling of member_of qparam since we allow multiple"},{"line_number":513,"context_line":"    # member_of params at microversion 1.24."},{"line_number":514,"context_line":"    for suffix, group in by_suffix.items():"},{"line_number":515,"context_line":"        group.member_of \u003d normalize_member_of_qs_params(req, suffix)"},{"line_number":516,"context_line":""},{"line_number":517,"context_line":"    # Ensure any group with \u0027required\u0027 or \u0027member_of\u0027 also has \u0027resources\u0027."},{"line_number":518,"context_line":"    orphans \u003d [(\u0027required%s\u0027 % suff) for suff, group in by_suffix.items()"}],"source_content_type":"text/x-python","patch_set":12,"id":"9f6a8fd7_8cbd65b8","line":515,"range":{"start_line":514,"start_character":0,"end_line":515,"end_character":68},"updated":"2018-04-25 21:20:09.000000000","message":"Now we\u0027re back to the point where this doesn\u0027t allow any orphans to get through.","commit_id":"01964b15896a1d9e6183107e00fd870e3c78d24f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"47891dd36d724c77446e6583604c1725006a4e1b","unresolved":false,"context_lines":[{"line_number":364,"context_line":"    multi_member_of \u003d want_version.matches((1, 24))"},{"line_number":365,"context_line":"    if not multi_member_of and len(req.GET.getall(\u0027member_of\u0027 + suffix)) \u003e 1:"},{"line_number":366,"context_line":"        raise webob.exc.HTTPBadRequest("},{"line_number":367,"context_line":"            _(\u0027Multiple member_of%s parameters are not supported\u0027) % suffix)"},{"line_number":368,"context_line":"    values \u003d []"},{"line_number":369,"context_line":"    for value in req.GET.getall(\u0027member_of\u0027 + suffix):"},{"line_number":370,"context_line":"        values.append(normalize_member_of_qs_param(value))"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_c0b6af3f","line":367,"range":{"start_line":367,"start_character":12,"end_line":367,"end_character":76},"updated":"2018-04-26 15:49:59.000000000","message":"Add an error code","commit_id":"2ba1df7541a9e108d7db00653e46dd1f799099bd"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"47891dd36d724c77446e6583604c1725006a4e1b","unresolved":false,"context_lines":[{"line_number":535,"context_line":"        msg \u003d _(\u0027All member_of parameters must be associated with \u0027"},{"line_number":536,"context_line":"                \u0027resources. Found the following orphaned member_of \u0027"},{"line_number":537,"context_line":"                \u0027 values: %s\u0027)"},{"line_number":538,"context_line":"        raise webob.exc.HTTPBadRequest(msg % \u0027, \u0027.join(orphans))"},{"line_number":539,"context_line":""},{"line_number":540,"context_line":"    # Make adjustments for forbidden traits by stripping forbidden out"},{"line_number":541,"context_line":"    # of required."}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_e0e1732c","line":538,"range":{"start_line":538,"start_character":8,"end_line":538,"end_character":64},"updated":"2018-04-26 15:49:59.000000000","message":"Oh, I guess you didn\u0027t add this one.  But we should add an error code here too.  (In a fup if you don\u0027t want to \"pollute\" this patch.)","commit_id":"2ba1df7541a9e108d7db00653e46dd1f799099bd"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":528,"context_line":"        msg \u003d _(\u0027All traits parameters must be associated with resources.  \u0027"},{"line_number":529,"context_line":"                \u0027Found the following orphaned traits keys: %s\u0027)"},{"line_number":530,"context_line":"        raise webob.exc.HTTPBadRequest(msg % \u0027, \u0027.join(orphans))"},{"line_number":531,"context_line":""},{"line_number":532,"context_line":"    orphans \u003d [(\u0027member_of%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":533,"context_line":"                              if group.member_of and not group.resources]"},{"line_number":534,"context_line":"    if orphans:"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_c1f2359b","line":531,"updated":"2018-05-03 10:22:16.000000000","message":"unrelated change, but I\u0027m ok with this one","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"bd43ee0a46175b3d12ef16a4f04d5f1699c9b985","unresolved":false,"context_lines":[{"line_number":528,"context_line":"        msg \u003d _(\u0027All traits parameters must be associated with resources.  \u0027"},{"line_number":529,"context_line":"                \u0027Found the following orphaned traits keys: %s\u0027)"},{"line_number":530,"context_line":"        raise webob.exc.HTTPBadRequest(msg % \u0027, \u0027.join(orphans))"},{"line_number":531,"context_line":""},{"line_number":532,"context_line":"    orphans \u003d [(\u0027member_of%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":533,"context_line":"                              if group.member_of and not group.resources]"},{"line_number":534,"context_line":"    if orphans:"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_d2c8c575","line":531,"in_reply_to":"5f7c97a3_c1f2359b","updated":"2018-05-03 13:02:43.000000000","message":"Done","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":530,"context_line":"        raise webob.exc.HTTPBadRequest(msg % \u0027, \u0027.join(orphans))"},{"line_number":531,"context_line":""},{"line_number":532,"context_line":"    orphans \u003d [(\u0027member_of%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":533,"context_line":"                              if group.member_of and not group.resources]"},{"line_number":534,"context_line":"    if orphans:"},{"line_number":535,"context_line":"        msg \u003d _(\u0027All member_of parameters must be associated with \u0027"},{"line_number":536,"context_line":"                \u0027resources. Found the following orphaned member_of \u0027"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_21f68991","line":533,"range":{"start_line":533,"start_character":15,"end_line":533,"end_character":30},"updated":"2018-05-03 10:22:16.000000000","message":"not this one though","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"bd43ee0a46175b3d12ef16a4f04d5f1699c9b985","unresolved":false,"context_lines":[{"line_number":530,"context_line":"        raise webob.exc.HTTPBadRequest(msg % \u0027, \u0027.join(orphans))"},{"line_number":531,"context_line":""},{"line_number":532,"context_line":"    orphans \u003d [(\u0027member_of%s\u0027 % suff) for suff, group in by_suffix.items()"},{"line_number":533,"context_line":"                              if group.member_of and not group.resources]"},{"line_number":534,"context_line":"    if orphans:"},{"line_number":535,"context_line":"        msg \u003d _(\u0027All member_of parameters must be associated with \u0027"},{"line_number":536,"context_line":"                \u0027resources. Found the following orphaned member_of \u0027"}],"source_content_type":"text/x-python","patch_set":15,"id":"5f7c97a3_f2c5c15c","line":533,"range":{"start_line":533,"start_character":15,"end_line":533,"end_character":30},"in_reply_to":"5f7c97a3_21f68991","updated":"2018-05-03 13:02:43.000000000","message":"Done. Was a rebase conflict goof...","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"}],"nova/tests/functional/api/openstack/placement/gabbits/resource-provider-aggregates.yaml":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":120,"context_line":"      $.errors[0].title: Bad Request"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":"- name: error trying multiple member_of params prior correct microversion"},{"line_number":123,"context_line":"  GET: \u0027/resource_providers?member_of\u003d83a3d69d-8920-48e2-8914-cadfd8fa2f91\u0026member_of\u003d99652f11-9f77-46b9-80b7-4b1989be9f8c\u0027"},{"line_number":124,"context_line":"  request_headers:"},{"line_number":125,"context_line":"      openstack-api-version: placement 1.21"},{"line_number":126,"context_line":"  status: 400"}],"source_content_type":"text/x-yaml","patch_set":3,"id":"bf659307_60c82654","line":123,"range":{"start_line":123,"start_character":38,"end_line":123,"end_character":74},"updated":"2018-04-13 22:06:47.000000000","message":"ugh, I guess this is carried over from above, but we should have agg UUIDs set up in the fixture.  It\u0027s hard to read/validate these by eye.","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":176,"context_line":"      # and each is associated with either agg 99652f11 or agg 282s469e"},{"line_number":177,"context_line":"      $.resource_providers.`len`: 2"},{"line_number":178,"context_line":"      $.resource_providers[0].uuid: /5202c48f-c960-4eec-bde3-89c4f22a17b9|893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/"},{"line_number":179,"context_line":"      $.resource_providers[1].uuid: /5202c48f-c960-4eec-bde3-89c4f22a17b9|893337e9-1e55-49f0-bcfe-6a2f16fbf2f7/"}],"source_content_type":"text/x-yaml","patch_set":3,"id":"bf659307_c007b281","line":179,"updated":"2018-04-13 22:06:47.000000000","message":"Add test cases including an aggregate that doesn\u0027t exist in the aggregates table.  If it\u0027s alone in a member_of, it should yield no results; but if it\u0027s one of an in: where another in the same list does exist and has a provider associated with it, we should return that provider.  (See comment at [1]).\n\n[1] https://review.openstack.org/#/c/561315/3/nova/api/openstack/placement/objects/resource_provider.py@716","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"10cd23ee40aa0e30e70bf8dc024d7364865db19f","unresolved":false,"context_lines":[{"line_number":120,"context_line":"      $.errors[0].title: Bad Request"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":"- name: error trying multiple member_of params prior correct microversion"},{"line_number":123,"context_line":"  GET: \u0027/resource_providers?member_of\u003d83a3d69d-8920-48e2-8914-cadfd8fa2f91\u0026member_of\u003d99652f11-9f77-46b9-80b7-4b1989be9f8c\u0027"},{"line_number":124,"context_line":"  request_headers:"},{"line_number":125,"context_line":"      openstack-api-version: placement 1.22"},{"line_number":126,"context_line":"  status: 400"}],"source_content_type":"text/x-yaml","patch_set":4,"id":"9f6a8fd7_a494bd45","line":123,"updated":"2018-04-17 17:32:48.000000000","message":"I may have said this before, but this would be easier to read with macros for the agg UUIDs.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"81991ef14c7f19fdea84bfd754960a861c0b595c","unresolved":false,"context_lines":[{"line_number":120,"context_line":"      $.errors[0].title: Bad Request"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":"- name: error trying multiple member_of params prior correct microversion"},{"line_number":123,"context_line":"  GET: \u0027/resource_providers?member_of\u003d83a3d69d-8920-48e2-8914-cadfd8fa2f91\u0026member_of\u003d99652f11-9f77-46b9-80b7-4b1989be9f8c\u0027"},{"line_number":124,"context_line":"  request_headers:"},{"line_number":125,"context_line":"      openstack-api-version: placement 1.22"},{"line_number":126,"context_line":"  status: 400"}],"source_content_type":"text/x-yaml","patch_set":4,"id":"9f6a8fd7_bd212cb7","line":123,"in_reply_to":"9f6a8fd7_a494bd45","updated":"2018-04-17 20:03:30.000000000","message":"yeah, I can try and clean this up in a later patch. this is just copying the existing tests.","commit_id":"108d83202a161d20f35b872b11791a061601fd5f"},{"author":{"_account_id":25625,"name":"Tetsuro Nakamura","email":"tetsuro.nakamura.bc@hco.ntt.co.jp","username":"tetsuro0907"},"change_message_id":"b14538cc3d432532739cc8c5d7d8ff35ea5e3404","unresolved":false,"context_lines":[{"line_number":132,"context_line":"- name: multiple member_of params with no results"},{"line_number":133,"context_line":"  GET: \u0027/resource_providers?member_of\u003d83a3d69d-8920-48e2-8914-cadfd8fa2f91\u0026member_of\u003d99652f11-9f77-46b9-80b7-4b1989be9f8c\u0027"},{"line_number":134,"context_line":"  status: 200"},{"line_number":135,"context_line":"  data:"},{"line_number":136,"context_line":"      # No provider is associated with both aggregates"},{"line_number":137,"context_line":"      resource_providers: []"},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"- name: associate two aggregates with rp2"},{"line_number":140,"context_line":"  PUT: /resource_providers/5202c48f-c960-4eec-bde3-89c4f22a17b9/aggregates"}],"source_content_type":"text/x-yaml","patch_set":7,"id":"9f6a8fd7_1b04bf7a","line":137,"range":{"start_line":135,"start_character":0,"end_line":137,"end_character":28},"updated":"2018-04-19 01:46:55.000000000","message":"The \"data\" is used for writing the *request* body from the *client*. We should use \"response_json_paths\" to validate the *response* body from the *server*.\n\nThe same can be said of the following test cases  using GET API.","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"cacb83f047b59b852066451ac5e46f233d976403","unresolved":false,"context_lines":[{"line_number":132,"context_line":"- name: multiple member_of params with no results"},{"line_number":133,"context_line":"  GET: \u0027/resource_providers?member_of\u003d83a3d69d-8920-48e2-8914-cadfd8fa2f91\u0026member_of\u003d99652f11-9f77-46b9-80b7-4b1989be9f8c\u0027"},{"line_number":134,"context_line":"  status: 200"},{"line_number":135,"context_line":"  data:"},{"line_number":136,"context_line":"      # No provider is associated with both aggregates"},{"line_number":137,"context_line":"      resource_providers: []"},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"- name: associate two aggregates with rp2"},{"line_number":140,"context_line":"  PUT: /resource_providers/5202c48f-c960-4eec-bde3-89c4f22a17b9/aggregates"}],"source_content_type":"text/x-yaml","patch_set":7,"id":"9f6a8fd7_59f15200","line":137,"range":{"start_line":135,"start_character":0,"end_line":137,"end_character":28},"in_reply_to":"9f6a8fd7_1b04bf7a","updated":"2018-04-25 16:52:18.000000000","message":"Done","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63cfac78bb5b333aaf8bf8dc7e97e505e45f6efd","unresolved":false,"context_lines":[{"line_number":53,"context_line":"  GET: \u0027/resource_providers?member_of\u003dnot+a+uuid\u0027"},{"line_number":54,"context_line":"  status: 400"},{"line_number":55,"context_line":"  response_strings:"},{"line_number":56,"context_line":"    - \"Expected \u0027member_of\u0027 parameter to contain valid UUID(s). Got: not a uuid\""},{"line_number":57,"context_line":"  response_json_paths:"},{"line_number":58,"context_line":"      $.errors[0].title: Bad Request"},{"line_number":59,"context_line":""}],"source_content_type":"text/x-yaml","patch_set":8,"id":"9f6a8fd7_c3749000","line":56,"range":{"start_line":56,"start_character":63,"end_line":56,"end_character":80},"updated":"2018-04-25 19:30:44.000000000","message":"why remove this?","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"62028af7d8c8144ab486874e13d23b2d98fbba47","unresolved":false,"context_lines":[{"line_number":53,"context_line":"  GET: \u0027/resource_providers?member_of\u003dnot+a+uuid\u0027"},{"line_number":54,"context_line":"  status: 400"},{"line_number":55,"context_line":"  response_strings:"},{"line_number":56,"context_line":"    - \"Expected \u0027member_of\u0027 parameter to contain valid UUID(s). Got: not a uuid\""},{"line_number":57,"context_line":"  response_json_paths:"},{"line_number":58,"context_line":"      $.errors[0].title: Bad Request"},{"line_number":59,"context_line":""}],"source_content_type":"text/x-yaml","patch_set":8,"id":"9f6a8fd7_26ceba59","line":56,"range":{"start_line":56,"start_character":63,"end_line":56,"end_character":80},"in_reply_to":"9f6a8fd7_c3749000","updated":"2018-04-25 19:55:07.000000000","message":"rebase hell.","commit_id":"4d2094bcf7f373a2357adf2c4d3ee8c1033dcfc8"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":15,"id":"5f7c97a3_410dc58e","line":174,"updated":"2018-05-03 10:22:16.000000000","message":"I imagine a duplicate test (e.g. two identical aggregate UUIDs) would be helpful too","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"bd43ee0a46175b3d12ef16a4f04d5f1699c9b985","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":15,"id":"5f7c97a3_52aa7585","line":174,"in_reply_to":"5f7c97a3_410dc58e","updated":"2018-05-03 13:02:43.000000000","message":"Done","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"}],"nova/tests/unit/api/openstack/placement/test_util.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"ede72277a347db3153d678261a537636bdd052c9","unresolved":false,"context_lines":[{"line_number":681,"context_line":"              \u0027\u0026required\u003dHW_CPU_X86_VMX,CUSTOM_MEM_FLASH,STORAGE_DISK_SSD\u0027"},{"line_number":682,"context_line":"              \u0027\u0026member_of2\u003d%s\u0027 % agg1_uuid)"},{"line_number":683,"context_line":"        self.assertRaises(webob.exc.HTTPBadRequest, self.do_parse, qs)"},{"line_number":684,"context_line":""},{"line_number":685,"context_line":"    def test_forbidden_one_group(self):"},{"line_number":686,"context_line":"        \"\"\"When forbidden are allowed this will parse, but otherwise will"},{"line_number":687,"context_line":"        indicate an invalid trait."}],"source_content_type":"text/x-python","patch_set":13,"id":"9f6a8fd7_31a34003","line":684,"updated":"2018-04-26 14:25:36.000000000","message":"We don\u0027t have coverage for a successful parsing of one or more numbered member_of\u003cN\u003e.\n\nI suppose that can be added in a fup.","commit_id":"99a2f01fcdf0920409918eb1ce945bc913142df4"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"47891dd36d724c77446e6583604c1725006a4e1b","unresolved":false,"context_lines":[{"line_number":631,"context_line":"        agg3_uuid \u003d uuidsentinel.agg3"},{"line_number":632,"context_line":"        qs \u003d (\u0027resources1\u003dVCPU:2\u0027"},{"line_number":633,"context_line":"              \u0027\u0026member_of1\u003d%s\u0027"},{"line_number":634,"context_line":"              \u0027\u0026member_of1\u003d%s\u0027"},{"line_number":635,"context_line":"              \u0027\u0026resources2\u003dVCPU:2\u0027"},{"line_number":636,"context_line":"              \u0027\u0026member_of2\u003d%s\u0027% (agg1_uuid, agg2_uuid, agg3_uuid))"},{"line_number":637,"context_line":"        expected \u003d ["}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_e0fdf3b1","line":634,"range":{"start_line":634,"start_character":16,"end_line":634,"end_character":26},"updated":"2018-04-26 15:49:59.000000000","message":"Can you make one of these an \u0027in:\u0027 with multiple?","commit_id":"2ba1df7541a9e108d7db00653e46dd1f799099bd"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"313afaad2cd3ea6269816da214dc7e2d81e5a591","unresolved":false,"context_lines":[{"line_number":631,"context_line":"        agg3_uuid \u003d uuidsentinel.agg3"},{"line_number":632,"context_line":"        qs \u003d (\u0027resources1\u003dVCPU:2\u0027"},{"line_number":633,"context_line":"              \u0027\u0026member_of1\u003d%s\u0027"},{"line_number":634,"context_line":"              \u0027\u0026member_of1\u003d%s\u0027"},{"line_number":635,"context_line":"              \u0027\u0026resources2\u003dVCPU:2\u0027"},{"line_number":636,"context_line":"              \u0027\u0026member_of2\u003d%s\u0027% (agg1_uuid, agg2_uuid, agg3_uuid))"},{"line_number":637,"context_line":"        expected \u003d ["}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_f925aa0b","line":634,"range":{"start_line":634,"start_character":16,"end_line":634,"end_character":26},"in_reply_to":"9f6a8fd7_e0fdf3b1","updated":"2018-04-26 18:47:43.000000000","message":"Done","commit_id":"2ba1df7541a9e108d7db00653e46dd1f799099bd"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"47891dd36d724c77446e6583604c1725006a4e1b","unresolved":false,"context_lines":[{"line_number":633,"context_line":"              \u0027\u0026member_of1\u003d%s\u0027"},{"line_number":634,"context_line":"              \u0027\u0026member_of1\u003d%s\u0027"},{"line_number":635,"context_line":"              \u0027\u0026resources2\u003dVCPU:2\u0027"},{"line_number":636,"context_line":"              \u0027\u0026member_of2\u003d%s\u0027% (agg1_uuid, agg2_uuid, agg3_uuid))"},{"line_number":637,"context_line":"        expected \u003d ["},{"line_number":638,"context_line":"            pl.RequestGroup("},{"line_number":639,"context_line":"                resources\u003d{"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_0072677d","line":636,"range":{"start_line":636,"start_character":29,"end_line":636,"end_character":31},"updated":"2018-04-26 15:49:59.000000000","message":"I think pep will kick you out here.","commit_id":"2ba1df7541a9e108d7db00653e46dd1f799099bd"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"313afaad2cd3ea6269816da214dc7e2d81e5a591","unresolved":false,"context_lines":[{"line_number":633,"context_line":"              \u0027\u0026member_of1\u003d%s\u0027"},{"line_number":634,"context_line":"              \u0027\u0026member_of1\u003d%s\u0027"},{"line_number":635,"context_line":"              \u0027\u0026resources2\u003dVCPU:2\u0027"},{"line_number":636,"context_line":"              \u0027\u0026member_of2\u003d%s\u0027% (agg1_uuid, agg2_uuid, agg3_uuid))"},{"line_number":637,"context_line":"        expected \u003d ["},{"line_number":638,"context_line":"            pl.RequestGroup("},{"line_number":639,"context_line":"                resources\u003d{"}],"source_content_type":"text/x-python","patch_set":14,"id":"9f6a8fd7_b91f32b6","line":636,"range":{"start_line":636,"start_character":29,"end_line":636,"end_character":31},"in_reply_to":"9f6a8fd7_0072677d","updated":"2018-04-26 18:47:43.000000000","message":"Done","commit_id":"2ba1df7541a9e108d7db00653e46dd1f799099bd"}],"placement-api-ref/source/parameters.yaml":[{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"7a5581834e1297fcffcaf70a6f3191aad85fcba4","unresolved":false,"context_lines":[{"line_number":75,"context_line":"        member_of\u003d5e08ea53-c4c6-448e-9334-ac4953de3cfa"},{"line_number":76,"context_line":"        member_of\u003din:42896e0d-205d-4fe3-bd1e-100924931787,5e08ea53-c4c6-448e-9334-ac4953de3cfa"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    **Starting from microversion 1.24** specifying multiple ``member_of`` query"},{"line_number":79,"context_line":"    string parameters is possible. Multiple ``member_of`` parameters will"},{"line_number":80,"context_line":"    result in filtering providers that are associated with aggregates listed in"},{"line_number":81,"context_line":"    all of the ``member_of`` query string values. For example, to get the"}],"source_content_type":"text/x-yaml","patch_set":15,"id":"5f7c97a3_8178bdf8","line":78,"range":{"start_line":78,"start_character":4,"end_line":78,"end_character":39},"updated":"2018-05-03 10:22:16.000000000","message":"I wonder would the \u0027versionchanged\u0027 directive make sense here? [1]\n\n[1] http://www.sphinx-doc.org/en/latest/usage/restructuredtext/directives.html#directive-versionchanged","commit_id":"e9956acc37549b529d93d5bfa08033f717ea3089"}],"releasenotes/notes/get-resource-providers-multi-member-of-4f9518a96652c0c6.yaml":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":9,"context_line":"    supported and continues to indicate an IN() operation for aggregate"},{"line_number":10,"context_line":"    membership. Some examples for using the new functionality:"},{"line_number":11,"context_line":"    Get all providers that are associated with BOTH agg1 and agg2:"},{"line_number":12,"context_line":"       ?member_of\u003dagg1\u0026member_of\u003dagg2`"},{"line_number":13,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2:"},{"line_number":14,"context_line":"       ?member_of\u003din:agg1,agg2`"},{"line_number":15,"context_line":"    Get all providers that are associated with agg1 and EITHER agg2 OR agg3:"}],"source_content_type":"text/x-yaml","patch_set":3,"id":"bf659307_6094a68b","line":12,"range":{"start_line":12,"start_character":37,"end_line":12,"end_character":38},"updated":"2018-04-13 22:06:47.000000000","message":"trailing backtick weirdness throughout.  Is this some kind of sphinx-ism I\u0027m not familiar with?\n\nIn any case, perhaps double-backticks (to make \u003ctt\u003eish) would be more appropriate for all the examples.","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":10,"context_line":"    membership. Some examples for using the new functionality:"},{"line_number":11,"context_line":"    Get all providers that are associated with BOTH agg1 and agg2:"},{"line_number":12,"context_line":"       ?member_of\u003dagg1\u0026member_of\u003dagg2`"},{"line_number":13,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2:"},{"line_number":14,"context_line":"       ?member_of\u003din:agg1,agg2`"},{"line_number":15,"context_line":"    Get all providers that are associated with agg1 and EITHER agg2 OR agg3:"},{"line_number":16,"context_line":"       ?member_of\u003dagg1\u0026member_of\u003din:agg2,agg3`"}],"source_content_type":"text/x-yaml","patch_set":3,"id":"bf659307_e088b671","line":13,"range":{"start_line":13,"start_character":47,"end_line":13,"end_character":61},"updated":"2018-04-13 22:06:47.000000000","message":"EITHER/OR implies XOR, which is not the case.  Suggest AND/OR instead.\n\n(same below)","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2ddf97a927fe4c2a6eb959d04ff5a922e176ae20","unresolved":false,"context_lines":[{"line_number":16,"context_line":"       ?member_of\u003dagg1\u0026member_of\u003din:agg2,agg3`"},{"line_number":17,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2 AND are also"},{"line_number":18,"context_line":"    associated with EITHER agg3 OR agg4:"},{"line_number":19,"context_line":"       ?member_of\u003din:agg1,agg2\u0026member_of\u003din:agg3,agg4`"}],"source_content_type":"text/x-yaml","patch_set":3,"id":"bf659307_008fea74","line":19,"updated":"2018-04-13 22:06:47.000000000","message":"++ good examples.","commit_id":"4af396725757a676e6aa3fa24ff7ec1422c7fd98"}],"releasenotes/notes/multi-member-of-4f9518a96652c0c6.yaml":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1348876968f31eeece8200e98e1ec5a5fd3a4a1e","unresolved":false,"context_lines":[{"line_number":10,"context_line":"    supported and continues to indicate an IN() operation for aggregate"},{"line_number":11,"context_line":"    membership. Some examples for using the new functionality:"},{"line_number":12,"context_line":"    Get all providers that are associated with BOTH agg1 and agg2:"},{"line_number":13,"context_line":"    ?member_of\u003dagg1\u0026member_of\u003dagg2`"},{"line_number":14,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2:"},{"line_number":15,"context_line":"    ?member_of\u003din:agg1,agg2`"},{"line_number":16,"context_line":"    Get all providers that are associated with agg1 and EITHER agg2 OR agg3:"}],"source_content_type":"text/x-yaml","patch_set":7,"id":"9f6a8fd7_98cf967e","line":13,"updated":"2018-04-17 20:27:53.000000000","message":"Changes for \"any of\" as in rest_api_version_history.rst","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"cacb83f047b59b852066451ac5e46f233d976403","unresolved":false,"context_lines":[{"line_number":10,"context_line":"    supported and continues to indicate an IN() operation for aggregate"},{"line_number":11,"context_line":"    membership. Some examples for using the new functionality:"},{"line_number":12,"context_line":"    Get all providers that are associated with BOTH agg1 and agg2:"},{"line_number":13,"context_line":"    ?member_of\u003dagg1\u0026member_of\u003dagg2`"},{"line_number":14,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2:"},{"line_number":15,"context_line":"    ?member_of\u003din:agg1,agg2`"},{"line_number":16,"context_line":"    Get all providers that are associated with agg1 and EITHER agg2 OR agg3:"}],"source_content_type":"text/x-yaml","patch_set":7,"id":"9f6a8fd7_f98aa661","line":13,"in_reply_to":"9f6a8fd7_98cf967e","updated":"2018-04-25 16:52:18.000000000","message":"Done","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"c4d250d21967f0792f2d85c79ee3e29297c0d55f","unresolved":false,"context_lines":[{"line_number":10,"context_line":"    supported and continues to indicate an IN() operation for aggregate"},{"line_number":11,"context_line":"    membership. Some examples for using the new functionality:"},{"line_number":12,"context_line":"    Get all providers that are associated with BOTH agg1 and agg2:"},{"line_number":13,"context_line":"    ?member_of\u003dagg1\u0026member_of\u003dagg2`"},{"line_number":14,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2:"},{"line_number":15,"context_line":"    ?member_of\u003din:agg1,agg2`"},{"line_number":16,"context_line":"    Get all providers that are associated with agg1 and EITHER agg2 OR agg3:"}],"source_content_type":"text/x-yaml","patch_set":7,"id":"9f6a8fd7_79ac569e","line":13,"in_reply_to":"9f6a8fd7_f98aa661","updated":"2018-04-25 17:01:31.000000000","message":"not done","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1348876968f31eeece8200e98e1ec5a5fd3a4a1e","unresolved":false,"context_lines":[{"line_number":17,"context_line":"    ?member_of\u003dagg1\u0026member_of\u003din:agg2,agg3`"},{"line_number":18,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2 AND are also"},{"line_number":19,"context_line":"    associated with EITHER agg3 OR agg4:"},{"line_number":20,"context_line":"    ?member_of\u003din:agg1,agg2\u0026member_of\u003din:agg3,agg4`"}],"source_content_type":"text/x-yaml","patch_set":7,"id":"9f6a8fd7_58c9fe75","line":20,"range":{"start_line":20,"start_character":50,"end_line":20,"end_character":51},"updated":"2018-04-17 20:27:53.000000000","message":"Still got weird trailing backticks throughout here.\n\nSuggest putting these querystring examples in double backticks.","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"c4d250d21967f0792f2d85c79ee3e29297c0d55f","unresolved":false,"context_lines":[{"line_number":17,"context_line":"    ?member_of\u003dagg1\u0026member_of\u003din:agg2,agg3`"},{"line_number":18,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2 AND are also"},{"line_number":19,"context_line":"    associated with EITHER agg3 OR agg4:"},{"line_number":20,"context_line":"    ?member_of\u003din:agg1,agg2\u0026member_of\u003din:agg3,agg4`"}],"source_content_type":"text/x-yaml","patch_set":7,"id":"9f6a8fd7_19975a4a","line":20,"range":{"start_line":20,"start_character":50,"end_line":20,"end_character":51},"in_reply_to":"9f6a8fd7_196c3acc","updated":"2018-04-25 17:01:31.000000000","message":"not done","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"cacb83f047b59b852066451ac5e46f233d976403","unresolved":false,"context_lines":[{"line_number":17,"context_line":"    ?member_of\u003dagg1\u0026member_of\u003din:agg2,agg3`"},{"line_number":18,"context_line":"    Get all providers that are associated with EITHER agg1 OR agg2 AND are also"},{"line_number":19,"context_line":"    associated with EITHER agg3 OR agg4:"},{"line_number":20,"context_line":"    ?member_of\u003din:agg1,agg2\u0026member_of\u003din:agg3,agg4`"}],"source_content_type":"text/x-yaml","patch_set":7,"id":"9f6a8fd7_196c3acc","line":20,"range":{"start_line":20,"start_character":50,"end_line":20,"end_character":51},"in_reply_to":"9f6a8fd7_58c9fe75","updated":"2018-04-25 16:52:18.000000000","message":"Done","commit_id":"bc009bcf728ad54e13798a2cf99cded5da569f3b"}]}
