)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7c3c485a06279c3d7fb124bf1afff54cb09687d2","unresolved":false,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Reworks the way that we solve requests for resource when nested resource"},{"line_number":10,"context_line":"providers are present. When a granular request group is *not* sent, we"},{"line_number":11,"context_line":"ensure that all resources in the request are met by a single provider"},{"line_number":12,"context_line":"(not summing inventories across the tree). For each resource in the"},{"line_number":13,"context_line":"request, we make a separate query to determine the provider and root"},{"line_number":14,"context_line":"provider IDs of those resource providers which can satisfy that request"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"df7087c5_d48e2d26","line":11,"range":{"start_line":11,"start_character":16,"end_line":11,"end_character":40},"updated":"2018-03-20 22:38:06.000000000","message":"of a single resource class.\n\n(as written, implies that all the resources will come from a single provider)","commit_id":"f4fac22462c9a769df3a25ed32bf7fe0d5a3929d"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7c3c485a06279c3d7fb124bf1afff54cb09687d2","unresolved":false,"context_lines":[{"line_number":16,"context_line":""},{"line_number":17,"context_line":"We then filter out providers that are in trees that did *not* have all"},{"line_number":18,"context_line":"resources met by some provider in the tree. After that, we can further"},{"line_number":19,"context_line":"filter for the providers in trees that **collectively** contain the"},{"line_number":20,"context_line":"traits we require as well."},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"Change-Id: I343a0cb19f4037ddde5c5fc96d0a053f699f5257"},{"line_number":23,"context_line":"blueprint: nested-resource-providers-allocation-candidates"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"df7087c5_54cbfd51","line":20,"range":{"start_line":19,"start_character":28,"end_line":20,"end_character":26},"updated":"2018-03-20 22:38:06.000000000","message":"this should specify that the traits must be satisfied only by the providers actually providing resource.","commit_id":"f4fac22462c9a769df3a25ed32bf7fe0d5a3929d"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"ff97ca50ed49e7cc58b24d0a1a594236b7bd704c","unresolved":false,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Reworks the way that we solve requests for resource when nested resource"},{"line_number":10,"context_line":"providers are present. When a granular request group is *not* sent, we"},{"line_number":11,"context_line":"ensure that all resources in the request are met by a single provider"},{"line_number":12,"context_line":"(not summing inventories across the tree). For each resource in the"},{"line_number":13,"context_line":"request, we make a separate query to determine the provider and root"},{"line_number":14,"context_line":"provider IDs of those resource providers which can satisfy that request"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"bf659307_3fb78889","line":11,"range":{"start_line":11,"start_character":16,"end_line":11,"end_character":40},"updated":"2018-03-23 21:53:06.000000000","message":"see PS1 comment","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"91d8250fa83f6f39ba099a417616f2c9ef684021","unresolved":false,"context_lines":[{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Reworks the way that we solve requests for resource when nested resource"},{"line_number":10,"context_line":"providers are present. When a granular request group is *not* sent, we"},{"line_number":11,"context_line":"ensure that all resources in the request are met by a single provider"},{"line_number":12,"context_line":"(not summing inventories across the tree). For each resource in the"},{"line_number":13,"context_line":"request, we make a separate query to determine the provider and root"},{"line_number":14,"context_line":"provider IDs of those resource providers which can satisfy that request"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"bf659307_cb3ddc2b","line":11,"range":{"start_line":11,"start_character":16,"end_line":11,"end_character":40},"in_reply_to":"bf659307_3fb78889","updated":"2018-03-29 19:12:03.000000000","message":"Done","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b0c12201a8c7e823f22a8c639f386054bea107c","unresolved":false,"context_lines":[{"line_number":17,"context_line":"We then filter out providers that are in trees that did *not* have all"},{"line_number":18,"context_line":"resources met by some provider in the tree. After that, we further"},{"line_number":19,"context_line":"filter for the providers that are in trees that contain all required"},{"line_number":20,"context_line":"traits and that the provider of those traits were the providers giving"},{"line_number":21,"context_line":"inventory to the request."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"Change-Id: I343a0cb19f4037ddde5c5fc96d0a053f699f5257"},{"line_number":24,"context_line":"blueprint: nested-resource-providers-allocation-candidates"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"9f6a8fd7_dfecc690","line":21,"range":{"start_line":20,"start_character":32,"end_line":21,"end_character":25},"updated":"2018-04-20 14:19:53.000000000","message":"This is there to avoid getting the HW_NIC_OFFLOAD_GENEVE trait from one of the PF while getting the VF allocation from the other PF not having this trait. So I see that traits on siblings are something we should not consider during the matching. \nHowever is there any reason, besides that we don\u0027t need it yet, not to consider traits from parents? For example in the networking side I can imagine that a backend agent supports a capability but the resources are provided by the child RPs of that agent. I don\u0027t feel it a serious issue as it can be worked around today by adding the trait directly to each child RP of that agent.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"7d48fbae99bf5efe0a442c8be0ee29d364df8e26","unresolved":false,"context_lines":[{"line_number":17,"context_line":"We then filter out providers that are in trees that did *not* have all"},{"line_number":18,"context_line":"resources met by some provider in the tree. After that, we further"},{"line_number":19,"context_line":"filter for the providers that are in trees that contain all required"},{"line_number":20,"context_line":"traits and that the provider of those traits were the providers giving"},{"line_number":21,"context_line":"inventory to the request."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"Change-Id: I343a0cb19f4037ddde5c5fc96d0a053f699f5257"},{"line_number":24,"context_line":"blueprint: nested-resource-providers-allocation-candidates"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"9f6a8fd7_e3dd14dd","line":21,"range":{"start_line":20,"start_character":32,"end_line":21,"end_character":25},"in_reply_to":"9f6a8fd7_dfecc690","updated":"2018-04-25 19:26:55.000000000","message":"Good question. Eric had wanted to make a separate \"traits_in_subtree\" approach at some point in the future.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"97924a3035da12ffde0798677043de9467c9b00d","unresolved":false,"context_lines":[{"line_number":17,"context_line":"We then filter out providers that are in trees that did *not* have all"},{"line_number":18,"context_line":"resources met by some provider in the tree. After that, we further"},{"line_number":19,"context_line":"filter for the providers that are in trees that contain all required"},{"line_number":20,"context_line":"traits and that the provider of those traits were the providers giving"},{"line_number":21,"context_line":"inventory to the request."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"Change-Id: I343a0cb19f4037ddde5c5fc96d0a053f699f5257"},{"line_number":24,"context_line":"blueprint: nested-resource-providers-allocation-candidates"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"9f6a8fd7_66acb29e","line":21,"range":{"start_line":20,"start_character":32,"end_line":21,"end_character":25},"in_reply_to":"9f6a8fd7_e3dd14dd","updated":"2018-04-25 19:49:59.000000000","message":"I remember we talked about trait \"inheritance\" - it was early in Queens IIRC, and you hate the word \"inheritance\" - and we actually decided that traits would indeed propagate.  But we haven\u0027t implemented it that way.  Nor, in retrospect, do I think we should do so.  I have no problem requiring the user to mark traits explicitly on each provider to which the trait applies.\n\nThe \"common_ancestor_by_trait\" thing is a little different.  It\u0027s a way to affinitize resources from sibling/cousin providers.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"}],"nova/api/openstack/placement/objects/resource_provider.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7c3c485a06279c3d7fb124bf1afff54cb09687d2","unresolved":false,"context_lines":[{"line_number":3002,"context_line":"    sel \u003d sel.where(sa.and_(*where_conds))"},{"line_number":3003,"context_line":"    res \u003d ctx.session.execute(sel).fetchall()"},{"line_number":3004,"context_line":"    res \u003d set((r[0], r[1]) for r in res)"},{"line_number":3005,"context_line":"    return res"},{"line_number":3006,"context_line":""},{"line_number":3007,"context_line":""},{"line_number":3008,"context_line":"@db_api.api_context_manager.reader"}],"source_content_type":"text/x-python","patch_set":1,"id":"df7087c5_afb800e5","line":3005,"updated":"2018-03-20 22:38:06.000000000","message":"We should (still) factor the bulk of this query out into a common helper.","commit_id":"f4fac22462c9a769df3a25ed32bf7fe0d5a3929d"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7c3c485a06279c3d7fb124bf1afff54cb09687d2","unresolved":false,"context_lines":[{"line_number":3009,"context_line":"def _get_trees_matching_all(ctx, resources, required_traits, member_of):"},{"line_number":3010,"context_line":"    \"\"\"Returns a list of two-tuples (provider internal ID, root provider"},{"line_number":3011,"context_line":"    internal ID)s for provider trees where the nodes in the tree can"},{"line_number":3012,"context_line":"    INDIVIDUALLY satisfy the resource requests and the tree COLLECTIVELY is"},{"line_number":3013,"context_line":"    able to satisfy the require trait constraints."},{"line_number":3014,"context_line":""},{"line_number":3015,"context_line":"    :note: This function is used for scenarios that do NOT involve sharing"}],"source_content_type":"text/x-python","patch_set":1,"id":"df7087c5_0fac8c8a","line":3012,"range":{"start_line":3012,"start_character":51,"end_line":3012,"end_character":59},"updated":"2018-03-20 22:38:06.000000000","message":"the providers providing resource","commit_id":"f4fac22462c9a769df3a25ed32bf7fe0d5a3929d"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7c3c485a06279c3d7fb124bf1afff54cb09687d2","unresolved":false,"context_lines":[{"line_number":3010,"context_line":"    \"\"\"Returns a list of two-tuples (provider internal ID, root provider"},{"line_number":3011,"context_line":"    internal ID)s for provider trees where the nodes in the tree can"},{"line_number":3012,"context_line":"    INDIVIDUALLY satisfy the resource requests and the tree COLLECTIVELY is"},{"line_number":3013,"context_line":"    able to satisfy the require trait constraints."},{"line_number":3014,"context_line":""},{"line_number":3015,"context_line":"    :note: This function is used for scenarios that do NOT involve sharing"},{"line_number":3016,"context_line":"    providers AND where there are nested providers present in the deployment."}],"source_content_type":"text/x-python","patch_set":1,"id":"df7087c5_efba78be","line":3013,"range":{"start_line":3013,"start_character":24,"end_line":3013,"end_character":31},"updated":"2018-03-20 22:38:06.000000000","message":"required","commit_id":"f4fac22462c9a769df3a25ed32bf7fe0d5a3929d"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7c3c485a06279c3d7fb124bf1afff54cb09687d2","unresolved":false,"context_lines":[{"line_number":3019,"context_line":"    :param resources: A dict, keyed by resource class ID, of the amount"},{"line_number":3020,"context_line":"                      requested of that resource class."},{"line_number":3021,"context_line":"    :param required_traits: A map, keyed by trait string name, of required"},{"line_number":3022,"context_line":"                            trait internal IDs that each provider TREE must"},{"line_number":3023,"context_line":"                            COLLECTIVELY have associated with it"},{"line_number":3024,"context_line":"    :param member_of: An optional list of aggregate UUIDs. If provided, the"},{"line_number":3025,"context_line":"                      allocation_candidates returned will only be for resource"}],"source_content_type":"text/x-python","patch_set":1,"id":"df7087c5_afb480d2","line":3022,"range":{"start_line":3022,"start_character":66,"end_line":3022,"end_character":70},"updated":"2018-03-20 22:38:06.000000000","message":".","commit_id":"f4fac22462c9a769df3a25ed32bf7fe0d5a3929d"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7c3c485a06279c3d7fb124bf1afff54cb09687d2","unresolved":false,"context_lines":[{"line_number":3021,"context_line":"    :param required_traits: A map, keyed by trait string name, of required"},{"line_number":3022,"context_line":"                            trait internal IDs that each provider TREE must"},{"line_number":3023,"context_line":"                            COLLECTIVELY have associated with it"},{"line_number":3024,"context_line":"    :param member_of: An optional list of aggregate UUIDs. If provided, the"},{"line_number":3025,"context_line":"                      allocation_candidates returned will only be for resource"},{"line_number":3026,"context_line":"                      providers that are members of one or more of the supplied"},{"line_number":3027,"context_line":"                      aggregates."},{"line_number":3028,"context_line":"    \"\"\""},{"line_number":3029,"context_line":"    # We first grab the provider trees that have nodes that meet the request"},{"line_number":3030,"context_line":"    # for each resource class.  Once we have this information, we\u0027ll then do a"}],"source_content_type":"text/x-python","patch_set":1,"id":"df7087c5_2fc0702a","line":3027,"range":{"start_line":3024,"start_character":0,"end_line":3027,"end_character":33},"updated":"2018-03-20 22:38:06.000000000","message":"What\u0027s this used for?  Is the :note: about not involving sharing providers a lie?","commit_id":"f4fac22462c9a769df3a25ed32bf7fe0d5a3929d"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7c3c485a06279c3d7fb124bf1afff54cb09687d2","unresolved":false,"context_lines":[{"line_number":3070,"context_line":"    sel \u003d sa.select([rpt.c.id, rpt.c.root_provider_id])"},{"line_number":3071,"context_line":"    sel \u003d sel.select_from(rpt_to_rptt)"},{"line_number":3072,"context_line":"    sel \u003d sel.where("},{"line_number":3073,"context_line":"        sa.and_("},{"line_number":3074,"context_line":"            rpt.c.root_provider_id.in_(trees_with_inv),"},{"line_number":3075,"context_line":"            rptt.c.trait_id.in_(required_traits.values())))"},{"line_number":3076,"context_line":"    sel \u003d sel.group_by(rpt.c.root_provider_id)"},{"line_number":3077,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"},{"line_number":3078,"context_line":"    # need to GROUP BY the resource provider and ensure that the"}],"source_content_type":"text/x-python","patch_set":1,"id":"df7087c5_2f4ab0ab","line":3075,"range":{"start_line":3073,"start_character":0,"end_line":3075,"end_character":59},"updated":"2018-03-20 22:38:06.000000000","message":"Right, so here I think instead of saying\n\n AND root_provider_id IN (trees_with_inv)\n\n...you should be saying\n\n AND provider_id IN (provs_with_inv-except-grouped-for-each-tree)","commit_id":"f4fac22462c9a769df3a25ed32bf7fe0d5a3929d"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"232664e982eb1e7f8e15dee217c38d6e1e396d49","unresolved":false,"context_lines":[{"line_number":2803,"context_line":"@db_api.api_context_manager.reader"},{"line_number":2804,"context_line":"def _get_provider_ids_matching_all(ctx, resources, required_traits,"},{"line_number":2805,"context_line":"        member_of\u003dNone):"},{"line_number":2806,"context_line":"    \"\"\"Returns a list of resource provider internal IDs that have available"},{"line_number":2807,"context_line":"    inventory to satisfy all the supplied requests for resources."},{"line_number":2808,"context_line":""},{"line_number":2809,"context_line":"    :note: This function is used for scenarios that do NOT involve sharing"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_c746c850","line":2806,"range":{"start_line":2806,"start_character":7,"end_line":2806,"end_character":55},"updated":"2018-03-23 18:58:37.000000000","message":"Should be changed to reflect that you are now returning a list of 2-tuples of (rp, rp_root).","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"91d8250fa83f6f39ba099a417616f2c9ef684021","unresolved":false,"context_lines":[{"line_number":2803,"context_line":"@db_api.api_context_manager.reader"},{"line_number":2804,"context_line":"def _get_provider_ids_matching_all(ctx, resources, required_traits,"},{"line_number":2805,"context_line":"        member_of\u003dNone):"},{"line_number":2806,"context_line":"    \"\"\"Returns a list of resource provider internal IDs that have available"},{"line_number":2807,"context_line":"    inventory to satisfy all the supplied requests for resources."},{"line_number":2808,"context_line":""},{"line_number":2809,"context_line":"    :note: This function is used for scenarios that do NOT involve sharing"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_6b74d0fe","line":2806,"range":{"start_line":2806,"start_character":7,"end_line":2806,"end_character":55},"in_reply_to":"bf659307_c746c850","updated":"2018-03-29 19:12:03.000000000","message":"Done","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":25625,"name":"Tetsuro Nakamura","email":"tetsuro.nakamura.bc@hco.ntt.co.jp","username":"tetsuro0907"},"change_message_id":"50f5d543b378b8a44125d1b0963d37ec4e147a09","unresolved":false,"context_lines":[{"line_number":2970,"context_line":"    # ) AS usage"},{"line_number":2971,"context_line":"    #  ON inv.resource_provider_id \u003d usage.resource_provider_id"},{"line_number":2972,"context_line":"    # WHERE"},{"line_number":2973,"context_line":"    #  used + $AMOUNT \u003c\u003d ((total + reserved) * inv.allocation_ratio)"},{"line_number":2974,"context_line":"    #  AND inv.min_unit \u003c\u003d $AMOUNT"},{"line_number":2975,"context_line":"    #  AND inv.max_unit \u003e\u003d $AMOUNT"},{"line_number":2976,"context_line":"    #  AND $AMOUNT % inv.step_size \u003d\u003d 0"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_f3d94022","line":2973,"range":{"start_line":2973,"start_character":33,"end_line":2973,"end_character":34},"updated":"2018-03-25 00:41:33.000000000","message":"-, I think. Coud you review https://review.openstack.org/#/c/533195/?","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"91d8250fa83f6f39ba099a417616f2c9ef684021","unresolved":false,"context_lines":[{"line_number":2970,"context_line":"    # ) AS usage"},{"line_number":2971,"context_line":"    #  ON inv.resource_provider_id \u003d usage.resource_provider_id"},{"line_number":2972,"context_line":"    # WHERE"},{"line_number":2973,"context_line":"    #  used + $AMOUNT \u003c\u003d ((total + reserved) * inv.allocation_ratio)"},{"line_number":2974,"context_line":"    #  AND inv.min_unit \u003c\u003d $AMOUNT"},{"line_number":2975,"context_line":"    #  AND inv.max_unit \u003e\u003d $AMOUNT"},{"line_number":2976,"context_line":"    #  AND $AMOUNT % inv.step_size \u003d\u003d 0"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_8b4a84a9","line":2973,"range":{"start_line":2973,"start_character":33,"end_line":2973,"end_character":34},"in_reply_to":"bf659307_f3d94022","updated":"2018-03-29 19:12:03.000000000","message":"Done","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":25625,"name":"Tetsuro Nakamura","email":"tetsuro.nakamura.bc@hco.ntt.co.jp","username":"tetsuro0907"},"change_message_id":"50f5d543b378b8a44125d1b0963d37ec4e147a09","unresolved":false,"context_lines":[{"line_number":2985,"context_line":"    usage \u003d sa.alias(usage, name\u003d\"usage\")"},{"line_number":2986,"context_line":"    where_conds \u003d ["},{"line_number":2987,"context_line":"        sql.func.coalesce(usage.c.used, 0) + amount \u003c\u003d ("},{"line_number":2988,"context_line":"            (inv.c.total + inv.c.reserved) * inv.c.allocation_ratio),"},{"line_number":2989,"context_line":"        inv.c.min_unit \u003c\u003d amount,"},{"line_number":2990,"context_line":"        inv.c.max_unit \u003e\u003d amount,"},{"line_number":2991,"context_line":"        amount % inv.c.step_size \u003d\u003d 0,"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_d3e19cd2","line":2988,"range":{"start_line":2988,"start_character":25,"end_line":2988,"end_character":26},"updated":"2018-03-25 00:41:33.000000000","message":"-","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"232664e982eb1e7f8e15dee217c38d6e1e396d49","unresolved":false,"context_lines":[{"line_number":3050,"context_line":"            trees_with_inv \u003d rc_trees"},{"line_number":3051,"context_line":"            provs_with_inv \u003d rc_provs_with_inv"},{"line_number":3052,"context_line":""},{"line_number":3053,"context_line":"    # Go ahead and remove all (rp_id, root_id) tuples for providers in trees"},{"line_number":3054,"context_line":"    # that did not match all resources"},{"line_number":3055,"context_line":"    provs_with_inv \u003d set(p for p in provs_with_inv if p[1] in trees_with_inv)"},{"line_number":3056,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_e7f74cd4","line":3053,"range":{"start_line":3053,"start_character":6,"end_line":3053,"end_character":29},"updated":"2018-03-23 18:58:37.000000000","message":"This is confusing. You\u0027re not removing anything; you\u0027re simply selecting the providers that are in the matching trees.","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"91d8250fa83f6f39ba099a417616f2c9ef684021","unresolved":false,"context_lines":[{"line_number":3050,"context_line":"            trees_with_inv \u003d rc_trees"},{"line_number":3051,"context_line":"            provs_with_inv \u003d rc_provs_with_inv"},{"line_number":3052,"context_line":""},{"line_number":3053,"context_line":"    # Go ahead and remove all (rp_id, root_id) tuples for providers in trees"},{"line_number":3054,"context_line":"    # that did not match all resources"},{"line_number":3055,"context_line":"    provs_with_inv \u003d set(p for p in provs_with_inv if p[1] in trees_with_inv)"},{"line_number":3056,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_0bd434bc","line":3053,"range":{"start_line":3053,"start_character":6,"end_line":3053,"end_character":29},"in_reply_to":"bf659307_e7f74cd4","updated":"2018-03-29 19:12:03.000000000","message":"Done","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"ff97ca50ed49e7cc58b24d0a1a594236b7bd704c","unresolved":false,"context_lines":[{"line_number":3079,"context_line":"    #   ON rp.id \u003d rptt.resource_provider_id"},{"line_number":3080,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3081,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3082,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3083,"context_line":"    #   HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3084,"context_line":"    # ) AS trees_with_traits"},{"line_number":3085,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3086,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_42086327","line":3083,"range":{"start_line":3082,"start_character":8,"end_line":3083,"end_character":47},"updated":"2018-03-23 21:53:06.000000000","message":"Just to confirm my understanding, each group will have one instance of the root_provider_id for each instance of a required trait on any provider in that tree.\n\nIn other words, this still works when e.g. one provider has more than one of the required traits.","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"91d8250fa83f6f39ba099a417616f2c9ef684021","unresolved":false,"context_lines":[{"line_number":3079,"context_line":"    #   ON rp.id \u003d rptt.resource_provider_id"},{"line_number":3080,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3081,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3082,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3083,"context_line":"    #   HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3084,"context_line":"    # ) AS trees_with_traits"},{"line_number":3085,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3086,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_ab78a8c3","line":3083,"range":{"start_line":3082,"start_character":8,"end_line":3083,"end_character":47},"in_reply_to":"bf659307_42086327","updated":"2018-03-29 19:12:03.000000000","message":"That is correct. We\u0027re grouping by the root provider ID and there will be one element in each produced group for each trait matched. Therefore the HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS constraint will select only those groups where the tree contains all required traits.","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":25625,"name":"Tetsuro Nakamura","email":"tetsuro.nakamura.bc@hco.ntt.co.jp","username":"tetsuro0907"},"change_message_id":"8b6c672b9f8942afe464ac348762494e05057f08","unresolved":false,"context_lines":[{"line_number":2971,"context_line":"    # ) AS usage"},{"line_number":2972,"context_line":"    #  ON inv.resource_provider_id \u003d usage.resource_provider_id"},{"line_number":2973,"context_line":"    # WHERE"},{"line_number":2974,"context_line":"    #  used + $AMOUNT \u003c\u003d ((total + reserved) * inv.allocation_ratio)"},{"line_number":2975,"context_line":"    #  AND inv.min_unit \u003c\u003d $AMOUNT"},{"line_number":2976,"context_line":"    #  AND inv.max_unit \u003e\u003d $AMOUNT"},{"line_number":2977,"context_line":"    #  AND $AMOUNT % inv.step_size \u003d\u003d 0"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_1f90b249","line":2974,"range":{"start_line":2974,"start_character":33,"end_line":2974,"end_character":34},"updated":"2018-04-03 11:12:45.000000000","message":"Not done! My fix was only applied for merged codes.","commit_id":"5c0dce3334edb9c3077fc1158123af0befde9ec5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"095ce088b34d1319a63487e0e7e53e2692f52048","unresolved":false,"context_lines":[{"line_number":2971,"context_line":"    # ) AS usage"},{"line_number":2972,"context_line":"    #  ON inv.resource_provider_id \u003d usage.resource_provider_id"},{"line_number":2973,"context_line":"    # WHERE"},{"line_number":2974,"context_line":"    #  used + $AMOUNT \u003c\u003d ((total + reserved) * inv.allocation_ratio)"},{"line_number":2975,"context_line":"    #  AND inv.min_unit \u003c\u003d $AMOUNT"},{"line_number":2976,"context_line":"    #  AND inv.max_unit \u003e\u003d $AMOUNT"},{"line_number":2977,"context_line":"    #  AND $AMOUNT % inv.step_size \u003d\u003d 0"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_ddb4a638","line":2974,"range":{"start_line":2974,"start_character":33,"end_line":2974,"end_character":34},"in_reply_to":"bf659307_1f90b249","updated":"2018-04-12 14:45:48.000000000","message":"Done","commit_id":"5c0dce3334edb9c3077fc1158123af0befde9ec5"},{"author":{"_account_id":25625,"name":"Tetsuro Nakamura","email":"tetsuro.nakamura.bc@hco.ntt.co.jp","username":"tetsuro0907"},"change_message_id":"8b6c672b9f8942afe464ac348762494e05057f08","unresolved":false,"context_lines":[{"line_number":2986,"context_line":"    usage \u003d sa.alias(usage, name\u003d\"usage\")"},{"line_number":2987,"context_line":"    where_conds \u003d ["},{"line_number":2988,"context_line":"        sql.func.coalesce(usage.c.used, 0) + amount \u003c\u003d ("},{"line_number":2989,"context_line":"            (inv.c.total + inv.c.reserved) * inv.c.allocation_ratio),"},{"line_number":2990,"context_line":"        inv.c.min_unit \u003c\u003d amount,"},{"line_number":2991,"context_line":"        inv.c.max_unit \u003e\u003d amount,"},{"line_number":2992,"context_line":"        amount % inv.c.step_size \u003d\u003d 0,"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_bf97463a","line":2989,"range":{"start_line":2989,"start_character":25,"end_line":2989,"end_character":26},"updated":"2018-04-03 11:12:45.000000000","message":"ditto.","commit_id":"5c0dce3334edb9c3077fc1158123af0befde9ec5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"63d9c7838cbfcb4db25b381db510dfefe231b9a7","unresolved":false,"context_lines":[{"line_number":2986,"context_line":"    usage \u003d sa.alias(usage, name\u003d\"usage\")"},{"line_number":2987,"context_line":"    where_conds \u003d ["},{"line_number":2988,"context_line":"        sql.func.coalesce(usage.c.used, 0) + amount \u003c\u003d ("},{"line_number":2989,"context_line":"            (inv.c.total + inv.c.reserved) * inv.c.allocation_ratio),"},{"line_number":2990,"context_line":"        inv.c.min_unit \u003c\u003d amount,"},{"line_number":2991,"context_line":"        inv.c.max_unit \u003e\u003d amount,"},{"line_number":2992,"context_line":"        amount % inv.c.step_size \u003d\u003d 0,"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_b367734d","line":2989,"range":{"start_line":2989,"start_character":25,"end_line":2989,"end_character":26},"in_reply_to":"bf659307_bf97463a","updated":"2018-04-03 18:28:19.000000000","message":"oo","commit_id":"5c0dce3334edb9c3077fc1158123af0befde9ec5"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"d58a76e82c3608321170611b57217d582219297b","unresolved":false,"context_lines":[{"line_number":3011,"context_line":"    \"\"\"Returns a list of two-tuples (provider internal ID, root provider"},{"line_number":3012,"context_line":"    internal ID)s for provider trees where the nodes in the tree can"},{"line_number":3013,"context_line":"    INDIVIDUALLY satisfy the resource requests and the tree COLLECTIVELY is"},{"line_number":3014,"context_line":"    able to satisfy the require trait constraints."},{"line_number":3015,"context_line":""},{"line_number":3016,"context_line":"    :note: This function is used for scenarios that do NOT involve sharing"},{"line_number":3017,"context_line":"    providers AND where there are nested providers present in the deployment."}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_69e80eb2","line":3014,"updated":"2018-04-03 20:14:44.000000000","message":"I don\u0027t really understand what \"COLLECTIVELY\" means here?  Is it that all the rps have the trait? That either a node in the tree that satisfies the resources has the trait or one of its ancestors do? Something else?","commit_id":"5c0dce3334edb9c3077fc1158123af0befde9ec5"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"095ce088b34d1319a63487e0e7e53e2692f52048","unresolved":false,"context_lines":[{"line_number":3011,"context_line":"    \"\"\"Returns a list of two-tuples (provider internal ID, root provider"},{"line_number":3012,"context_line":"    internal ID)s for provider trees where the nodes in the tree can"},{"line_number":3013,"context_line":"    INDIVIDUALLY satisfy the resource requests and the tree COLLECTIVELY is"},{"line_number":3014,"context_line":"    able to satisfy the require trait constraints."},{"line_number":3015,"context_line":""},{"line_number":3016,"context_line":"    :note: This function is used for scenarios that do NOT involve sharing"},{"line_number":3017,"context_line":"    providers AND where there are nested providers present in the deployment."}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_fdb88a11","line":3014,"in_reply_to":"bf659307_69e80eb2","updated":"2018-04-12 14:45:48.000000000","message":"It means that the set of resource providers that can provide inventory for the request have all of the required traits. I will reword.","commit_id":"5c0dce3334edb9c3077fc1158123af0befde9ec5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"a3d171aad435a0a602e35f29bc49ce1672b9b618","unresolved":false,"context_lines":[{"line_number":3009,"context_line":"@db_api.api_context_manager.reader"},{"line_number":3010,"context_line":"def _get_trees_matching_all(ctx, resources, required_traits, member_of):"},{"line_number":3011,"context_line":"    \"\"\"Returns a list of two-tuples (provider internal ID, root provider"},{"line_number":3012,"context_line":"    internal ID)s for providers that satisfy the request for resources."},{"line_number":3013,"context_line":""},{"line_number":3014,"context_line":"    If traits are also required, this function only returns results where the"},{"line_number":3015,"context_line":"    set of providers within a tree that satisfy the resource request"}],"source_content_type":"text/x-python","patch_set":4,"id":"bf659307_ecdf7a63","line":3012,"range":{"start_line":3012,"start_character":16,"end_line":3012,"end_character":17},"updated":"2018-04-12 17:32:36.000000000","message":"strike","commit_id":"df8bf52adf34e6860dc2b22dbf4760bd80b24bc7"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"991c1637adb60d04e7f26f1c9b5e172099257f88","unresolved":false,"context_lines":[{"line_number":3009,"context_line":"@db_api.api_context_manager.reader"},{"line_number":3010,"context_line":"def _get_trees_matching_all(ctx, resources, required_traits, member_of):"},{"line_number":3011,"context_line":"    \"\"\"Returns a list of two-tuples (provider internal ID, root provider"},{"line_number":3012,"context_line":"    internal ID)s for providers that satisfy the request for resources."},{"line_number":3013,"context_line":""},{"line_number":3014,"context_line":"    If traits are also required, this function only returns results where the"},{"line_number":3015,"context_line":"    set of providers within a tree that satisfy the resource request"}],"source_content_type":"text/x-python","patch_set":4,"id":"9f6a8fd7_cb055e7c","line":3012,"range":{"start_line":3012,"start_character":16,"end_line":3012,"end_character":17},"in_reply_to":"bf659307_ecdf7a63","updated":"2018-04-16 18:09:12.000000000","message":"Done","commit_id":"df8bf52adf34e6860dc2b22dbf4760bd80b24bc7"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0218f451ee07dacbd6d6fb54bf43185052d10bc4","unresolved":false,"context_lines":[{"line_number":2970,"context_line":""},{"line_number":2971,"context_line":"@db_api.api_context_manager.reader"},{"line_number":2972,"context_line":"def _get_providers_with_resource(ctx, rc_id, amount):"},{"line_number":2973,"context_line":"    \"\"\"Returns the provider ID and root provider ID of providers that satisfy"},{"line_number":2974,"context_line":"    the request for a single resource class."},{"line_number":2975,"context_line":""},{"line_number":2976,"context_line":"    :param ctx: Session context to use"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_95db4a4d","line":2973,"range":{"start_line":2973,"start_character":15,"end_line":2973,"end_character":52},"updated":"2018-04-24 16:53:02.000000000","message":"a set of tuples of (provider internal ID, root provider internal ID)","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"7d48fbae99bf5efe0a442c8be0ee29d364df8e26","unresolved":false,"context_lines":[{"line_number":2970,"context_line":""},{"line_number":2971,"context_line":"@db_api.api_context_manager.reader"},{"line_number":2972,"context_line":"def _get_providers_with_resource(ctx, rc_id, amount):"},{"line_number":2973,"context_line":"    \"\"\"Returns the provider ID and root provider ID of providers that satisfy"},{"line_number":2974,"context_line":"    the request for a single resource class."},{"line_number":2975,"context_line":""},{"line_number":2976,"context_line":"    :param ctx: Session context to use"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_63eb4477","line":2973,"range":{"start_line":2973,"start_character":15,"end_line":2973,"end_character":52},"in_reply_to":"9f6a8fd7_95db4a4d","updated":"2018-04-25 19:26:55.000000000","message":"Done","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0218f451ee07dacbd6d6fb54bf43185052d10bc4","unresolved":false,"context_lines":[{"line_number":2990,"context_line":"    #  WHERE allocs.resource_class_id \u003d $RC_ID"},{"line_number":2991,"context_line":"    #  GROUP BY allocs.resource_provider_id"},{"line_number":2992,"context_line":"    # ) AS usage"},{"line_number":2993,"context_line":"    #  ON inv.resource_provider_id \u003d usage.resource_provider_id"},{"line_number":2994,"context_line":"    # WHERE"},{"line_number":2995,"context_line":"    #  used + $AMOUNT \u003c\u003d ((total - reserved) * inv.allocation_ratio)"},{"line_number":2996,"context_line":"    #  AND inv.min_unit \u003c\u003d $AMOUNT"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_156c1a9a","line":2993,"range":{"start_line":2993,"start_character":7,"end_line":2993,"end_character":63},"updated":"2018-04-24 16:53:02.000000000","message":"Note to self: we don\u0027t also need\n\n AND alloc.resource_provider_id \u003d\u003d usage.resource_provider_id\n\nbecause that commutes from the inv join condition.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0218f451ee07dacbd6d6fb54bf43185052d10bc4","unresolved":false,"context_lines":[{"line_number":3028,"context_line":""},{"line_number":3029,"context_line":""},{"line_number":3030,"context_line":"@db_api.api_context_manager.reader"},{"line_number":3031,"context_line":"def _get_trees_matching_all(ctx, resources, required_traits, member_of):"},{"line_number":3032,"context_line":"    \"\"\"Returns a list of two-tuples (provider internal ID, root provider"},{"line_number":3033,"context_line":"    internal ID) for providers that satisfy the request for resources."},{"line_number":3034,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_159dfa64","line":3031,"range":{"start_line":3031,"start_character":44,"end_line":3031,"end_character":59},"updated":"2018-04-24 16:53:02.000000000","message":"This now needs to be rebased to account for forbidden traits.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"7d48fbae99bf5efe0a442c8be0ee29d364df8e26","unresolved":false,"context_lines":[{"line_number":3028,"context_line":""},{"line_number":3029,"context_line":""},{"line_number":3030,"context_line":"@db_api.api_context_manager.reader"},{"line_number":3031,"context_line":"def _get_trees_matching_all(ctx, resources, required_traits, member_of):"},{"line_number":3032,"context_line":"    \"\"\"Returns a list of two-tuples (provider internal ID, root provider"},{"line_number":3033,"context_line":"    internal ID) for providers that satisfy the request for resources."},{"line_number":3034,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_03b4c87e","line":3031,"range":{"start_line":3031,"start_character":44,"end_line":3031,"end_character":59},"in_reply_to":"9f6a8fd7_159dfa64","updated":"2018-04-25 19:26:55.000000000","message":"Done","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"407ef4b14229d5d040a26c30e87a438359f2180c","unresolved":false,"context_lines":[{"line_number":3080,"context_line":"            # then we can short-circuit"},{"line_number":3081,"context_line":"            return []"},{"line_number":3082,"context_line":"        rc_trees \u003d set(p[1] for p in rc_provs_with_inv)"},{"line_number":3083,"context_line":"        if provs_with_inv:"},{"line_number":3084,"context_line":"            provs_with_inv |\u003d rc_provs_with_inv"},{"line_number":3085,"context_line":"            trees_with_inv \u0026\u003d rc_trees"},{"line_number":3086,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_757b1627","line":3083,"range":{"start_line":3083,"start_character":11,"end_line":3083,"end_character":25},"updated":"2018-04-24 16:43:59.000000000","message":"nit: since we are ORing this value, this isn\u0027t the important value to test on. The code could be written more simply as (adding gibi\u0027s short-circuit):\n\n  provs_with_inv |\u003d rc_provs_with_inv\n  if trees_with_inv:\n    trees_with_inv \u0026\u003d rc_trees\n    if not trees_with_inv:\n      return []\n  else:\n    trees_with_inv \u003d rc_trees","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"02b8fa27d6ac76dcf1897ad2dd944ce94cc26a58","unresolved":false,"context_lines":[{"line_number":3080,"context_line":"            # then we can short-circuit"},{"line_number":3081,"context_line":"            return []"},{"line_number":3082,"context_line":"        rc_trees \u003d set(p[1] for p in rc_provs_with_inv)"},{"line_number":3083,"context_line":"        if provs_with_inv:"},{"line_number":3084,"context_line":"            provs_with_inv |\u003d rc_provs_with_inv"},{"line_number":3085,"context_line":"            trees_with_inv \u0026\u003d rc_trees"},{"line_number":3086,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_e6df6263","line":3083,"range":{"start_line":3083,"start_character":11,"end_line":3083,"end_character":25},"in_reply_to":"9f6a8fd7_757b1627","updated":"2018-04-25 20:24:15.000000000","message":"Done","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b0c12201a8c7e823f22a8c639f386054bea107c","unresolved":false,"context_lines":[{"line_number":3080,"context_line":"            # then we can short-circuit"},{"line_number":3081,"context_line":"            return []"},{"line_number":3082,"context_line":"        rc_trees \u003d set(p[1] for p in rc_provs_with_inv)"},{"line_number":3083,"context_line":"        if provs_with_inv:"},{"line_number":3084,"context_line":"            provs_with_inv |\u003d rc_provs_with_inv"},{"line_number":3085,"context_line":"            trees_with_inv \u0026\u003d rc_trees"},{"line_number":3086,"context_line":"        else:"},{"line_number":3087,"context_line":"            trees_with_inv \u003d rc_trees"},{"line_number":3088,"context_line":"            provs_with_inv \u003d rc_provs_with_inv"},{"line_number":3089,"context_line":""},{"line_number":3090,"context_line":"    # Select only those tuples where there are providers for all requested"},{"line_number":3091,"context_line":"    # resource classes (trees_with_inv contains the root provider IDs of those"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_da37f44c","line":3088,"range":{"start_line":3083,"start_character":0,"end_line":3088,"end_character":46},"updated":"2018-04-20 14:19:53.000000000","message":"note to myself: we always hit the \u0027else\u0027 branch first (or return at L3081) so trees_with_inv is not empty when we hit L3085\n\nBTW, a possible optimization is that whenever trees_with_inv becomes empty after the first iteration we can return [] e.g.:\n\n        if provs_with_inv:\n            provs_with_inv |\u003d rc_provs_with_inv\n            trees_with_inv \u0026\u003d rc_trees\n            if not trees_with_inv:\n                return []\n        else:\n            trees_with_inv \u003d rc_trees\n            provs_with_inv \u003d rc_provs_with_inv","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b0c12201a8c7e823f22a8c639f386054bea107c","unresolved":false,"context_lines":[{"line_number":3103,"context_line":"        # environments, so just short-circuit and return"},{"line_number":3104,"context_line":"        return list(provs_with_inv)"},{"line_number":3105,"context_line":""},{"line_number":3106,"context_line":"    # We now want to restrict the returned providers to only those providers"},{"line_number":3107,"context_line":"    # trees that have all our required traits."},{"line_number":3108,"context_line":"    #"},{"line_number":3109,"context_line":"    # The SQL we want looks like this:"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_da5e1475","line":3106,"range":{"start_line":3106,"start_character":67,"end_line":3106,"end_character":76},"updated":"2018-04-20 14:19:53.000000000","message":"nit: provider","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b0c12201a8c7e823f22a8c639f386054bea107c","unresolved":false,"context_lines":[{"line_number":3116,"context_line":"    #   JOIN resource_provider_traits AS rptt"},{"line_number":3117,"context_line":"    #   ON rp.id \u003d rptt.resource_provider_id"},{"line_number":3118,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3119,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3120,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3121,"context_line":"    #   HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3122,"context_line":"    # ) AS trees_with_traits"},{"line_number":3123,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3124,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_f52f6b3c","line":3121,"range":{"start_line":3119,"start_character":0,"end_line":3121,"end_character":47},"updated":"2018-04-20 14:19:53.000000000","message":"I\u0027m still not an SQL expert so I could be on a totally  wrong track below:\n\nDoes this part of the query means that we need as many (rp_id, trait_id) pairs as many required trait we have in the request? \nDo we ensure that the count is not increased by a matching trait more than once when a given trait matches a second time match to a different rp_id in the same tree?","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"9968df8db39721b6785dad921fcb3fefc6b4cfa1","unresolved":false,"context_lines":[{"line_number":3116,"context_line":"    #   JOIN resource_provider_traits AS rptt"},{"line_number":3117,"context_line":"    #   ON rp.id \u003d rptt.resource_provider_id"},{"line_number":3118,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3119,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3120,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3121,"context_line":"    #   HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3122,"context_line":"    # ) AS trees_with_traits"},{"line_number":3123,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3124,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_824a72a9","line":3121,"range":{"start_line":3119,"start_character":0,"end_line":3121,"end_character":47},"in_reply_to":"9f6a8fd7_f52f6b3c","updated":"2018-04-20 16:05:26.000000000","message":"Note that we\u0027re grouping by the root_provider_id, so the subquery here will return the root_provider_ids where the providers in the tree collectively have all of the required traits.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b0c12201a8c7e823f22a8c639f386054bea107c","unresolved":false,"context_lines":[{"line_number":3136,"context_line":"            rptt.c.trait_id.in_(required_traits.values())))"},{"line_number":3137,"context_line":"    subq \u003d subq.group_by(rpt.c.root_provider_id)"},{"line_number":3138,"context_line":"    trees_with_traits \u003d sa.alias(subq, name\u003d\"trees_with_traits\")"},{"line_number":3139,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"},{"line_number":3140,"context_line":"    # need to GROUP BY the resource provider and ensure that the"},{"line_number":3141,"context_line":"    # COUNT(trait_id) is equal to the number of traits we are requiring"},{"line_number":3142,"context_line":"    num_traits \u003d len(required_traits)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_f90be520","line":3139,"range":{"start_line":3139,"start_character":3,"end_line":3139,"end_character":71},"updated":"2018-04-20 14:19:53.000000000","message":"Does it mean that a single RP needs to have ALL the traits from the request? What if we request two traits and each trait is satisfied by a different RP from the same tree (and both RP provide some resource as well)? I think that should satisfy your request.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"9968df8db39721b6785dad921fcb3fefc6b4cfa1","unresolved":false,"context_lines":[{"line_number":3136,"context_line":"            rptt.c.trait_id.in_(required_traits.values())))"},{"line_number":3137,"context_line":"    subq \u003d subq.group_by(rpt.c.root_provider_id)"},{"line_number":3138,"context_line":"    trees_with_traits \u003d sa.alias(subq, name\u003d\"trees_with_traits\")"},{"line_number":3139,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"},{"line_number":3140,"context_line":"    # need to GROUP BY the resource provider and ensure that the"},{"line_number":3141,"context_line":"    # COUNT(trait_id) is equal to the number of traits we are requiring"},{"line_number":3142,"context_line":"    num_traits \u003d len(required_traits)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_e2e7aeab","line":3139,"range":{"start_line":3139,"start_character":3,"end_line":3139,"end_character":71},"in_reply_to":"9f6a8fd7_f90be520","updated":"2018-04-20 16:05:26.000000000","message":"Yes, if two providers satisfy a different required trait and they are providing different resources, that is fine.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"7d48fbae99bf5efe0a442c8be0ee29d364df8e26","unresolved":false,"context_lines":[{"line_number":3141,"context_line":"    # COUNT(trait_id) is equal to the number of traits we are requiring"},{"line_number":3142,"context_line":"    num_traits \u003d len(required_traits)"},{"line_number":3143,"context_line":"    cond \u003d sa.func.count(rptt.c.trait_id) \u003d\u003d num_traits"},{"line_number":3144,"context_line":"    subq \u003d subq.having(cond)"},{"line_number":3145,"context_line":""},{"line_number":3146,"context_line":"    outer_rps \u003d sa.alias(_RP_TBL, name\u003d\"outer_rps\")"},{"line_number":3147,"context_line":"    outer_to_subq \u003d sa.join("}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_e32754c6","line":3144,"updated":"2018-04-25 19:26:55.000000000","message":"LOL. The problem is here... I placed the HAVING condition here but put it on the subq variable instead of the trees_with_traits variable (which is the aliased subquery that I actually join on below)...","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b0c12201a8c7e823f22a8c639f386054bea107c","unresolved":false,"context_lines":[{"line_number":3153,"context_line":"    res \u003d ctx.session.execute(sel).fetchall()"},{"line_number":3154,"context_line":""},{"line_number":3155,"context_line":"    # Return the providers where the providers have the available inventory"},{"line_number":3156,"context_line":"    # capacity and the TREE has the required traits"},{"line_number":3157,"context_line":"    return [(rp_id, root_id) for rp_id, root_id in res]"},{"line_number":3158,"context_line":""},{"line_number":3159,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_392f1d8f","line":3156,"range":{"start_line":3156,"start_character":15,"end_line":3156,"end_character":51},"updated":"2018-04-20 14:19:53.000000000","message":"OK that suggest that I might be wrong above.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2db1e0e93fccb0903b455a84d21c9b76eeacff12","unresolved":false,"context_lines":[{"line_number":3153,"context_line":"    res \u003d ctx.session.execute(sel).fetchall()"},{"line_number":3154,"context_line":""},{"line_number":3155,"context_line":"    # Return the providers where the providers have the available inventory"},{"line_number":3156,"context_line":"    # capacity and the TREE has the required traits"},{"line_number":3157,"context_line":"    return [(rp_id, root_id) for rp_id, root_id in res]"},{"line_number":3158,"context_line":""},{"line_number":3159,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_b1ee82ea","line":3156,"range":{"start_line":3156,"start_character":15,"end_line":3156,"end_character":51},"in_reply_to":"9f6a8fd7_02a2e24b","updated":"2018-04-25 20:27:54.000000000","message":"Done","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"a4c933820865cf1c83f7d705c5a5285e8dd45ada","unresolved":false,"context_lines":[{"line_number":3153,"context_line":"    res \u003d ctx.session.execute(sel).fetchall()"},{"line_number":3154,"context_line":""},{"line_number":3155,"context_line":"    # Return the providers where the providers have the available inventory"},{"line_number":3156,"context_line":"    # capacity and the TREE has the required traits"},{"line_number":3157,"context_line":"    return [(rp_id, root_id) for rp_id, root_id in res]"},{"line_number":3158,"context_line":""},{"line_number":3159,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_f13ddac3","line":3156,"range":{"start_line":3156,"start_character":15,"end_line":3156,"end_character":51},"in_reply_to":"9f6a8fd7_02a2e24b","updated":"2018-04-25 20:16:30.000000000","message":"Not done?","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"9968df8db39721b6785dad921fcb3fefc6b4cfa1","unresolved":false,"context_lines":[{"line_number":3153,"context_line":"    res \u003d ctx.session.execute(sel).fetchall()"},{"line_number":3154,"context_line":""},{"line_number":3155,"context_line":"    # Return the providers where the providers have the available inventory"},{"line_number":3156,"context_line":"    # capacity and the TREE has the required traits"},{"line_number":3157,"context_line":"    return [(rp_id, root_id) for rp_id, root_id in res]"},{"line_number":3158,"context_line":""},{"line_number":3159,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_02a2e24b","line":3156,"range":{"start_line":3156,"start_character":15,"end_line":3156,"end_character":51},"in_reply_to":"9f6a8fd7_392f1d8f","updated":"2018-04-20 16:05:26.000000000","message":"No, the wording here is incorrect. I\u0027ll change it to read \"and that set of providers (grouped by their tree) have all of the required traits\"","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"a4c933820865cf1c83f7d705c5a5285e8dd45ada","unresolved":false,"context_lines":[{"line_number":3154,"context_line":"    # parameter that would further winnow results to a set of resource provider"},{"line_number":3155,"context_line":"    # IDs (which we have here as we\u0027ve already looked up the providers that"},{"line_number":3156,"context_line":"    # have appropriate inventory capacity)"},{"line_number":3157,"context_line":"    if forbidden_traits:"},{"line_number":3158,"context_line":"        forbidden_rp_ids \u003d _get_provider_ids_having_any_trait("},{"line_number":3159,"context_line":"            ctx, forbidden_traits)"},{"line_number":3160,"context_line":"        subq \u003d subq.where(~rpt.c.id.in_(forbidden_rp_ids))"},{"line_number":3161,"context_line":""},{"line_number":3162,"context_line":"    subq \u003d subq.group_by(rpt.c.root_provider_id)"},{"line_number":3163,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_b148c25b","line":3160,"range":{"start_line":3157,"start_character":0,"end_line":3160,"end_character":58},"updated":"2018-04-25 20:16:30.000000000","message":"We don\u0027t have any tests that hit this code path now, right?","commit_id":"fc30fb203ab9d4f51eff3d2782183dec3a47c91a"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"02b8fa27d6ac76dcf1897ad2dd944ce94cc26a58","unresolved":false,"context_lines":[{"line_number":3154,"context_line":"    # parameter that would further winnow results to a set of resource provider"},{"line_number":3155,"context_line":"    # IDs (which we have here as we\u0027ve already looked up the providers that"},{"line_number":3156,"context_line":"    # have appropriate inventory capacity)"},{"line_number":3157,"context_line":"    if forbidden_traits:"},{"line_number":3158,"context_line":"        forbidden_rp_ids \u003d _get_provider_ids_having_any_trait("},{"line_number":3159,"context_line":"            ctx, forbidden_traits)"},{"line_number":3160,"context_line":"        subq \u003d subq.where(~rpt.c.id.in_(forbidden_rp_ids))"},{"line_number":3161,"context_line":""},{"line_number":3162,"context_line":"    subq \u003d subq.group_by(rpt.c.root_provider_id)"},{"line_number":3163,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_7139caa1","line":3160,"range":{"start_line":3157,"start_character":0,"end_line":3160,"end_character":58},"in_reply_to":"9f6a8fd7_b148c25b","updated":"2018-04-25 20:24:15.000000000","message":"Yes, I added one:\n\nhttps://review.openstack.org/#/c/554529/7/nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py","commit_id":"fc30fb203ab9d4f51eff3d2782183dec3a47c91a"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":2936,"context_line":"    # If \u0027member_of\u0027 has values join with the PlacementAggregates to"},{"line_number":2937,"context_line":"    # get those resource providers that are associated with any of the"},{"line_number":2938,"context_line":"    # list of aggregate uuids provided with \u0027member_of\u0027."},{"line_number":2939,"context_line":"    if member_of:"},{"line_number":2940,"context_line":"        member_join \u003d sa.join(join_chain, _RP_AGG_TBL,"},{"line_number":2941,"context_line":"                _RP_AGG_TBL.c.resource_provider_id \u003d\u003d rpt.c.id)"},{"line_number":2942,"context_line":"        agg_join \u003d sa.join(member_join, _AGG_TBL, sa.and_("}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_40870411","line":2939,"updated":"2018-04-26 12:48:31.000000000","message":"not entirely relevant to this patch, but test_allocation_candidates doesn\u0027t cover this block, just noting it for future reference.","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8ef7cdbc7f66772c13db37ef22063226ebd1b6a0","unresolved":false,"context_lines":[{"line_number":2936,"context_line":"    # If \u0027member_of\u0027 has values join with the PlacementAggregates to"},{"line_number":2937,"context_line":"    # get those resource providers that are associated with any of the"},{"line_number":2938,"context_line":"    # list of aggregate uuids provided with \u0027member_of\u0027."},{"line_number":2939,"context_line":"    if member_of:"},{"line_number":2940,"context_line":"        member_join \u003d sa.join(join_chain, _RP_AGG_TBL,"},{"line_number":2941,"context_line":"                _RP_AGG_TBL.c.resource_provider_id \u003d\u003d rpt.c.id)"},{"line_number":2942,"context_line":"        agg_join \u003d sa.join(member_join, _AGG_TBL, sa.and_("}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_ab9cc16a","line":2939,"in_reply_to":"9f6a8fd7_40870411","updated":"2018-04-26 13:31:13.000000000","message":"ack. I\u0027ll tack another patch on the end of the multi member_of patches (or maybe actually Tetsuro already added some func tests on this..)","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":3089,"context_line":"        if not rc_provs_with_inv:"},{"line_number":3090,"context_line":"            # If there\u0027s no providers that have one of the resource classes,"},{"line_number":3091,"context_line":"            # then we can short-circuit"},{"line_number":3092,"context_line":"            return []"},{"line_number":3093,"context_line":"        rc_trees \u003d set(p[1] for p in rc_provs_with_inv)"},{"line_number":3094,"context_line":"        provs_with_inv |\u003d rc_provs_with_inv"},{"line_number":3095,"context_line":"        if trees_with_inv:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_409ce45c","line":3092,"updated":"2018-04-26 12:48:31.000000000","message":"not hugely relevant but this short circuit doesn\u0027t get covered","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"55127957fc9ca01341d51fbf789c0c3df9647263","unresolved":false,"context_lines":[{"line_number":3089,"context_line":"        if not rc_provs_with_inv:"},{"line_number":3090,"context_line":"            # If there\u0027s no providers that have one of the resource classes,"},{"line_number":3091,"context_line":"            # then we can short-circuit"},{"line_number":3092,"context_line":"            return []"},{"line_number":3093,"context_line":"        rc_trees \u003d set(p[1] for p in rc_provs_with_inv)"},{"line_number":3094,"context_line":"        provs_with_inv |\u003d rc_provs_with_inv"},{"line_number":3095,"context_line":"        if trees_with_inv:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_ab7e01ad","line":3092,"in_reply_to":"9f6a8fd7_0b792d2e","updated":"2018-04-26 13:39:43.000000000","message":"I mean that when I switch the cover target in tox to run the functional tests and run tox -ecover -- test_allocation_candidates this line of code (and the two others) are never hit.","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8ef7cdbc7f66772c13db37ef22063226ebd1b6a0","unresolved":false,"context_lines":[{"line_number":3089,"context_line":"        if not rc_provs_with_inv:"},{"line_number":3090,"context_line":"            # If there\u0027s no providers that have one of the resource classes,"},{"line_number":3091,"context_line":"            # then we can short-circuit"},{"line_number":3092,"context_line":"            return []"},{"line_number":3093,"context_line":"        rc_trees \u003d set(p[1] for p in rc_provs_with_inv)"},{"line_number":3094,"context_line":"        provs_with_inv |\u003d rc_provs_with_inv"},{"line_number":3095,"context_line":"        if trees_with_inv:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_0b792d2e","line":3092,"in_reply_to":"9f6a8fd7_409ce45c","updated":"2018-04-26 13:31:13.000000000","message":"Doesn\u0027t get covered by tests or doesn\u0027t ever get hit?","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"10dd3f8d9f15bdc4e3c9bd45b987d2f956f42800","unresolved":false,"context_lines":[{"line_number":3089,"context_line":"        if not rc_provs_with_inv:"},{"line_number":3090,"context_line":"            # If there\u0027s no providers that have one of the resource classes,"},{"line_number":3091,"context_line":"            # then we can short-circuit"},{"line_number":3092,"context_line":"            return []"},{"line_number":3093,"context_line":"        rc_trees \u003d set(p[1] for p in rc_provs_with_inv)"},{"line_number":3094,"context_line":"        provs_with_inv |\u003d rc_provs_with_inv"},{"line_number":3095,"context_line":"        if trees_with_inv:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_393fa288","line":3092,"in_reply_to":"9f6a8fd7_ab7e01ad","updated":"2018-04-26 18:44:36.000000000","message":"ack. will address.","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":3095,"context_line":"        if trees_with_inv:"},{"line_number":3096,"context_line":"            trees_with_inv \u0026\u003d rc_trees"},{"line_number":3097,"context_line":"            if not trees_with_inv:"},{"line_number":3098,"context_line":"                return []"},{"line_number":3099,"context_line":"        else:"},{"line_number":3100,"context_line":"            trees_with_inv \u003d rc_trees"},{"line_number":3101,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_a0c38038","line":3098,"updated":"2018-04-26 12:48:31.000000000","message":"nor does this one get covered","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":3095,"context_line":"        if trees_with_inv:"},{"line_number":3096,"context_line":"            trees_with_inv \u0026\u003d rc_trees"},{"line_number":3097,"context_line":"            if not trees_with_inv:"},{"line_number":3098,"context_line":"                return []"},{"line_number":3099,"context_line":"        else:"},{"line_number":3100,"context_line":"            trees_with_inv \u003d rc_trees"},{"line_number":3101,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_5d2feba6","line":3098,"updated":"2018-04-26 12:48:31.000000000","message":"took me a while to decode this, but yeah","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8ef7cdbc7f66772c13db37ef22063226ebd1b6a0","unresolved":false,"context_lines":[{"line_number":3095,"context_line":"        if trees_with_inv:"},{"line_number":3096,"context_line":"            trees_with_inv \u0026\u003d rc_trees"},{"line_number":3097,"context_line":"            if not trees_with_inv:"},{"line_number":3098,"context_line":"                return []"},{"line_number":3099,"context_line":"        else:"},{"line_number":3100,"context_line":"            trees_with_inv \u003d rc_trees"},{"line_number":3101,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_ebce395a","line":3098,"in_reply_to":"9f6a8fd7_a0c38038","updated":"2018-04-26 13:31:13.000000000","message":"The above is what edleafe and gibi had asked be to rewrite the original code to. See patch 6:\n\nhttps://review.openstack.org/#/c/554529/6/nova/api/openstack/placement/objects/resource_provider.py@3077","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":3105,"context_line":"    provs_with_inv \u003d set(p for p in provs_with_inv if p[1] in trees_with_inv)"},{"line_number":3106,"context_line":""},{"line_number":3107,"context_line":"    if not provs_with_inv:"},{"line_number":3108,"context_line":"        return []"},{"line_number":3109,"context_line":""},{"line_number":3110,"context_line":"    # TODO(jaypipes): Handle filtering on member_of parameter"},{"line_number":3111,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_60db2821","line":3108,"updated":"2018-04-26 12:48:31.000000000","message":"or this one","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"10dd3f8d9f15bdc4e3c9bd45b987d2f956f42800","unresolved":false,"context_lines":[{"line_number":3105,"context_line":"    provs_with_inv \u003d set(p for p in provs_with_inv if p[1] in trees_with_inv)"},{"line_number":3106,"context_line":""},{"line_number":3107,"context_line":"    if not provs_with_inv:"},{"line_number":3108,"context_line":"        return []"},{"line_number":3109,"context_line":""},{"line_number":3110,"context_line":"    # TODO(jaypipes): Handle filtering on member_of parameter"},{"line_number":3111,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_5944d61b","line":3108,"in_reply_to":"9f6a8fd7_60db2821","updated":"2018-04-26 18:44:36.000000000","message":"Done","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":3107,"context_line":"    if not provs_with_inv:"},{"line_number":3108,"context_line":"        return []"},{"line_number":3109,"context_line":""},{"line_number":3110,"context_line":"    # TODO(jaypipes): Handle filtering on member_of parameter"},{"line_number":3111,"context_line":""},{"line_number":3112,"context_line":"    if not required_traits and not forbidden_traits:"},{"line_number":3113,"context_line":"        # If there were no traits required, there\u0027s no difference in how we"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_fd1fdf6d","line":3110,"updated":"2018-04-26 12:48:31.000000000","message":"How soon does this todo need to happen? We\u0027re not losing functionality are we? Presumably not, as we\u0027d have test booms, but just checking.","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"55127957fc9ca01341d51fbf789c0c3df9647263","unresolved":false,"context_lines":[{"line_number":3107,"context_line":"    if not provs_with_inv:"},{"line_number":3108,"context_line":"        return []"},{"line_number":3109,"context_line":""},{"line_number":3110,"context_line":"    # TODO(jaypipes): Handle filtering on member_of parameter"},{"line_number":3111,"context_line":""},{"line_number":3112,"context_line":"    if not required_traits and not forbidden_traits:"},{"line_number":3113,"context_line":"        # If there were no traits required, there\u0027s no difference in how we"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_2b443174","line":3110,"in_reply_to":"9f6a8fd7_6b1229b7","updated":"2018-04-26 13:39:43.000000000","message":"ack","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8ef7cdbc7f66772c13db37ef22063226ebd1b6a0","unresolved":false,"context_lines":[{"line_number":3107,"context_line":"    if not provs_with_inv:"},{"line_number":3108,"context_line":"        return []"},{"line_number":3109,"context_line":""},{"line_number":3110,"context_line":"    # TODO(jaypipes): Handle filtering on member_of parameter"},{"line_number":3111,"context_line":""},{"line_number":3112,"context_line":"    if not required_traits and not forbidden_traits:"},{"line_number":3113,"context_line":"        # If there were no traits required, there\u0027s no difference in how we"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_6b1229b7","line":3110,"in_reply_to":"9f6a8fd7_fd1fdf6d","updated":"2018-04-26 13:31:13.000000000","message":"Well, this _get_trees_matching_all() function isn\u0027t yet integrated into AllocationCandidates.get_by_requests(), so it would have to be done before that integration is done.\n\nI have that multi member_of patch series that I could do that in.","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"f72b30f4c1e88fb5ad40f87547ca234864dc8a93","unresolved":false,"context_lines":[{"line_number":3119,"context_line":"    # capacity and that set of providers (grouped by their tree) have all"},{"line_number":3120,"context_line":"    # of the required traits and none of the forbidden traits"},{"line_number":3121,"context_line":""},{"line_number":3122,"context_line":"    # We now want to restrict the returned providers to only those providers"},{"line_number":3123,"context_line":"    # trees that have all our required traits."},{"line_number":3124,"context_line":"    #"},{"line_number":3125,"context_line":"    # The SQL we want looks like this:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_ecaf2f29","line":3122,"range":{"start_line":3122,"start_character":67,"end_line":3122,"end_character":76},"updated":"2018-04-26 15:59:50.000000000","message":"nit: provider","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"10dd3f8d9f15bdc4e3c9bd45b987d2f956f42800","unresolved":false,"context_lines":[{"line_number":3119,"context_line":"    # capacity and that set of providers (grouped by their tree) have all"},{"line_number":3120,"context_line":"    # of the required traits and none of the forbidden traits"},{"line_number":3121,"context_line":""},{"line_number":3122,"context_line":"    # We now want to restrict the returned providers to only those providers"},{"line_number":3123,"context_line":"    # trees that have all our required traits."},{"line_number":3124,"context_line":"    #"},{"line_number":3125,"context_line":"    # The SQL we want looks like this:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_d9d546e7","line":3122,"range":{"start_line":3122,"start_character":67,"end_line":3122,"end_character":76},"in_reply_to":"9f6a8fd7_ecaf2f29","updated":"2018-04-26 18:44:36.000000000","message":"Done","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"f72b30f4c1e88fb5ad40f87547ca234864dc8a93","unresolved":false,"context_lines":[{"line_number":3131,"context_line":"    #   FROM resource_providers AS rp"},{"line_number":3132,"context_line":"    #   JOIN resource_provider_traits AS rptt"},{"line_number":3133,"context_line":"    #   ON rp.id \u003d rptt.resource_provider_id"},{"line_number":3134,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3135,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3136,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3137,"context_line":"    #   HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3138,"context_line":"    # ) AS trees_with_traits"},{"line_number":3139,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3140,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_00cfc757","line":3137,"range":{"start_line":3134,"start_character":8,"end_line":3137,"end_character":47},"updated":"2018-04-26 15:59:50.000000000","message":"I think that when a required trait matches more than once in a given RP tree this calculation breaks. See my test hack to show the strange behavior https://review.openstack.org/#/c/564541","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"09076132b068332d099ff1de5ffd6a1fdcb23f48","unresolved":false,"context_lines":[{"line_number":3131,"context_line":"    #   FROM resource_providers AS rp"},{"line_number":3132,"context_line":"    #   JOIN resource_provider_traits AS rptt"},{"line_number":3133,"context_line":"    #   ON rp.id \u003d rptt.resource_provider_id"},{"line_number":3134,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3135,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3136,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3137,"context_line":"    #   HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3138,"context_line":"    # ) AS trees_with_traits"},{"line_number":3139,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3140,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_63256dab","line":3137,"range":{"start_line":3134,"start_character":8,"end_line":3137,"end_character":47},"in_reply_to":"9f6a8fd7_00cfc757","updated":"2018-04-26 16:21:11.000000000","message":"If we use\n\n HAVING COUNT(DISTINCT *)\n\ndoes that fix it?","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"49f15cb66a91f6481aa788fe7576bb064d70f165","unresolved":false,"context_lines":[{"line_number":3131,"context_line":"    #   FROM resource_providers AS rp"},{"line_number":3132,"context_line":"    #   JOIN resource_provider_traits AS rptt"},{"line_number":3133,"context_line":"    #   ON rp.id \u003d rptt.resource_provider_id"},{"line_number":3134,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3135,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3136,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3137,"context_line":"    #   HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3138,"context_line":"    # ) AS trees_with_traits"},{"line_number":3139,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3140,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_d6a755a7","line":3137,"range":{"start_line":3134,"start_character":8,"end_line":3137,"end_character":47},"in_reply_to":"9f6a8fd7_63256dab","updated":"2018-04-26 17:39:52.000000000","message":"DISTINCT(trait) does.  See PS2 [1].\n\nNote that this same pattern can be found above at [2].\n\n[1] https://review.openstack.org/#/c/564541/\n[2] https://review.openstack.org/#/c/554529/8/nova/api/openstack/placement/objects/resource_provider.py@1612","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"10dd3f8d9f15bdc4e3c9bd45b987d2f956f42800","unresolved":false,"context_lines":[{"line_number":3131,"context_line":"    #   FROM resource_providers AS rp"},{"line_number":3132,"context_line":"    #   JOIN resource_provider_traits AS rptt"},{"line_number":3133,"context_line":"    #   ON rp.id \u003d rptt.resource_provider_id"},{"line_number":3134,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3135,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3136,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3137,"context_line":"    #   HAVING COUNT(*) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3138,"context_line":"    # ) AS trees_with_traits"},{"line_number":3139,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3140,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_79043a7f","line":3137,"range":{"start_line":3134,"start_character":8,"end_line":3137,"end_character":47},"in_reply_to":"9f6a8fd7_d6a755a7","updated":"2018-04-26 18:44:36.000000000","message":"Done","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":3153,"context_line":""},{"line_number":3154,"context_line":"    # Tack on an additional WHERE clause for the derived table if we\u0027ve got"},{"line_number":3155,"context_line":"    # forbidden traits in the mix."},{"line_number":3156,"context_line":"    # TODO(jaypipes): This approach is not efficient. We could potentially"},{"line_number":3157,"context_line":"    # change _get_provider_ids_having_any_trait() to accept an optional rp_ids"},{"line_number":3158,"context_line":"    # parameter that would further winnow results to a set of resource provider"},{"line_number":3159,"context_line":"    # IDs (which we have here as we\u0027ve already looked up the providers that"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_2020d09b","line":3156,"updated":"2018-04-26 12:48:31.000000000","message":"yeah, when I implemented the original version of forbidden I decided to do the quick and dirty first and then come back to it later with something nicer","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8ef7cdbc7f66772c13db37ef22063226ebd1b6a0","unresolved":false,"context_lines":[{"line_number":3153,"context_line":""},{"line_number":3154,"context_line":"    # Tack on an additional WHERE clause for the derived table if we\u0027ve got"},{"line_number":3155,"context_line":"    # forbidden traits in the mix."},{"line_number":3156,"context_line":"    # TODO(jaypipes): This approach is not efficient. We could potentially"},{"line_number":3157,"context_line":"    # change _get_provider_ids_having_any_trait() to accept an optional rp_ids"},{"line_number":3158,"context_line":"    # parameter that would further winnow results to a set of resource provider"},{"line_number":3159,"context_line":"    # IDs (which we have here as we\u0027ve already looked up the providers that"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_4b1165ac","line":3156,"in_reply_to":"9f6a8fd7_2020d09b","updated":"2018-04-26 13:31:13.000000000","message":"not a problem :) I wanted to re-use the existing code as much as I could.","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":3164,"context_line":"        subq \u003d subq.where(~rpt.c.id.in_(forbidden_rp_ids))"},{"line_number":3165,"context_line":""},{"line_number":3166,"context_line":"    subq \u003d subq.group_by(rpt.c.root_provider_id)"},{"line_number":3167,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"},{"line_number":3168,"context_line":"    # need to GROUP BY the resource provider and ensure that the"},{"line_number":3169,"context_line":"    # COUNT(trait_id) is equal to the number of traits we are requiring"},{"line_number":3170,"context_line":"    num_traits \u003d len(required_traits)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_c08c7481","line":3167,"updated":"2018-04-26 12:48:31.000000000","message":"When you say \"resource providers\" here, you mean \"tree of providers\", right. And thus what we\u0027re counting below is the number of traits exposed by each tree?\n\nBecause we don\u0027t require that a single resource provider have all the traits, but that the tree does (until granular comes into the picure).","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"10dd3f8d9f15bdc4e3c9bd45b987d2f956f42800","unresolved":false,"context_lines":[{"line_number":3164,"context_line":"        subq \u003d subq.where(~rpt.c.id.in_(forbidden_rp_ids))"},{"line_number":3165,"context_line":""},{"line_number":3166,"context_line":"    subq \u003d subq.group_by(rpt.c.root_provider_id)"},{"line_number":3167,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"},{"line_number":3168,"context_line":"    # need to GROUP BY the resource provider and ensure that the"},{"line_number":3169,"context_line":"    # COUNT(trait_id) is equal to the number of traits we are requiring"},{"line_number":3170,"context_line":"    num_traits \u003d len(required_traits)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_59037674","line":3167,"in_reply_to":"9f6a8fd7_ab2cc1ac","updated":"2018-04-26 18:44:36.000000000","message":"The unit/thing that has all the traits is the collection of resource providers within a tree that have already been determined to have the required resource capacity above.","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8ef7cdbc7f66772c13db37ef22063226ebd1b6a0","unresolved":false,"context_lines":[{"line_number":3164,"context_line":"        subq \u003d subq.where(~rpt.c.id.in_(forbidden_rp_ids))"},{"line_number":3165,"context_line":""},{"line_number":3166,"context_line":"    subq \u003d subq.group_by(rpt.c.root_provider_id)"},{"line_number":3167,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"},{"line_number":3168,"context_line":"    # need to GROUP BY the resource provider and ensure that the"},{"line_number":3169,"context_line":"    # COUNT(trait_id) is equal to the number of traits we are requiring"},{"line_number":3170,"context_line":"    num_traits \u003d len(required_traits)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_cb71f50e","line":3167,"in_reply_to":"9f6a8fd7_c08c7481","updated":"2018-04-26 13:31:13.000000000","message":"Well, no, not really. I\u0027m grabbing the individual resource providers from the outer table selection after finding the collection of resource providers that -- grouped by tree -- have all the traits required.\n\nWords. They are tough indeed... I\u0027m open to rewording suggestions, though!","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"55127957fc9ca01341d51fbf789c0c3df9647263","unresolved":false,"context_lines":[{"line_number":3164,"context_line":"        subq \u003d subq.where(~rpt.c.id.in_(forbidden_rp_ids))"},{"line_number":3165,"context_line":""},{"line_number":3166,"context_line":"    subq \u003d subq.group_by(rpt.c.root_provider_id)"},{"line_number":3167,"context_line":"    # Only get the resource providers that have ALL the required traits, so we"},{"line_number":3168,"context_line":"    # need to GROUP BY the resource provider and ensure that the"},{"line_number":3169,"context_line":"    # COUNT(trait_id) is equal to the number of traits we are requiring"},{"line_number":3170,"context_line":"    num_traits \u003d len(required_traits)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_ab2cc1ac","line":3167,"in_reply_to":"9f6a8fd7_cb71f50e","updated":"2018-04-26 13:39:43.000000000","message":"Hmmm. Yeah, I couldn\u0027t parse your additional explanation either.\n\nWhat is the unit/thing that has all the traits when that having_cond is happening. Upon what are those trait ids?","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":3170,"context_line":"    num_traits \u003d len(required_traits)"},{"line_number":3171,"context_line":"    having_cond \u003d sa.func.count(rptt.c.trait_id) \u003d\u003d num_traits"},{"line_number":3172,"context_line":"    subq \u003d subq.having(having_cond)"},{"line_number":3173,"context_line":"    trees_with_traits \u003d sa.alias(subq, name\u003d\"trees_with_traits\")"},{"line_number":3174,"context_line":""},{"line_number":3175,"context_line":"    outer_rps \u003d sa.alias(_RP_TBL, name\u003d\"outer_rps\")"},{"line_number":3176,"context_line":"    outer_to_subq \u003d sa.join("}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_604b285f","line":3173,"updated":"2018-04-26 12:48:31.000000000","message":"Out of curiosity: do you name the aliases because it helps with debugging or some other reason?","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"55127957fc9ca01341d51fbf789c0c3df9647263","unresolved":false,"context_lines":[{"line_number":3170,"context_line":"    num_traits \u003d len(required_traits)"},{"line_number":3171,"context_line":"    having_cond \u003d sa.func.count(rptt.c.trait_id) \u003d\u003d num_traits"},{"line_number":3172,"context_line":"    subq \u003d subq.having(having_cond)"},{"line_number":3173,"context_line":"    trees_with_traits \u003d sa.alias(subq, name\u003d\"trees_with_traits\")"},{"line_number":3174,"context_line":""},{"line_number":3175,"context_line":"    outer_rps \u003d sa.alias(_RP_TBL, name\u003d\"outer_rps\")"},{"line_number":3176,"context_line":"    outer_to_subq \u003d sa.join("}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_cb29f59b","line":3173,"in_reply_to":"9f6a8fd7_2bcf512a","updated":"2018-04-26 13:39:43.000000000","message":"coo","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8ef7cdbc7f66772c13db37ef22063226ebd1b6a0","unresolved":false,"context_lines":[{"line_number":3170,"context_line":"    num_traits \u003d len(required_traits)"},{"line_number":3171,"context_line":"    having_cond \u003d sa.func.count(rptt.c.trait_id) \u003d\u003d num_traits"},{"line_number":3172,"context_line":"    subq \u003d subq.having(having_cond)"},{"line_number":3173,"context_line":"    trees_with_traits \u003d sa.alias(subq, name\u003d\"trees_with_traits\")"},{"line_number":3174,"context_line":""},{"line_number":3175,"context_line":"    outer_rps \u003d sa.alias(_RP_TBL, name\u003d\"outer_rps\")"},{"line_number":3176,"context_line":"    outer_to_subq \u003d sa.join("}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_2bcf512a","line":3173,"in_reply_to":"9f6a8fd7_604b285f","updated":"2018-04-26 13:31:13.000000000","message":"Helps with debugging the actual SQL that is produced, yes. Without the alias, SQLAlchemy will auto-name the derived table as \"\u003cderived0\u003e\"","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"14f4b27ec479f309c42a1e0ef403e7d4bd54e77a","unresolved":false,"context_lines":[{"line_number":3134,"context_line":"    #   WHERE rp.id IN ($RP_IDS_WITH_INV)"},{"line_number":3135,"context_line":"    #   AND rptt.trait_id IN ($REQUIRED_TRAIT_IDS)"},{"line_number":3136,"context_line":"    #   GROUP BY rp.root_provider_id"},{"line_number":3137,"context_line":"    #   HAVING COUNT(DISTINCT rptt.trait_id) \u003d\u003d $NUM_REQUIRED_TRAITS"},{"line_number":3138,"context_line":"    # ) AS trees_with_traits"},{"line_number":3139,"context_line":"    #  ON outer_rp.root_provider_id \u003d trees_with_traits.root_provider_id"},{"line_number":3140,"context_line":"    rp_ids_with_inv \u003d set(p[0] for p in provs_with_inv)"}],"source_content_type":"text/x-python","patch_set":9,"id":"9f6a8fd7_32180f74","line":3137,"updated":"2018-04-27 10:49:53.000000000","message":"Ahh, I missed the fact that there is a second JOIN statement in this query but now this DISTINCT makes sense to me.","commit_id":"2f70faffc9821ef824c014a2a4c5e805827203de"}],"nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py":[{"author":{"_account_id":25625,"name":"Tetsuro Nakamura","email":"tetsuro.nakamura.bc@hco.ntt.co.jp","username":"tetsuro0907"},"change_message_id":"8b6c672b9f8942afe464ac348762494e05057f08","unresolved":false,"context_lines":[{"line_number":1601,"context_line":"                fields.ResourceClass.SRIOV_NET_VF): 1,"},{"line_number":1602,"context_line":"        }"},{"line_number":1603,"context_line":"        trees \u003d rp_obj._get_trees_matching_all(self.ctx, resources, {}, None)"},{"line_number":1604,"context_line":"        # trees is a list of two-tuples of (provider ID, root provider ID)"},{"line_number":1605,"context_line":"        tree_root_ids \u003d set(p[1] for p in trees)"},{"line_number":1606,"context_line":"        expect_root_ids \u003d self._get_root_ids_matching_names(cn_names)"},{"line_number":1607,"context_line":"        self.assertEqual(expect_root_ids, tree_root_ids)"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_5df7125a","line":1604,"range":{"start_line":1604,"start_character":8,"end_line":1604,"end_character":74},"updated":"2018-04-03 11:12:45.000000000","message":"yup, but I see only tests for \"root provider ID\"s.\nwhat do you expect for \"provider ID\"s?","commit_id":"5c0dce3334edb9c3077fc1158123af0befde9ec5"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"d58a76e82c3608321170611b57217d582219297b","unresolved":false,"context_lines":[{"line_number":1628,"context_line":"        self.assertEqual(expect_root_ids, set(tree_root_ids))"},{"line_number":1629,"context_line":""},{"line_number":1630,"context_line":"        # OK, now we\u0027re going to add a required trait to the mix. The only"},{"line_number":1631,"context_line":"        # provider that is decorate with the HW_NIC_OFFLOAD_GENEVE trait is the"},{"line_number":1632,"context_line":"        # second physical function on the third compute host. So we should only"},{"line_number":1633,"context_line":"        # get the third compute node back if we require that trait"},{"line_number":1634,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_6936ce53","line":1631,"range":{"start_line":1631,"start_character":27,"end_line":1631,"end_character":35},"updated":"2018-04-03 20:14:44.000000000","message":"decorated\n\n(I\u0027m aware of the irony here)","commit_id":"5c0dce3334edb9c3077fc1158123af0befde9ec5"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"8b0c12201a8c7e823f22a8c639f386054bea107c","unresolved":false,"context_lines":[{"line_number":230,"context_line":"        # We should get all the incl_* RPs"},{"line_number":231,"context_line":"        expected \u003d [incl_biginv_noalloc, incl_extra_full]"},{"line_number":232,"context_line":""},{"line_number":233,"context_line":"        self.assertEqual(set((rp.id, rp.id) for rp in expected), set(res))"},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"        # Now request that the providers must have a set of required traits and"},{"line_number":236,"context_line":"        # that this results in no results returned, since we haven\u0027t yet"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_d97b8178","line":233,"updated":"2018-04-20 14:19:53.000000000","message":"Note to myself: This is a non-nested case so root_rp_id and the matching rp_id is the same. This is why (rp.id, rp.id) is expected.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0218f451ee07dacbd6d6fb54bf43185052d10bc4","unresolved":false,"context_lines":[{"line_number":230,"context_line":"        # We should get all the incl_* RPs"},{"line_number":231,"context_line":"        expected \u003d [incl_biginv_noalloc, incl_extra_full]"},{"line_number":232,"context_line":""},{"line_number":233,"context_line":"        self.assertEqual(set((rp.id, rp.id) for rp in expected), set(res))"},{"line_number":234,"context_line":""},{"line_number":235,"context_line":"        # Now request that the providers must have a set of required traits and"},{"line_number":236,"context_line":"        # that this results in no results returned, since we haven\u0027t yet"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_1575faf9","line":233,"in_reply_to":"9f6a8fd7_d97b8178","updated":"2018-04-24 16:53:02.000000000","message":"Yeah, but a comment to that effect would be helpful.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"2e87d255d2f82f35fadf4aca3bc5aa755864c83d","unresolved":false,"context_lines":[{"line_number":1818,"context_line":"            cn_root_ids \u003d set([r[0] for r in conn.execute(sel)])"},{"line_number":1819,"context_line":"        return cn_root_ids"},{"line_number":1820,"context_line":""},{"line_number":1821,"context_line":"    def test_trees_matching_all(self):"},{"line_number":1822,"context_line":"        \"\"\"Creates a few provider trees having different inventories and"},{"line_number":1823,"context_line":"        allocations and tests the _get_trees_matching_all_resources() utility"},{"line_number":1824,"context_line":"        function to ensure that only the root provider IDs of matching provider"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_bc231bbd","line":1821,"updated":"2018-04-20 15:02:04.000000000","message":"Either I missing something or the implementation has a bug. I started playing with the test to see how the counting of the matching (rp_id, trait_id) pairs work in the SQL. \n\nSo I added another trait to the last request without adding that trait to any of the PRs and the test still passing. But I expected to fail due to the extra trait that non of the trees provide.\n\nSee the exact addition below.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"2e87d255d2f82f35fadf4aca3bc5aa755864c83d","unresolved":false,"context_lines":[{"line_number":1901,"context_line":"        # second physical function on the third compute host. So we should only"},{"line_number":1902,"context_line":"        # get the third compute node back if we require that trait"},{"line_number":1903,"context_line":""},{"line_number":1904,"context_line":"        geneve_t \u003d rp_obj.Trait.get_by_name("},{"line_number":1905,"context_line":"            self.ctx, os_traits.HW_NIC_OFFLOAD_GENEVE)"},{"line_number":1906,"context_line":"        # required_traits parameter is a dict of trait name to internal ID"},{"line_number":1907,"context_line":"        req_traits \u003d {"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_df06011d","line":1904,"updated":"2018-04-20 15:02:04.000000000","message":"--- a/nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py\n+++ b/nova/tests/functional/api/openstack/placement/db/test_allocation_candidates.py\n@@ -1903,9 +1903,11 @@ class AllocationCandidatesTestCase(ProviderDBBase):\n \n         geneve_t \u003d rp_obj.Trait.get_by_name(\n             self.ctx, os_traits.HW_NIC_OFFLOAD_GENEVE)\n+        cpu_t \u003d rp_obj.Trait.get_by_name(self.ctx, os_traits.HW_CPU_X86_AVX2)\n         # required_traits parameter is a dict of trait name to internal ID\n         req_traits \u003d {\n             geneve_t.name: geneve_t.id,\n+            cpu_t.name: cpu_t.id,\n         }\n         trees \u003d rp_obj._get_trees_matching_all(\n             self.ctx, resources, req_traits, None)","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"0218f451ee07dacbd6d6fb54bf43185052d10bc4","unresolved":false,"context_lines":[{"line_number":1901,"context_line":"        # second physical function on the third compute host. So we should only"},{"line_number":1902,"context_line":"        # get the third compute node back if we require that trait"},{"line_number":1903,"context_line":""},{"line_number":1904,"context_line":"        geneve_t \u003d rp_obj.Trait.get_by_name("},{"line_number":1905,"context_line":"            self.ctx, os_traits.HW_NIC_OFFLOAD_GENEVE)"},{"line_number":1906,"context_line":"        # required_traits parameter is a dict of trait name to internal ID"},{"line_number":1907,"context_line":"        req_traits \u003d {"}],"source_content_type":"text/x-python","patch_set":6,"id":"9f6a8fd7_15fc1a3c","line":1904,"in_reply_to":"9f6a8fd7_df06011d","updated":"2018-04-24 16:53:02.000000000","message":"So yeah, let\u0027s tack this on either at the end of this test case or as a new one and hack until it works.","commit_id":"2e3def330e55d12e9d07a21974da35e5f884ef43"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"02b8fa27d6ac76dcf1897ad2dd944ce94cc26a58","unresolved":false,"context_lines":[{"line_number":1952,"context_line":"        expect_root_ids \u003d self._get_root_ids_matching_names(cn_names)"},{"line_number":1953,"context_line":"        self.assertEqual(expect_root_ids, set(tree_root_ids))"},{"line_number":1954,"context_line":""},{"line_number":1955,"context_line":"        cn_names \u003d [\u0027cn3\u0027]"},{"line_number":1956,"context_line":"        expect_root_ids \u003d self._get_root_ids_matching_names(cn_names)"},{"line_number":1957,"context_line":"        self.assertEqual(expect_root_ids, set(tree_root_ids))"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_913c9e93","line":1957,"range":{"start_line":1955,"start_character":0,"end_line":1957,"end_character":61},"updated":"2018-04-25 20:24:15.000000000","message":"oops...","commit_id":"fc30fb203ab9d4f51eff3d2782183dec3a47c91a"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"ea8a95772cd5df2fe7bb329b49593ccfc4bd4a8f","unresolved":false,"context_lines":[{"line_number":1902,"context_line":"        self.assertEqual(expect_root_ids, set(tree_root_ids))"},{"line_number":1903,"context_line":""},{"line_number":1904,"context_line":"        # OK, now we\u0027re going to add a required trait to the mix. The only"},{"line_number":1905,"context_line":"        # provider that is decorate with the HW_NIC_OFFLOAD_GENEVE trait is the"},{"line_number":1906,"context_line":"        # second physical function on the third compute host. So we should only"},{"line_number":1907,"context_line":"        # get the third compute node back if we require that trait"},{"line_number":1908,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_e0dad877","line":1905,"range":{"start_line":1905,"start_character":27,"end_line":1905,"end_character":35},"updated":"2018-04-26 12:48:31.000000000","message":"decorated","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"10dd3f8d9f15bdc4e3c9bd45b987d2f956f42800","unresolved":false,"context_lines":[{"line_number":1902,"context_line":"        self.assertEqual(expect_root_ids, set(tree_root_ids))"},{"line_number":1903,"context_line":""},{"line_number":1904,"context_line":"        # OK, now we\u0027re going to add a required trait to the mix. The only"},{"line_number":1905,"context_line":"        # provider that is decorate with the HW_NIC_OFFLOAD_GENEVE trait is the"},{"line_number":1906,"context_line":"        # second physical function on the third compute host. So we should only"},{"line_number":1907,"context_line":"        # get the third compute node back if we require that trait"},{"line_number":1908,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_19cc1e60","line":1905,"range":{"start_line":1905,"start_character":27,"end_line":1905,"end_character":35},"in_reply_to":"9f6a8fd7_e0dad877","updated":"2018-04-26 18:44:36.000000000","message":"Done","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"751898ceb0637c62966ac2ae8089c3fbfa03e89d","unresolved":false,"context_lines":[{"line_number":1936,"context_line":"        self.assertEqual(0, len(tree_root_ids))"},{"line_number":1937,"context_line":""},{"line_number":1938,"context_line":"        # Finally, if we add the AVX2 trait as forbidden, not required, then we"},{"line_number":1939,"context_line":"        # should get back the original cn3"},{"line_number":1940,"context_line":"        req_traits \u003d {"},{"line_number":1941,"context_line":"            geneve_t.name: geneve_t.id,"},{"line_number":1942,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_1153ae6c","line":1939,"updated":"2018-04-25 20:46:05.000000000","message":"Okay, but also a case where a forbidden trait causes something to be *excluded*.  E.g. forbidding GENEVE and making sure CN3 does *not* come back.","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8ef7cdbc7f66772c13db37ef22063226ebd1b6a0","unresolved":false,"context_lines":[{"line_number":1936,"context_line":"        self.assertEqual(0, len(tree_root_ids))"},{"line_number":1937,"context_line":""},{"line_number":1938,"context_line":"        # Finally, if we add the AVX2 trait as forbidden, not required, then we"},{"line_number":1939,"context_line":"        # should get back the original cn3"},{"line_number":1940,"context_line":"        req_traits \u003d {"},{"line_number":1941,"context_line":"            geneve_t.name: geneve_t.id,"},{"line_number":1942,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_abe2819f","line":1939,"in_reply_to":"9f6a8fd7_1153ae6c","updated":"2018-04-26 13:31:13.000000000","message":"ack. I can add in a future patch?","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"879e3486dd52e43fdd433b621ff08d8e47f9c299","unresolved":false,"context_lines":[{"line_number":1936,"context_line":"        self.assertEqual(0, len(tree_root_ids))"},{"line_number":1937,"context_line":""},{"line_number":1938,"context_line":"        # Finally, if we add the AVX2 trait as forbidden, not required, then we"},{"line_number":1939,"context_line":"        # should get back the original cn3"},{"line_number":1940,"context_line":"        req_traits \u003d {"},{"line_number":1941,"context_line":"            geneve_t.name: geneve_t.id,"},{"line_number":1942,"context_line":"        }"}],"source_content_type":"text/x-python","patch_set":8,"id":"9f6a8fd7_598616de","line":1939,"in_reply_to":"9f6a8fd7_abe2819f","updated":"2018-04-26 18:48:09.000000000","message":"okay","commit_id":"ca91167fa950bb60787ea253d26a5ef759cfb9a4"}],"nova/tests/functional/db/test_allocation_candidates.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"ff97ca50ed49e7cc58b24d0a1a594236b7bd704c","unresolved":false,"context_lines":[{"line_number":1416,"context_line":"            )]"},{"line_number":1417,"context_line":"        )"},{"line_number":1418,"context_line":""},{"line_number":1419,"context_line":"        # TODO(jaypipes): This should be the following once nested providers"},{"line_number":1420,"context_line":"        # are handled by allocation candidates:"},{"line_number":1421,"context_line":"        # expected \u003d ["},{"line_number":1422,"context_line":"        #    [(\u0027cn\u0027, fields.ResourceClass.VCPU, 2),"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_e2465750","line":1419,"updated":"2018-03-23 21:53:06.000000000","message":"Uncomment the correct expected results so we\u0027ll know when the code is working.","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"91d8250fa83f6f39ba099a417616f2c9ef684021","unresolved":false,"context_lines":[{"line_number":1416,"context_line":"            )]"},{"line_number":1417,"context_line":"        )"},{"line_number":1418,"context_line":""},{"line_number":1419,"context_line":"        # TODO(jaypipes): This should be the following once nested providers"},{"line_number":1420,"context_line":"        # are handled by allocation candidates:"},{"line_number":1421,"context_line":"        # expected \u003d ["},{"line_number":1422,"context_line":"        #    [(\u0027cn\u0027, fields.ResourceClass.VCPU, 2),"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_6b57f027","line":1419,"in_reply_to":"bf659307_e2465750","updated":"2018-03-29 19:12:03.000000000","message":"I will when I link up AllocationCandidates.get_by_requests() with the _get_trees_matching_all() function (following patch).","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"ff97ca50ed49e7cc58b24d0a1a594236b7bd704c","unresolved":false,"context_lines":[{"line_number":1630,"context_line":"        # OK, now we\u0027re going to add a required trait to the mix. The only"},{"line_number":1631,"context_line":"        # provider that is decorate with the HW_NIC_OFFLOAD_GENEVE trait is the"},{"line_number":1632,"context_line":"        # second physical function on the third compute host. So we should only"},{"line_number":1633,"context_line":"        # get the third compute node back if we reuire that trait"},{"line_number":1634,"context_line":""},{"line_number":1635,"context_line":"        geneve_t \u003d rp_obj.Trait.get_by_name("},{"line_number":1636,"context_line":"            self.ctx, os_traits.HW_NIC_OFFLOAD_GENEVE)"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_9f99f420","line":1633,"range":{"start_line":1633,"start_character":48,"end_line":1633,"end_character":54},"updated":"2018-03-23 21:53:06.000000000","message":"require","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"91d8250fa83f6f39ba099a417616f2c9ef684021","unresolved":false,"context_lines":[{"line_number":1630,"context_line":"        # OK, now we\u0027re going to add a required trait to the mix. The only"},{"line_number":1631,"context_line":"        # provider that is decorate with the HW_NIC_OFFLOAD_GENEVE trait is the"},{"line_number":1632,"context_line":"        # second physical function on the third compute host. So we should only"},{"line_number":1633,"context_line":"        # get the third compute node back if we reuire that trait"},{"line_number":1634,"context_line":""},{"line_number":1635,"context_line":"        geneve_t \u003d rp_obj.Trait.get_by_name("},{"line_number":1636,"context_line":"            self.ctx, os_traits.HW_NIC_OFFLOAD_GENEVE)"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf659307_8b54c422","line":1633,"range":{"start_line":1633,"start_character":48,"end_line":1633,"end_character":54},"in_reply_to":"bf659307_9f99f420","updated":"2018-03-29 19:12:03.000000000","message":"Done","commit_id":"a12c0b70a450eb9f35a1165d64b339fc14f188e1"}]}
