)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b4dd26440134dad26c9bbcd43c7bda57166a302d","unresolved":false,"context_lines":[{"line_number":13,"context_line":"be able to enable this and get placement to pre-filter those hosts for"},{"line_number":14,"context_line":"them automatically."},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"This also allows making this filter advisory but not required, and supports"},{"line_number":17,"context_line":"multiple tenants per aggregate, unlike the original filter."},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"Related to blueprint placement-req-filter"},{"line_number":20,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":9,"id":"df7087c5_98c23f33","line":17,"range":{"start_line":16,"start_character":63,"end_line":17,"end_character":30},"updated":"2018-03-08 20:37:41.000000000","message":"This is something people using the existing filter want:\n\nhttp://lists.openstack.org/pipermail/openstack-operators/2018-March/014930.html\n\nAnd we have documentation about that filter, so can we somehow work this into the docs for that filter?\n\nhttps://docs.openstack.org/nova/latest/admin/configuration/schedulers.html#aggregatemultitenancyisolation\n\nSomething like, \"Starting in the 18.0.0 Rocky release, when using the FilterScheduler with Placement, it is now possible to \u003cgo into usage / configuration details\u003e\".","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"}],"nova/conf/scheduler.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b4dd26440134dad26c9bbcd43c7bda57166a302d","unresolved":false,"context_lines":[{"line_number":140,"context_line":"This option is only used by the FilterScheduler; if you use a different"},{"line_number":141,"context_line":"scheduler, this option has no effect."},{"line_number":142,"context_line":"\"\"\"),"},{"line_number":143,"context_line":"    cfg.BoolOpt(\"limit_tenants_to_placement_aggregate\","},{"line_number":144,"context_line":"                default\u003dFalse,"},{"line_number":145,"context_line":"                help\u003d\"\"\""},{"line_number":146,"context_line":"This setting causes the scheduler to look up a host aggregate with the"}],"source_content_type":"text/x-python","patch_set":9,"id":"df7087c5_78ac0b8c","line":143,"updated":"2018-03-08 20:37:41.000000000","message":"Release note for the new options?","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b4dd26440134dad26c9bbcd43c7bda57166a302d","unresolved":false,"context_lines":[{"line_number":160,"context_line":"                default\u003dFalse,"},{"line_number":161,"context_line":"                help\u003d\"\"\""},{"line_number":162,"context_line":"This setting, when limit_tenants_to_placement_aggregate\u003dTrue, will control"},{"line_number":163,"context_line":"whether or not a tenant with no aggregate affinity will be allowed schedule"},{"line_number":164,"context_line":"to any available node. If aggregates are used to limit some tenants but"},{"line_number":165,"context_line":"not all, then this should be False. If all tenants should be confined via"},{"line_number":166,"context_line":"aggregate, then this should be True to prevent them from receiving unrestricted"}],"source_content_type":"text/x-python","patch_set":9,"id":"df7087c5_b8d063f9","line":163,"range":{"start_line":163,"start_character":67,"end_line":163,"end_character":75},"updated":"2018-03-08 20:37:41.000000000","message":"to schedule","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ca9ed3848bc5e0fb6e8549ff1db24dc0fcd94a71","unresolved":false,"context_lines":[{"line_number":168,"context_line":"See also the placement_aggregate_required_for_tenants option."},{"line_number":169,"context_line":"\"\"\"),"},{"line_number":170,"context_line":"    cfg.BoolOpt(\"placement_aggregate_required_for_tenants\","},{"line_number":171,"context_line":"                default\u003dFalse,"},{"line_number":172,"context_line":"                help\u003d\"\"\""},{"line_number":173,"context_line":"This setting, when limit_tenants_to_placement_aggregate\u003dTrue, will control"},{"line_number":174,"context_line":"whether or not a tenant with no aggregate affinity will be allowed to schedule"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_f8d3f836","line":171,"updated":"2018-03-28 14:57:11.000000000","message":"Would this ever be False if limit_tenants_to_placement_aggregate\u003dTrue? I\u0027m a bit hung up on the two config options. With the existing filters, they are either enabled or they aren\u0027t, but if they are, they do a thing and if you don\u0027t want that thing, they aren\u0027t enabled. So could we simplify this and just combine the options?","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"01aae235d48465516a0658a3fc9510e4237e0bf0","unresolved":false,"context_lines":[{"line_number":168,"context_line":"See also the placement_aggregate_required_for_tenants option."},{"line_number":169,"context_line":"\"\"\"),"},{"line_number":170,"context_line":"    cfg.BoolOpt(\"placement_aggregate_required_for_tenants\","},{"line_number":171,"context_line":"                default\u003dFalse,"},{"line_number":172,"context_line":"                help\u003d\"\"\""},{"line_number":173,"context_line":"This setting, when limit_tenants_to_placement_aggregate\u003dTrue, will control"},{"line_number":174,"context_line":"whether or not a tenant with no aggregate affinity will be allowed to schedule"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_f73d3a8f","line":171,"in_reply_to":"bf659307_08ee97ec","updated":"2018-03-28 21:38:49.000000000","message":"OK so to confirm my understanding:\n\nlimit_tenants_to_placement_aggregate\u003dTrue means enable the filter.\n\nplacement_aggregate_required_for_tenants\u003dFalse means the filter is enabled but doesn\u0027t fail if a given tenant isn\u0027t in any aggregates.\n\nplacement_aggregate_required_for_tenants\u003dTrue means the filter is enabled and will fail if any tenant isn\u0027t an any aggregate.\n\nSo placement_aggregate_required_for_tenants\u003dTrue is a slight departure from how AggregateMultiTenancyIsolation works, and was maybe a CERN-specific use case, or at least that\u0027s how it came up?","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":168,"context_line":"See also the placement_aggregate_required_for_tenants option."},{"line_number":169,"context_line":"\"\"\"),"},{"line_number":170,"context_line":"    cfg.BoolOpt(\"placement_aggregate_required_for_tenants\","},{"line_number":171,"context_line":"                default\u003dFalse,"},{"line_number":172,"context_line":"                help\u003d\"\"\""},{"line_number":173,"context_line":"This setting, when limit_tenants_to_placement_aggregate\u003dTrue, will control"},{"line_number":174,"context_line":"whether or not a tenant with no aggregate affinity will be allowed to schedule"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_08ee97ec","line":171,"in_reply_to":"bf659307_f8d3f836","updated":"2018-03-28 18:21:38.000000000","message":"Yes. If I have one tenant that I want to corral into a single aggregate but not have to add every single tenant to an aggregate when I create them. Imagine spot instances or batch jobs from an automation tenant you want to keep to older hardware or something.\n\nYes, I could make this a tristate single config option if you care. It\u0027s simpler to reason about it IMHO if they\u0027re just flags. We have plenty of config options that are \"this is only active if foo\u003dtrue\".","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"2ae8b28c61888d8161b14a5a991c63acf6abebed","unresolved":false,"context_lines":[{"line_number":157,"context_line":"This setting causes the scheduler to look up a host aggregate with the"},{"line_number":158,"context_line":"metadata key of `filter_tenant_id` set to the project of an incoming"},{"line_number":159,"context_line":"request, and request results from placement be limited to that aggregate."},{"line_number":160,"context_line":"Multiple tenants may be added to a single aggregate by appending a serial"},{"line_number":161,"context_line":"number to the key, such as `filter_tenant_id:123`."},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"The matching aggregate UUID must be mirrored in placement for proper"},{"line_number":164,"context_line":"operation. If no host aggregate with the tenant id is found, or that"}],"source_content_type":"text/x-python","patch_set":27,"id":"bf659307_d02815e3","line":161,"range":{"start_line":160,"start_character":0,"end_line":161,"end_character":50},"updated":"2018-03-30 14:25:04.000000000","message":"that\u0027s very unusual with the existing filters where we only have one single key and a list of values but that sounds a reasonable approach based on your AggregateList.get_by_metadata_values() approach.","commit_id":"732e202e81142a8ea462a9ebcde9a7226a62a60b"}],"nova/scheduler/request_filter.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b4dd26440134dad26c9bbcd43c7bda57166a302d","unresolved":false,"context_lines":[{"line_number":38,"context_line":"    limit results accordingly."},{"line_number":39,"context_line":"    \"\"\""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    enabled \u003d CONF.scheduler.limit_tenants_to_placement_aggregate"},{"line_number":42,"context_line":"    agg_required \u003d CONF.scheduler.placement_aggregate_required_for_tenants"},{"line_number":43,"context_line":"    if not enabled:"},{"line_number":44,"context_line":"        return"}],"source_content_type":"text/x-python","patch_set":9,"id":"df7087c5_78488bcb","line":41,"range":{"start_line":41,"start_character":4,"end_line":41,"end_character":65},"updated":"2018-03-08 20:37:41.000000000","message":"So I guess this is how we do something like the enabled_filters option for post-placement (legacy) filters. Which means we\u0027ll likely have a boolean config option for each of these pre-placement request filters?\n\nI\u0027m not yet sure which I\u0027d prefer since I\u0027m used to the relative ease of the enabled_filters list option.","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"188101034b88d2a7514594e7cb5698b8b11e05c6","unresolved":false,"context_lines":[{"line_number":38,"context_line":"    limit results accordingly."},{"line_number":39,"context_line":"    \"\"\""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    enabled \u003d CONF.scheduler.limit_tenants_to_placement_aggregate"},{"line_number":42,"context_line":"    agg_required \u003d CONF.scheduler.placement_aggregate_required_for_tenants"},{"line_number":43,"context_line":"    if not enabled:"},{"line_number":44,"context_line":"        return"}],"source_content_type":"text/x-python","patch_set":9,"id":"bf659307_3800b767","line":41,"range":{"start_line":41,"start_character":4,"end_line":41,"end_character":65},"in_reply_to":"df7087c5_78488bcb","updated":"2018-03-27 14:23:23.000000000","message":"Until we have a few to get the pump primed, I was going to go with semantic flags instead, yeah.","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b4dd26440134dad26c9bbcd43c7bda57166a302d","unresolved":false,"context_lines":[{"line_number":58,"context_line":"        request_spec.requested_destination.aggregates \u003d ("},{"line_number":59,"context_line":"            aggregate_uuids_for_tenant)"},{"line_number":60,"context_line":"    elif agg_required:"},{"line_number":61,"context_line":"        LOG.warning(_(\u0027Tenant %(tenant)s has no available aggregates\u0027),"},{"line_number":62,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":63,"context_line":"        raise exception.RequestFilterFailed(\u0027No hosts available for tenant\u0027)"},{"line_number":64,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"df7087c5_981ebfb8","line":61,"range":{"start_line":61,"start_character":12,"end_line":61,"end_character":19},"updated":"2018-03-08 20:37:41.000000000","message":"Why a warning?","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b4dd26440134dad26c9bbcd43c7bda57166a302d","unresolved":false,"context_lines":[{"line_number":58,"context_line":"        request_spec.requested_destination.aggregates \u003d ("},{"line_number":59,"context_line":"            aggregate_uuids_for_tenant)"},{"line_number":60,"context_line":"    elif agg_required:"},{"line_number":61,"context_line":"        LOG.warning(_(\u0027Tenant %(tenant)s has no available aggregates\u0027),"},{"line_number":62,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":63,"context_line":"        raise exception.RequestFilterFailed(\u0027No hosts available for tenant\u0027)"},{"line_number":64,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"df7087c5_78216bfb","line":61,"range":{"start_line":61,"start_character":20,"end_line":61,"end_character":21},"updated":"2018-03-08 20:37:41.000000000","message":"don\u0027t need to mark this for translation","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"188101034b88d2a7514594e7cb5698b8b11e05c6","unresolved":false,"context_lines":[{"line_number":58,"context_line":"        request_spec.requested_destination.aggregates \u003d ("},{"line_number":59,"context_line":"            aggregate_uuids_for_tenant)"},{"line_number":60,"context_line":"    elif agg_required:"},{"line_number":61,"context_line":"        LOG.warning(_(\u0027Tenant %(tenant)s has no available aggregates\u0027),"},{"line_number":62,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":63,"context_line":"        raise exception.RequestFilterFailed(\u0027No hosts available for tenant\u0027)"},{"line_number":64,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"bf659307_d8ee5bb3","line":61,"range":{"start_line":61,"start_character":12,"end_line":61,"end_character":19},"in_reply_to":"df7087c5_981ebfb8","updated":"2018-03-27 14:23:23.000000000","message":"Because we\u0027re about to fail a boot that can\u0027t work because the operator has opted into per-tenant aggregates, but hasn\u0027t given this tenant access to any aggregates.","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b4dd26440134dad26c9bbcd43c7bda57166a302d","unresolved":false,"context_lines":[{"line_number":60,"context_line":"    elif agg_required:"},{"line_number":61,"context_line":"        LOG.warning(_(\u0027Tenant %(tenant)s has no available aggregates\u0027),"},{"line_number":62,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":63,"context_line":"        raise exception.RequestFilterFailed(\u0027No hosts available for tenant\u0027)"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"ALL_REQUEST_FILTERS \u003d ["}],"source_content_type":"text/x-python","patch_set":9,"id":"df7087c5_f80d7b90","line":63,"range":{"start_line":63,"start_character":68,"end_line":63,"end_character":74},"updated":"2018-03-08 20:37:41.000000000","message":"put the tenant id in the message","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"188101034b88d2a7514594e7cb5698b8b11e05c6","unresolved":false,"context_lines":[{"line_number":60,"context_line":"    elif agg_required:"},{"line_number":61,"context_line":"        LOG.warning(_(\u0027Tenant %(tenant)s has no available aggregates\u0027),"},{"line_number":62,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":63,"context_line":"        raise exception.RequestFilterFailed(\u0027No hosts available for tenant\u0027)"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"ALL_REQUEST_FILTERS \u003d ["}],"source_content_type":"text/x-python","patch_set":9,"id":"bf659307_f83ebf27","line":63,"range":{"start_line":63,"start_character":68,"end_line":63,"end_character":74},"in_reply_to":"df7087c5_f80d7b90","updated":"2018-03-27 14:23:23.000000000","message":"This is the equivalent of NoValidHosts which doesn\u0027t have the tenant id because it\u0027s exposed to the user. Do you really want me to add that? I think we\u0027ll get enough context logged when that happens for the operator to find it.","commit_id":"52958b3aec89a7cede82472b8a99ce78dc403dac"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4bab3d6f96c053b275527fb0441b37d34b439c98","unresolved":false,"context_lines":[{"line_number":38,"context_line":"    limit results accordingly."},{"line_number":39,"context_line":"    \"\"\""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    enabled \u003d CONF.scheduler.limit_tenants_to_placement_aggregate"},{"line_number":42,"context_line":"    agg_required \u003d CONF.scheduler.placement_aggregate_required_for_tenants"},{"line_number":43,"context_line":"    if not enabled:"},{"line_number":44,"context_line":"        return"}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_358247ca","line":41,"range":{"start_line":41,"start_character":4,"end_line":41,"end_character":11},"updated":"2018-03-23 23:38:28.000000000","message":"This var not used for anything else; could just use the value in the conditional on L43.","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4bab3d6f96c053b275527fb0441b37d34b439c98","unresolved":false,"context_lines":[{"line_number":39,"context_line":"    \"\"\""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    enabled \u003d CONF.scheduler.limit_tenants_to_placement_aggregate"},{"line_number":42,"context_line":"    agg_required \u003d CONF.scheduler.placement_aggregate_required_for_tenants"},{"line_number":43,"context_line":"    if not enabled:"},{"line_number":44,"context_line":"        return"},{"line_number":45,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_15694324","line":42,"range":{"start_line":42,"start_character":4,"end_line":42,"end_character":16},"updated":"2018-03-23 23:38:28.000000000","message":"ditto.\n\nBut I think I get that this is a style thing: pull the conf values up front.","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"188101034b88d2a7514594e7cb5698b8b11e05c6","unresolved":false,"context_lines":[{"line_number":39,"context_line":"    \"\"\""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    enabled \u003d CONF.scheduler.limit_tenants_to_placement_aggregate"},{"line_number":42,"context_line":"    agg_required \u003d CONF.scheduler.placement_aggregate_required_for_tenants"},{"line_number":43,"context_line":"    if not enabled:"},{"line_number":44,"context_line":"        return"},{"line_number":45,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_b8c92779","line":42,"range":{"start_line":42,"start_character":4,"end_line":42,"end_character":16},"in_reply_to":"bf659307_15694324","updated":"2018-03-27 14:23:23.000000000","message":"This one is because I can\u0027t fit the whole CONF invocation where I want to check it. The same was true for enabled in a previous incarnation, but I also think that variables are free and it reads better if you do this kind of thing where appropriate.","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4bab3d6f96c053b275527fb0441b37d34b439c98","unresolved":false,"context_lines":[{"line_number":50,"context_line":"        for key, value in agg.metadata.items():"},{"line_number":51,"context_line":"            if _allowed_tenant(key, value, request_spec.project_id):"},{"line_number":52,"context_line":"                aggregate_uuids_for_tenant.append(agg.uuid)"},{"line_number":53,"context_line":"                break"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    if aggregate_uuids_for_tenant:"},{"line_number":56,"context_line":"        if (\u0027requested_destination\u0027 not in request_spec or"}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_355b2788","line":53,"range":{"start_line":53,"start_character":16,"end_line":53,"end_character":21},"updated":"2018-03-23 23:38:28.000000000","message":"eh?  So we\u0027ll only ever add one?  Can there only be one?","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"188101034b88d2a7514594e7cb5698b8b11e05c6","unresolved":false,"context_lines":[{"line_number":50,"context_line":"        for key, value in agg.metadata.items():"},{"line_number":51,"context_line":"            if _allowed_tenant(key, value, request_spec.project_id):"},{"line_number":52,"context_line":"                aggregate_uuids_for_tenant.append(agg.uuid)"},{"line_number":53,"context_line":"                break"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    if aggregate_uuids_for_tenant:"},{"line_number":56,"context_line":"        if (\u0027requested_destination\u0027 not in request_spec or"}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_d8997b79","line":53,"range":{"start_line":53,"start_character":16,"end_line":53,"end_character":21},"in_reply_to":"bf659307_355b2788","updated":"2018-03-27 14:23:23.000000000","message":"Within a given aggregate, it only matters if we find ourselves once yeah. We\u0027ll continue looking for other aggregates that match, but we only need to process a given aggregate until we find ourselves.","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4bab3d6f96c053b275527fb0441b37d34b439c98","unresolved":false,"context_lines":[{"line_number":59,"context_line":"        destination \u003d request_spec.requested_destination"},{"line_number":60,"context_line":"        destination.require_aggregates(aggregate_uuids_for_tenant)"},{"line_number":61,"context_line":"    elif agg_required:"},{"line_number":62,"context_line":"        LOG.warning(_(\u0027Tenant %(tenant)s has no available aggregates\u0027),"},{"line_number":63,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":64,"context_line":"        raise exception.RequestFilterFailed(\u0027No hosts available for tenant\u0027)"},{"line_number":65,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_b54e57bf","line":62,"range":{"start_line":62,"start_character":20,"end_line":62,"end_character":21},"updated":"2018-03-23 23:38:28.000000000","message":"no log translation","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4bab3d6f96c053b275527fb0441b37d34b439c98","unresolved":false,"context_lines":[{"line_number":61,"context_line":"    elif agg_required:"},{"line_number":62,"context_line":"        LOG.warning(_(\u0027Tenant %(tenant)s has no available aggregates\u0027),"},{"line_number":63,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":64,"context_line":"        raise exception.RequestFilterFailed(\u0027No hosts available for tenant\u0027)"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"ALL_REQUEST_FILTERS \u003d ["}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_75c67f19","line":64,"updated":"2018-03-23 23:38:28.000000000","message":"But translation in exceptions?","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ca9ed3848bc5e0fb6e8549ff1db24dc0fcd94a71","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    aggregate_uuids_for_tenant \u003d []"},{"line_number":49,"context_line":"    for agg in aggregates:"},{"line_number":50,"context_line":"        for key, value in agg.metadata.items():"},{"line_number":51,"context_line":"            if _allowed_tenant(key, value, request_spec.project_id):"},{"line_number":52,"context_line":"                aggregate_uuids_for_tenant.append(agg.uuid)"},{"line_number":53,"context_line":"                break"},{"line_number":54,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_d8ae3497","line":51,"range":{"start_line":51,"start_character":15,"end_line":51,"end_character":67},"updated":"2018-03-28 14:57:11.000000000","message":"Couldn\u0027t this simply be: key.startswith(TENANT_METADATA_KEY)\n\nBecause if AggregateList.get_by_metadata is getting all aggregates where the value is the project_id, then we know the values are always going to match, so it\u0027s just the key we care about, and _allowed_tenant doesn\u0027t really need to be used to compare the values.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    aggregate_uuids_for_tenant \u003d []"},{"line_number":49,"context_line":"    for agg in aggregates:"},{"line_number":50,"context_line":"        for key, value in agg.metadata.items():"},{"line_number":51,"context_line":"            if _allowed_tenant(key, value, request_spec.project_id):"},{"line_number":52,"context_line":"                aggregate_uuids_for_tenant.append(agg.uuid)"},{"line_number":53,"context_line":"                break"},{"line_number":54,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_28c4bb5e","line":51,"range":{"start_line":51,"start_character":15,"end_line":51,"end_character":67},"in_reply_to":"bf659307_d8ae3497","updated":"2018-03-28 18:21:38.000000000","message":"Yeah I guess. This was a little different earlier and I probably just didn\u0027t reduce this. Not sure it matters, but.. :)","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ca9ed3848bc5e0fb6e8549ff1db24dc0fcd94a71","unresolved":false,"context_lines":[{"line_number":49,"context_line":"    for agg in aggregates:"},{"line_number":50,"context_line":"        for key, value in agg.metadata.items():"},{"line_number":51,"context_line":"            if _allowed_tenant(key, value, request_spec.project_id):"},{"line_number":52,"context_line":"                aggregate_uuids_for_tenant.append(agg.uuid)"},{"line_number":53,"context_line":"                break"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    if aggregate_uuids_for_tenant:"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_f88a1819","line":52,"range":{"start_line":52,"start_character":16,"end_line":52,"end_character":59},"updated":"2018-03-28 14:57:11.000000000","message":"Can we get duplicates in this? Use a set?","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":49,"context_line":"    for agg in aggregates:"},{"line_number":50,"context_line":"        for key, value in agg.metadata.items():"},{"line_number":51,"context_line":"            if _allowed_tenant(key, value, request_spec.project_id):"},{"line_number":52,"context_line":"                aggregate_uuids_for_tenant.append(agg.uuid)"},{"line_number":53,"context_line":"                break"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    if aggregate_uuids_for_tenant:"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_c88bbf1c","line":52,"range":{"start_line":52,"start_character":16,"end_line":52,"end_character":59},"in_reply_to":"bf659307_f88a1819","updated":"2018-03-28 18:21:38.000000000","message":"Sure.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"de92f17c41a717b1cc3bf084d23b573779a09dd4","unresolved":false,"context_lines":[{"line_number":61,"context_line":"    elif agg_required:"},{"line_number":62,"context_line":"        LOG.warning(\u0027Tenant %(tenant)s has no available aggregates\u0027,"},{"line_number":63,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":64,"context_line":"        raise exception.RequestFilterFailed(_(\u0027No hosts available for tenant\u0027))"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"ALL_REQUEST_FILTERS \u003d ["}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_780e083c","line":64,"range":{"start_line":64,"start_character":24,"end_line":64,"end_character":43},"updated":"2018-03-28 15:11:54.000000000","message":"This exception takes a reason kwarg, did you intend to overwrite the message?\n\nhttps://review.openstack.org/#/c/544730/15/nova/exception.py@1400","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":61,"context_line":"    elif agg_required:"},{"line_number":62,"context_line":"        LOG.warning(\u0027Tenant %(tenant)s has no available aggregates\u0027,"},{"line_number":63,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"},{"line_number":64,"context_line":"        raise exception.RequestFilterFailed(_(\u0027No hosts available for tenant\u0027))"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"ALL_REQUEST_FILTERS \u003d ["}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_28991b78","line":64,"range":{"start_line":64,"start_character":24,"end_line":64,"end_character":43},"in_reply_to":"bf659307_780e083c","updated":"2018-03-28 18:21:38.000000000","message":"No.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"86cdcbf2a35e4a41dbfcc40f9029390e4fcec4ce","unresolved":false,"context_lines":[{"line_number":52,"context_line":"                request_spec.requested_destination is None):"},{"line_number":53,"context_line":"            request_spec.requested_destination \u003d objects.Destination()"},{"line_number":54,"context_line":"        destination \u003d request_spec.requested_destination"},{"line_number":55,"context_line":"        destination.require_aggregates(aggregate_uuids_for_tenant)"},{"line_number":56,"context_line":"    elif agg_required:"},{"line_number":57,"context_line":"        LOG.warning(\u0027Tenant %(tenant)s has no available aggregates\u0027,"},{"line_number":58,"context_line":"                    {\u0027tenant\u0027: request_spec.project_id})"}],"source_content_type":"text/x-python","patch_set":26,"id":"bf659307_9ce745ad","line":55,"range":{"start_line":55,"start_character":39,"end_line":55,"end_character":65},"updated":"2018-03-28 21:17:47.000000000","message":"would prefer sorted()","commit_id":"60ea5bf4c32e867c41cd80c4767f0877b9365291"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"2ae8b28c61888d8161b14a5a991c63acf6abebed","unresolved":false,"context_lines":[{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    aggregates \u003d objects.AggregateList.get_by_metadata("},{"line_number":42,"context_line":"        ctxt, value\u003drequest_spec.project_id)"},{"line_number":43,"context_line":"    aggregate_uuids_for_tenant \u003d set([])"},{"line_number":44,"context_line":"    for agg in aggregates:"},{"line_number":45,"context_line":"        for key, value in agg.metadata.items():"},{"line_number":46,"context_line":"            if key.startswith(TENANT_METADATA_KEY):"},{"line_number":47,"context_line":"                aggregate_uuids_for_tenant.add(agg.uuid)"},{"line_number":48,"context_line":"                break"},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"    if aggregate_uuids_for_tenant:"},{"line_number":51,"context_line":"        if (\u0027requested_destination\u0027 not in request_spec or"}],"source_content_type":"text/x-python","patch_set":27,"id":"bf659307_70e349da","line":48,"range":{"start_line":43,"start_character":0,"end_line":48,"end_character":21},"updated":"2018-03-30 14:25:04.000000000","message":"we could eventually move that to some place like https://github.com/openstack/nova/blob/master/nova/scheduler/filters/utils.py (with the slight difference that we don\u0027t have a HostState object here) but that\u0027s a nit.","commit_id":"732e202e81142a8ea462a9ebcde9a7226a62a60b"}],"nova/tests/functional/test_aggregates.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4bab3d6f96c053b275527fb0441b37d34b439c98","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        self._add_host_to_aggregate(\u0027only-host2\u0027, \u0027host2\u0027)"},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"        # Aggregate with both hosts"},{"line_number":105,"context_line":"        self._create_aggregate(\u0027both-hosts\u0027)"},{"line_number":106,"context_line":"        self._add_host_to_aggregate(\u0027both-hosts\u0027, \u0027host1\u0027)"},{"line_number":107,"context_line":"        self._add_host_to_aggregate(\u0027both-hosts\u0027, \u0027host2\u0027)"},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"        # Aggregate with neither host"},{"line_number":110,"context_line":"        self._create_aggregate(\u0027no-hosts\u0027)"}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_d5f98b4d","line":107,"range":{"start_line":105,"start_character":0,"end_line":107,"end_character":58},"updated":"2018-03-23 23:38:28.000000000","message":"Yeah, I don\u0027t see a test case that uses these.  If you add one, won\u0027t [1] cause us to stack up all on one host?\n\n[1] https://review.openstack.org/#/c/545002/17/nova/scheduler/request_filter.py@53","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"188101034b88d2a7514594e7cb5698b8b11e05c6","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        self._add_host_to_aggregate(\u0027only-host2\u0027, \u0027host2\u0027)"},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"        # Aggregate with both hosts"},{"line_number":105,"context_line":"        self._create_aggregate(\u0027both-hosts\u0027)"},{"line_number":106,"context_line":"        self._add_host_to_aggregate(\u0027both-hosts\u0027, \u0027host1\u0027)"},{"line_number":107,"context_line":"        self._add_host_to_aggregate(\u0027both-hosts\u0027, \u0027host2\u0027)"},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"        # Aggregate with neither host"},{"line_number":110,"context_line":"        self._create_aggregate(\u0027no-hosts\u0027)"}],"source_content_type":"text/x-python","patch_set":17,"id":"bf659307_78b86fc7","line":107,"range":{"start_line":105,"start_character":0,"end_line":107,"end_character":58},"in_reply_to":"bf659307_d5f98b4d","updated":"2018-03-27 14:23:23.000000000","message":"It won\u0027t as noted.\n\nYeah, I didn\u0027t write a test for these, I was filling out all the permutations in setUp before I wrote anything else. I guess there\u0027s not much point as there isn\u0027t much to assert.","commit_id":"4f95b511344be9223046940d0863157a2faaf140"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"fb5c63a0a9beaa92f52a36211d5d2ef0ec5f5d44","unresolved":false,"context_lines":[{"line_number":77,"context_line":"        # the image fake backend needed for image discovery"},{"line_number":78,"context_line":"        nova.tests.unit.image.fake.stub_out_image_service(self)"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"        fake_network.set_stub_network_methods(self)"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"        self.start_service(\u0027conductor\u0027)"},{"line_number":83,"context_line":"        self.scheduler_service \u003d self.start_service(\u0027scheduler\u0027)"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_38773005","line":80,"updated":"2018-03-28 15:07:47.000000000","message":"nit: If you set networks\u003d\u0027none\u0027 when posting the server create request then I don\u0027t think you need this.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":77,"context_line":"        # the image fake backend needed for image discovery"},{"line_number":78,"context_line":"        nova.tests.unit.image.fake.stub_out_image_service(self)"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"        fake_network.set_stub_network_methods(self)"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"        self.start_service(\u0027conductor\u0027)"},{"line_number":83,"context_line":"        self.scheduler_service \u003d self.start_service(\u0027scheduler\u0027)"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_8896273e","line":80,"in_reply_to":"bf659307_38773005","updated":"2018-03-28 18:21:38.000000000","message":"I just copied this.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"fb5c63a0a9beaa92f52a36211d5d2ef0ec5f5d44","unresolved":false,"context_lines":[{"line_number":85,"context_line":"        self.computes \u003d {}"},{"line_number":86,"context_line":"        self.aggregates \u003d {}"},{"line_number":87,"context_line":""},{"line_number":88,"context_line":"        self.computes[\u0027host1\u0027] \u003d self._start_compute(\u0027host1\u0027)"},{"line_number":89,"context_line":"        self.computes[\u0027host2\u0027] \u003d self._start_compute(\u0027host2\u0027)"},{"line_number":90,"context_line":""},{"line_number":91,"context_line":"        self.context \u003d nova_context.get_admin_context()"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_782848e1","line":88,"range":{"start_line":88,"start_character":8,"end_line":88,"end_character":30},"updated":"2018-03-28 15:07:47.000000000","message":"This is redundant with _start_compute.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":85,"context_line":"        self.computes \u003d {}"},{"line_number":86,"context_line":"        self.aggregates \u003d {}"},{"line_number":87,"context_line":""},{"line_number":88,"context_line":"        self.computes[\u0027host1\u0027] \u003d self._start_compute(\u0027host1\u0027)"},{"line_number":89,"context_line":"        self.computes[\u0027host2\u0027] \u003d self._start_compute(\u0027host2\u0027)"},{"line_number":90,"context_line":""},{"line_number":91,"context_line":"        self.context \u003d nova_context.get_admin_context()"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_e8956334","line":88,"range":{"start_line":88,"start_character":8,"end_line":88,"end_character":30},"in_reply_to":"bf659307_782848e1","updated":"2018-03-28 18:21:38.000000000","message":"I just copied this","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"fb5c63a0a9beaa92f52a36211d5d2ef0ec5f5d44","unresolved":false,"context_lines":[{"line_number":148,"context_line":""},{"line_number":149,"context_line":"        # Get the existing aggregates for this host in placement and add the"},{"line_number":150,"context_line":"        # new one to it"},{"line_number":151,"context_line":"        aggs \u003d self.report_client.get("},{"line_number":152,"context_line":"            \u0027/resource_providers/%s/aggregates\u0027 % host_uuid,"},{"line_number":153,"context_line":"            version\u003d\u00271.1\u0027).json()"},{"line_number":154,"context_line":"        placement_aggs \u003d aggs[\u0027aggregates\u0027]"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_78fa8875","line":151,"range":{"start_line":151,"start_character":20,"end_line":151,"end_character":33},"updated":"2018-03-28 15:07:47.000000000","message":"Could just use placement_api for this but it\u0027s not a big deal.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"fb5c63a0a9beaa92f52a36211d5d2ef0ec5f5d44","unresolved":false,"context_lines":[{"line_number":152,"context_line":"            \u0027/resource_providers/%s/aggregates\u0027 % host_uuid,"},{"line_number":153,"context_line":"            version\u003d\u00271.1\u0027).json()"},{"line_number":154,"context_line":"        placement_aggs \u003d aggs[\u0027aggregates\u0027]"},{"line_number":155,"context_line":"        placement_aggs.append(agg[\u0027uuid\u0027])"},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"        # Make sure we have a view of the provider we\u0027re about to mess with"},{"line_number":158,"context_line":"        # FIXME(efried): This should be a thing we can do without internals"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_f82bf8e7","line":155,"range":{"start_line":155,"start_character":8,"end_line":155,"end_character":42},"updated":"2018-03-28 15:07:47.000000000","message":"Check for dupes?","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"01aae235d48465516a0658a3fc9510e4237e0bf0","unresolved":false,"context_lines":[{"line_number":152,"context_line":"            \u0027/resource_providers/%s/aggregates\u0027 % host_uuid,"},{"line_number":153,"context_line":"            version\u003d\u00271.1\u0027).json()"},{"line_number":154,"context_line":"        placement_aggs \u003d aggs[\u0027aggregates\u0027]"},{"line_number":155,"context_line":"        placement_aggs.append(agg[\u0027uuid\u0027])"},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"        # Make sure we have a view of the provider we\u0027re about to mess with"},{"line_number":158,"context_line":"        # FIXME(efried): This should be a thing we can do without internals"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_b72a6229","line":155,"range":{"start_line":155,"start_character":8,"end_line":155,"end_character":42},"in_reply_to":"bf659307_e81a43ca","updated":"2018-03-28 21:38:49.000000000","message":"If agg[\u0027uuid\u0027] is already in placement_aggs I assume that might cause problems, and tests could fail in weird ways. Maybe it\u0027s not an issue and I\u0027m just being paranoid.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"6693bfc0850f75c08b12e4519f8ed103ac7f11cc","unresolved":false,"context_lines":[{"line_number":152,"context_line":"            \u0027/resource_providers/%s/aggregates\u0027 % host_uuid,"},{"line_number":153,"context_line":"            version\u003d\u00271.1\u0027).json()"},{"line_number":154,"context_line":"        placement_aggs \u003d aggs[\u0027aggregates\u0027]"},{"line_number":155,"context_line":"        placement_aggs.append(agg[\u0027uuid\u0027])"},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"        # Make sure we have a view of the provider we\u0027re about to mess with"},{"line_number":158,"context_line":"        # FIXME(efried): This should be a thing we can do without internals"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_e81a43ca","line":155,"range":{"start_line":155,"start_character":8,"end_line":155,"end_character":42},"in_reply_to":"bf659307_f82bf8e7","updated":"2018-03-28 18:28:48.000000000","message":"Check for dupes what?","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"fb5c63a0a9beaa92f52a36211d5d2ef0ec5f5d44","unresolved":false,"context_lines":[{"line_number":191,"context_line":"        server_req \u003d self._build_minimal_create_server_request("},{"line_number":192,"context_line":"            self.api, \u0027test-instance\u0027, flavor_id\u003dself.flavors[0][\u0027id\u0027],"},{"line_number":193,"context_line":"            image_uuid\u003d\u0027155d900f-4e14-4e4c-a73d-069cbf4541e6\u0027,"},{"line_number":194,"context_line":"            networks\u003d[])"},{"line_number":195,"context_line":""},{"line_number":196,"context_line":"        created_server \u003d self.api.post_server({\u0027server\u0027: server_req})"},{"line_number":197,"context_line":"        server \u003d self._wait_for_state_change(created_server, \u0027BUILD\u0027)"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_f862183e","line":194,"range":{"start_line":194,"start_character":21,"end_line":194,"end_character":23},"updated":"2018-03-28 15:07:47.000000000","message":"\u0027none\u0027 is probably simpler.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":191,"context_line":"        server_req \u003d self._build_minimal_create_server_request("},{"line_number":192,"context_line":"            self.api, \u0027test-instance\u0027, flavor_id\u003dself.flavors[0][\u0027id\u0027],"},{"line_number":193,"context_line":"            image_uuid\u003d\u0027155d900f-4e14-4e4c-a73d-069cbf4541e6\u0027,"},{"line_number":194,"context_line":"            networks\u003d[])"},{"line_number":195,"context_line":""},{"line_number":196,"context_line":"        created_server \u003d self.api.post_server({\u0027server\u0027: server_req})"},{"line_number":197,"context_line":"        server \u003d self._wait_for_state_change(created_server, \u0027BUILD\u0027)"}],"source_content_type":"text/x-python","patch_set":19,"id":"bf659307_08753732","line":194,"range":{"start_line":194,"start_character":21,"end_line":194,"end_character":23},"in_reply_to":"bf659307_f862183e","updated":"2018-03-28 18:21:38.000000000","message":"I copied this.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"86cdcbf2a35e4a41dbfcc40f9029390e4fcec4ce","unresolved":false,"context_lines":[{"line_number":149,"context_line":"            \u0027/resource_providers/%s/aggregates\u0027 % host_uuid,"},{"line_number":150,"context_line":"            version\u003d\u00271.1\u0027).json()"},{"line_number":151,"context_line":"        placement_aggs \u003d aggs[\u0027aggregates\u0027]"},{"line_number":152,"context_line":"        placement_aggs.append(agg[\u0027uuid\u0027])"},{"line_number":153,"context_line":""},{"line_number":154,"context_line":"        # Make sure we have a view of the provider we\u0027re about to mess with"},{"line_number":155,"context_line":"        # FIXME(efried): This should be a thing we can do without internals"}],"source_content_type":"text/x-python","patch_set":26,"id":"bf659307_dcc85d23","line":152,"range":{"start_line":152,"start_character":8,"end_line":152,"end_character":42},"updated":"2018-03-28 21:17:47.000000000","message":"I think he means this should use a set instead of a list.","commit_id":"60ea5bf4c32e867c41cd80c4767f0877b9365291"}],"nova/tests/unit/scheduler/test_request_filter.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"86cdcbf2a35e4a41dbfcc40f9029390e4fcec4ce","unresolved":false,"context_lines":[{"line_number":61,"context_line":"        ]"},{"line_number":62,"context_line":"        reqspec \u003d objects.RequestSpec(project_id\u003d\u0027owner\u0027)"},{"line_number":63,"context_line":"        request_filter.require_tenant_aggregate(self.context, reqspec)"},{"line_number":64,"context_line":"        self.assertEqual("},{"line_number":65,"context_line":"            \u0027,\u0027.join(sorted([uuids.agg1, uuids.agg2])),"},{"line_number":66,"context_line":"            \u0027,\u0027.join(sorted("},{"line_number":67,"context_line":"                reqspec.requested_destination.aggregates[0].split(\u0027,\u0027))))"}],"source_content_type":"text/x-python","patch_set":26,"id":"bf659307_1ce255a1","line":64,"updated":"2018-03-28 21:17:47.000000000","message":"sigh","commit_id":"60ea5bf4c32e867c41cd80c4767f0877b9365291"}],"releasenotes/notes/tenant_aggregate_placement_filter-c2fed8889f43b6e3.yaml":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4a882aac4e8d29a3cf688873f1fea494c1cfebf4","unresolved":false,"context_lines":[{"line_number":1,"context_line":"---"},{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_3fd3af62","line":1,"updated":"2018-03-27 21:59:31.000000000","message":"no penalty for long lines here?","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"201dfafaf1f4c439c105a661fff1c43aa06bf783","unresolved":false,"context_lines":[{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_f560e1a7","line":6,"updated":"2018-03-28 14:31:12.000000000","message":"As mentioned in PS9, I would like to see actual docs about the new filter stuff, e.g.:\n\nhttps://docs.openstack.org/nova/latest/admin/configuration/schedulers.html#aggregatemultitenancyisolation\n\nSince release notes aren\u0027t going be as discoverable in a few releases from now.\n\nFurthermore, I think a doc section on this filter should give a simple example of how this is all wired up on the command line using the openstack CLIs for compute host aggregates and placement aggregates, that would be really nice.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"201dfafaf1f4c439c105a661fff1c43aa06bf783","unresolved":false,"context_lines":[{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_b55a69f0","line":6,"range":{"start_line":6,"start_character":55,"end_line":6,"end_character":63},"updated":"2018-03-28 14:31:12.000000000","message":"Does the suffix start at index 0 or 1 or does it not matter? I could dig into the code but for docs I shouldn\u0027t have to.\n\nLooking at the config option help, the example used there is \"filter_tenant_id:123\" and looking at the code, all that matters is the \"filter_tenant_id\" prefix, so I guess anything after that doesn\u0027t matter.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b6e29b9768c67f20a13339e16cf6b7638f4d5d33","unresolved":false,"context_lines":[{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_f7be9ab2","line":6,"range":{"start_line":6,"start_character":55,"end_line":6,"end_character":63},"in_reply_to":"bf659307_77e5aa08","updated":"2018-03-28 21:42:49.000000000","message":"\u003e If a docs patch comes right after this one in the series, I\u0027m OK\n \u003e with that. If it waits until the very end of the WIPs in the\n \u003e series, then I\u0027d prefer it\u0027s just in this change itself.\n\nNot a problem, you\u0027ve already got it lined up:\n\nhttps://review.openstack.org/#/c/557490/","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"01aae235d48465516a0658a3fc9510e4237e0bf0","unresolved":false,"context_lines":[{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_77e5aa08","line":6,"range":{"start_line":6,"start_character":55,"end_line":6,"end_character":63},"in_reply_to":"bf659307_a89beb63","updated":"2018-03-28 21:38:49.000000000","message":"If a docs patch comes right after this one in the series, I\u0027m OK with that. If it waits until the very end of the WIPs in the series, then I\u0027d prefer it\u0027s just in this change itself.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_a89beb63","line":6,"range":{"start_line":6,"start_character":55,"end_line":6,"end_character":63},"in_reply_to":"bf659307_b55a69f0","updated":"2018-03-28 18:21:38.000000000","message":"It doesn\u0027t matter, but sure.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"15b649004a0d3ce35f9a918a2679c174b3b32167","unresolved":false,"context_lines":[{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_28c03b2a","line":6,"in_reply_to":"bf659307_f560e1a7","updated":"2018-03-28 18:21:38.000000000","message":"I don\u0027t think this should be documented as a filter yet, but just as a feature. The fact that we call it a filter and make it modular internally is just an implementation detail.\n\nBut, the \"how to wire this up\" is legit and I\u0027ll go looking for a place to put that. I\u0027ll probably slap that on the end so it\u0027s not tied directly to the code if that\u0027s okay.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"201dfafaf1f4c439c105a661fff1c43aa06bf783","unresolved":false,"context_lines":[{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"},{"line_number":10,"context_line":"    makes it either optional or mandatory, allowing only some tenants to be restricted."}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_95c72546","line":8,"range":{"start_line":7,"start_character":50,"end_line":8,"end_character":36},"updated":"2018-03-28 14:31:12.000000000","message":"Aggregates don\u0027t get created directly in placement, they just get associated with resource providers. It would be helpful to people reading this to link to the osc-placement CLI usage for associating aggregates with resource providers so people don\u0027t have to hunt for that:\n\nhttps://docs.openstack.org/osc-placement/latest/cli/index.html#resource-provider-aggregate-set","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"201dfafaf1f4c439c105a661fff1c43aa06bf783","unresolved":false,"context_lines":[{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"},{"line_number":10,"context_line":"    makes it either optional or mandatory, allowing only some tenants to be restricted."}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_55174dee","line":8,"range":{"start_line":8,"start_character":44,"end_line":8,"end_character":80},"updated":"2018-03-28 14:31:12.000000000","message":"nit: include the option group in this, so [scheduler] or [filter_scheduler] or whatever it is.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"01aae235d48465516a0658a3fc9510e4237e0bf0","unresolved":false,"context_lines":[{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"},{"line_number":10,"context_line":"    makes it either optional or mandatory, allowing only some tenants to be restricted."}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_57d18622","line":8,"range":{"start_line":7,"start_character":50,"end_line":8,"end_character":36},"in_reply_to":"bf659307_6854f353","updated":"2018-03-28 21:38:49.000000000","message":"\u003e and if I\u0027m going to do a real doc to explain how this gets wired up I think that\u0027s a reasonable place to do that.\n\nYup, totally agree with that.\n\nIt would be nice if this release note could link to said docs when they are up, but we can also amend the release note later for the docs link too.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"6693bfc0850f75c08b12e4519f8ed103ac7f11cc","unresolved":false,"context_lines":[{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"},{"line_number":10,"context_line":"    makes it either optional or mandatory, allowing only some tenants to be restricted."}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_6854f353","line":8,"range":{"start_line":7,"start_character":50,"end_line":8,"end_character":36},"in_reply_to":"bf659307_95c72546","updated":"2018-03-28 18:28:48.000000000","message":"They don\u0027t get created directly, but they do get created (by uuid) by associating hosts. I\u0027m not sure that I really need to explain how placement aggregates work here, and if I\u0027m going to do a real doc to explain how this gets wired up I think that\u0027s a reasonable place to do that.","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"201dfafaf1f4c439c105a661fff1c43aa06bf783","unresolved":false,"context_lines":[{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed for multiple tenants,"},{"line_number":7,"context_line":"    like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate is created in"},{"line_number":8,"context_line":"    placement with an identical UUID. The ``limit_tenants_to_placement_aggregate``"},{"line_number":9,"context_line":"    config option enables this behavior and ``placement_aggregate_required_for_tenants``"},{"line_number":10,"context_line":"    makes it either optional or mandatory, allowing only some tenants to be restricted."}],"source_content_type":"text/x-yaml","patch_set":19,"id":"bf659307_15d79525","line":9,"range":{"start_line":9,"start_character":46,"end_line":9,"end_character":86},"updated":"2018-03-28 14:31:12.000000000","message":"same","commit_id":"16feed978cd95c60200fa216ac126282582594b9"},{"author":{"_account_id":26936,"name":"Surya Seetharaman","email":"suryaseetharaman.9@gmail.com","username":"tssurya"},"change_message_id":"e8665c7889b4b0ed22f000bbc32dfcb13a53717e","unresolved":false,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed with any string for"},{"line_number":7,"context_line":"    multiple tenants, like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate"},{"line_number":8,"context_line":"    is created in placement with an identical UUID. The"},{"line_number":9,"context_line":"    ``[scheduler]/limit_tenants_to_placement_aggregate`` config option enables this"}],"source_content_type":"text/x-yaml","patch_set":27,"id":"bf659307_403e948c","line":6,"range":{"start_line":5,"start_character":53,"end_line":6,"end_character":41},"updated":"2018-03-29 10:01:02.000000000","message":"you mean an aggregate metadata is created with the `filter_tenant_id` key in the host aggregate...","commit_id":"732e202e81142a8ea462a9ebcde9a7226a62a60b"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"215789f6a86f65debbac193bde33d23d66d0f4e0","unresolved":false,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    The scheduler can now use placement to more efficiently query for hosts within a"},{"line_number":5,"context_line":"    tenant-restricted aggregate. This requires that a host aggregate is created in"},{"line_number":6,"context_line":"    nova with the ``filter_tenant_id`` key (optionally suffixed with any string for"},{"line_number":7,"context_line":"    multiple tenants, like ``filter_tenant_id3\u003d$tenantid``) and the same aggregate"},{"line_number":8,"context_line":"    is created in placement with an identical UUID. The"},{"line_number":9,"context_line":"    ``[scheduler]/limit_tenants_to_placement_aggregate`` config option enables this"}],"source_content_type":"text/x-yaml","patch_set":27,"id":"bf659307_74e1162a","line":6,"range":{"start_line":5,"start_character":53,"end_line":6,"end_character":41},"in_reply_to":"bf659307_403e948c","updated":"2018-03-29 13:47:20.000000000","message":"I think people that are familiar with aggregates will know what this means. Could be updated if this requires a respin, or simply say \u0027metadata key\u0027 instead of just \u0027key\u0027, but I\u0027m still OK with what\u0027s here.","commit_id":"732e202e81142a8ea462a9ebcde9a7226a62a60b"}]}
