)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":15,"context_line":"function is intended to be consumed by the resource tracker in a later"},{"line_number":16,"context_line":"patch."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"TODO: More tests."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"Change-Id: I2d15af56fece3c5bba7583d51578b57f76a5fb70"},{"line_number":21,"context_line":"Blueprint: provider-config-file"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":19,"id":"3fa7e38b_912469b1","line":18,"range":{"start_line":18,"start_character":0,"end_line":18,"end_character":17},"updated":"2019-10-18 21:33:24.000000000","message":"does this still apply?\n\n[Later] Yup. Tests for multiple providers (in one or multiple files) including conflict checking.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e9a9ad165eaea571d5f18cd8f54977dd63e59fdf","unresolved":false,"context_lines":[{"line_number":15,"context_line":"function is intended to be consumed by the resource tracker in a later"},{"line_number":16,"context_line":"patch."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"TODO: More tests."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"Change-Id: I2d15af56fece3c5bba7583d51578b57f76a5fb70"},{"line_number":21,"context_line":"Blueprint: provider-config-file"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":24,"id":"3fa7e38b_09a6a9c2","line":18,"range":{"start_line":18,"start_character":0,"end_line":18,"end_character":17},"updated":"2019-10-25 20:13:34.000000000","message":"still?","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"}],"nova/compute/provider_config.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":66,"context_line":"        return yaml.safe_load(f)"},{"line_number":67,"context_line":""},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"def _verify_providers(yaml_file):"},{"line_number":70,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":71,"context_line":"     performs additional checks for format and required keys."},{"line_number":72,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_c3b402f5","line":69,"range":{"start_line":69,"start_character":4,"end_line":69,"end_character":21},"updated":"2019-08-13 22:50:23.000000000","message":"Somewhere in here - or possibly even in the schema loading/parsing stuff in the prior patch - you should have something that checks the input schema (minor) version against the code schema version. If the latter is lower, log a warning like\n\n \"Provider config file %s is at schema version %s, but the \n \"code only understands up to version %s. Some fields may \n \"be ignored.\"","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":66,"context_line":"        return yaml.safe_load(f)"},{"line_number":67,"context_line":""},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"def _verify_providers(yaml_file):"},{"line_number":70,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":71,"context_line":"     performs additional checks for format and required keys."},{"line_number":72,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_25d628f4","line":69,"range":{"start_line":69,"start_character":4,"end_line":69,"end_character":21},"in_reply_to":"7faddb67_c3b402f5","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":75,"context_line":"    :raise: nova.exception.InvalidResourceClass if any resource class fails to"},{"line_number":76,"context_line":"        validate."},{"line_number":77,"context_line":"    \"\"\""},{"line_number":78,"context_line":"    try:"},{"line_number":79,"context_line":"        providers \u003d yaml_file[\"providers\"]"},{"line_number":80,"context_line":"    except KeyError:"},{"line_number":81,"context_line":"        # NOTE(dustinc): no providers, this is OK"},{"line_number":82,"context_line":"        providers \u003d []"},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    # NOTE(dustinc): Here we will check that the identification method is known"},{"line_number":85,"context_line":"    #   since the schema only requires that some property be present"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_c3264269","line":82,"range":{"start_line":78,"start_character":0,"end_line":82,"end_character":22},"updated":"2019-08-13 22:50:23.000000000","message":"or\n\n providers \u003d yaml_file.get(\"providers\", [])","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":75,"context_line":"    :raise: nova.exception.InvalidResourceClass if any resource class fails to"},{"line_number":76,"context_line":"        validate."},{"line_number":77,"context_line":"    \"\"\""},{"line_number":78,"context_line":"    try:"},{"line_number":79,"context_line":"        providers \u003d yaml_file[\"providers\"]"},{"line_number":80,"context_line":"    except KeyError:"},{"line_number":81,"context_line":"        # NOTE(dustinc): no providers, this is OK"},{"line_number":82,"context_line":"        providers \u003d []"},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    # NOTE(dustinc): Here we will check that the identification method is known"},{"line_number":85,"context_line":"    #   since the schema only requires that some property be present"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_a5fbf878","line":82,"range":{"start_line":78,"start_character":0,"end_line":82,"end_character":22},"in_reply_to":"7faddb67_c3264269","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":84,"context_line":"    # NOTE(dustinc): Here we will check that the identification method is known"},{"line_number":85,"context_line":"    #   since the schema only requires that some property be present"},{"line_number":86,"context_line":"    for provider in providers:"},{"line_number":87,"context_line":"        try:"},{"line_number":88,"context_line":"            provider_id \u003d provider[\"identification\"][\"name\"]"},{"line_number":89,"context_line":"        except KeyError:"},{"line_number":90,"context_line":"            try:"},{"line_number":91,"context_line":"                provider_id \u003d provider[\"identification\"][\"uuid\"]"},{"line_number":92,"context_line":"            except KeyError:"},{"line_number":93,"context_line":"                raise jsonschema.exceptions.ValidationError("},{"line_number":94,"context_line":"                    \"The Custom provider does not have known identification.\")"},{"line_number":95,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_83e5aa0c","line":92,"range":{"start_line":87,"start_character":8,"end_line":92,"end_character":28},"updated":"2019-08-13 22:50:23.000000000","message":"This nested try is a bit ick. Since \u0027identification\u0027 is required by the schema, you could do something like:\n\n pid \u003d provider[\u0027identification\u0027]\n provider_id \u003d pid.get(\u0027name\u0027) or pid.get(\u0027uuid\u0027)\n if not provider_id:\n     raise ....","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":84,"context_line":"    # NOTE(dustinc): Here we will check that the identification method is known"},{"line_number":85,"context_line":"    #   since the schema only requires that some property be present"},{"line_number":86,"context_line":"    for provider in providers:"},{"line_number":87,"context_line":"        try:"},{"line_number":88,"context_line":"            provider_id \u003d provider[\"identification\"][\"name\"]"},{"line_number":89,"context_line":"        except KeyError:"},{"line_number":90,"context_line":"            try:"},{"line_number":91,"context_line":"                provider_id \u003d provider[\"identification\"][\"uuid\"]"},{"line_number":92,"context_line":"            except KeyError:"},{"line_number":93,"context_line":"                raise jsonschema.exceptions.ValidationError("},{"line_number":94,"context_line":"                    \"The Custom provider does not have known identification.\")"},{"line_number":95,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_05676c4f","line":92,"range":{"start_line":87,"start_character":8,"end_line":92,"end_character":28},"in_reply_to":"7faddb67_83e5aa0c","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        # NOTE(dustinc): Here we will check that traits and resource class"},{"line_number":97,"context_line":"        #   names all start with CUSTOM_"},{"line_number":98,"context_line":"        try:"},{"line_number":99,"context_line":"            traits \u003d provider[\"traits\"][\"additional\"]"},{"line_number":100,"context_line":"        except KeyError:"},{"line_number":101,"context_line":"            # NOTE(dustinc): no traits, this is OK"},{"line_number":102,"context_line":"            traits \u003d []"},{"line_number":103,"context_line":"        trait_conflicts \u003d [trait for trait in traits"},{"line_number":104,"context_line":"                     if not trait.startswith(\"CUSTOM_\")]"},{"line_number":105,"context_line":"        if trait_conflicts:"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_a3c9c679","line":102,"range":{"start_line":98,"start_character":0,"end_line":102,"end_character":23},"updated":"2019-08-13 22:50:23.000000000","message":"or\n\n traits \u003d provider.get(\u0027traits\u0027, {}).get(\u0027additional\u0027, [])","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":95,"context_line":""},{"line_number":96,"context_line":"        # NOTE(dustinc): Here we will check that traits and resource class"},{"line_number":97,"context_line":"        #   names all start with CUSTOM_"},{"line_number":98,"context_line":"        try:"},{"line_number":99,"context_line":"            traits \u003d provider[\"traits\"][\"additional\"]"},{"line_number":100,"context_line":"        except KeyError:"},{"line_number":101,"context_line":"            # NOTE(dustinc): no traits, this is OK"},{"line_number":102,"context_line":"            traits \u003d []"},{"line_number":103,"context_line":"        trait_conflicts \u003d [trait for trait in traits"},{"line_number":104,"context_line":"                     if not trait.startswith(\"CUSTOM_\")]"},{"line_number":105,"context_line":"        if trait_conflicts:"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_e561f03a","line":102,"range":{"start_line":98,"start_character":0,"end_line":102,"end_character":23},"in_reply_to":"7faddb67_a3c9c679","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":107,"context_line":"            LOG.warning(\"Invalid traits on provider [%s], traits must start \""},{"line_number":108,"context_line":"                        \"with \u0027CUSTOM_\u0027. These traits will be ignored: %s\","},{"line_number":109,"context_line":"                        (provider_id, trait_conflicts))"},{"line_number":110,"context_line":"            provider[\"traits\"][\"additional\"] \u003d [trait for trait in traits if"},{"line_number":111,"context_line":"                                                trait not in trait_conflicts]"},{"line_number":112,"context_line":"        try:"},{"line_number":113,"context_line":"            additional_inventories \u003d provider[\"inventories\"][\"additional\"]"},{"line_number":114,"context_line":"        except KeyError:"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_238cf633","line":111,"range":{"start_line":110,"start_character":47,"end_line":111,"end_character":77},"updated":"2019-08-13 22:50:23.000000000","message":"If you use sets throughout for traits and trait_conflicts, this becomes (simpler and) faster:\n\n list(traits - trait_conflicts)","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":107,"context_line":"            LOG.warning(\"Invalid traits on provider [%s], traits must start \""},{"line_number":108,"context_line":"                        \"with \u0027CUSTOM_\u0027. These traits will be ignored: %s\","},{"line_number":109,"context_line":"                        (provider_id, trait_conflicts))"},{"line_number":110,"context_line":"            provider[\"traits\"][\"additional\"] \u003d [trait for trait in traits if"},{"line_number":111,"context_line":"                                                trait not in trait_conflicts]"},{"line_number":112,"context_line":"        try:"},{"line_number":113,"context_line":"            additional_inventories \u003d provider[\"inventories\"][\"additional\"]"},{"line_number":114,"context_line":"        except KeyError:"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_c55cf47e","line":111,"range":{"start_line":110,"start_character":47,"end_line":111,"end_character":77},"in_reply_to":"7faddb67_238cf633","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":109,"context_line":"                        (provider_id, trait_conflicts))"},{"line_number":110,"context_line":"            provider[\"traits\"][\"additional\"] \u003d [trait for trait in traits if"},{"line_number":111,"context_line":"                                                trait not in trait_conflicts]"},{"line_number":112,"context_line":"        try:"},{"line_number":113,"context_line":"            additional_inventories \u003d provider[\"inventories\"][\"additional\"]"},{"line_number":114,"context_line":"        except KeyError:"},{"line_number":115,"context_line":"            # NOTE(dustinc): no additional inventories, this is OK"},{"line_number":116,"context_line":"            additional_inventories \u003d []"},{"line_number":117,"context_line":"        for inventory in additional_inventories:"},{"line_number":118,"context_line":"            inventory_conflicts \u003d [key for key in inventory.keys()"},{"line_number":119,"context_line":"                         if not key.startswith(\"CUSTOM_\")]"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_e3857e08","line":116,"range":{"start_line":112,"start_character":0,"end_line":116,"end_character":39},"updated":"2019-08-13 22:50:23.000000000","message":"similar to above","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":109,"context_line":"                        (provider_id, trait_conflicts))"},{"line_number":110,"context_line":"            provider[\"traits\"][\"additional\"] \u003d [trait for trait in traits if"},{"line_number":111,"context_line":"                                                trait not in trait_conflicts]"},{"line_number":112,"context_line":"        try:"},{"line_number":113,"context_line":"            additional_inventories \u003d provider[\"inventories\"][\"additional\"]"},{"line_number":114,"context_line":"        except KeyError:"},{"line_number":115,"context_line":"            # NOTE(dustinc): no additional inventories, this is OK"},{"line_number":116,"context_line":"            additional_inventories \u003d []"},{"line_number":117,"context_line":"        for inventory in additional_inventories:"},{"line_number":118,"context_line":"            inventory_conflicts \u003d [key for key in inventory.keys()"},{"line_number":119,"context_line":"                         if not key.startswith(\"CUSTOM_\")]"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_85d7dcbf","line":116,"range":{"start_line":112,"start_character":0,"end_line":116,"end_character":39},"in_reply_to":"7faddb67_e3857e08","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":115,"context_line":"            # NOTE(dustinc): no additional inventories, this is OK"},{"line_number":116,"context_line":"            additional_inventories \u003d []"},{"line_number":117,"context_line":"        for inventory in additional_inventories:"},{"line_number":118,"context_line":"            inventory_conflicts \u003d [key for key in inventory.keys()"},{"line_number":119,"context_line":"                         if not key.startswith(\"CUSTOM_\")]"},{"line_number":120,"context_line":"            if inventory_conflicts:"},{"line_number":121,"context_line":"                # NOTE(dustinc): per spec, fail if we have non-CUSTOM_*"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_e3ac9ea0","line":118,"range":{"start_line":118,"start_character":59,"end_line":118,"end_character":66},"updated":"2019-08-13 22:50:23.000000000","message":"redundant","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":115,"context_line":"            # NOTE(dustinc): no additional inventories, this is OK"},{"line_number":116,"context_line":"            additional_inventories \u003d []"},{"line_number":117,"context_line":"        for inventory in additional_inventories:"},{"line_number":118,"context_line":"            inventory_conflicts \u003d [key for key in inventory.keys()"},{"line_number":119,"context_line":"                         if not key.startswith(\"CUSTOM_\")]"},{"line_number":120,"context_line":"            if inventory_conflicts:"},{"line_number":121,"context_line":"                # NOTE(dustinc): per spec, fail if we have non-CUSTOM_*"}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_65550050","line":118,"range":{"start_line":118,"start_character":59,"end_line":118,"end_character":66},"in_reply_to":"7faddb67_e3ac9ea0","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":149,"context_line":""},{"line_number":150,"context_line":"def get_custom_resources(provider_config_dir):"},{"line_number":151,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":152,"context_line":"    and merges them into a single dict while checking for name conflicts."},{"line_number":153,"context_line":""},{"line_number":154,"context_line":"    :param provider_config_dir: Path to a directory containing provider config"},{"line_number":155,"context_line":"        files to be loaded."}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_e301fe6b","line":152,"range":{"start_line":152,"start_character":8,"end_line":152,"end_character":72},"updated":"2019-08-13 22:50:23.000000000","message":"Right now it\u0027s merging together all the traits and all the inventories, and losing the information about the provider identification, which I don\u0027t think is what you intended. It\u0027s also not checking for name/ident conflicts.\n\nI don\u0027t think you want to merge together traits or inventories from multiple sections.","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2194b0811dfde121b4b48ca484539ce82f99a205","unresolved":false,"context_lines":[{"line_number":149,"context_line":""},{"line_number":150,"context_line":"def get_custom_resources(provider_config_dir):"},{"line_number":151,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":152,"context_line":"    and merges them into a single dict while checking for name conflicts."},{"line_number":153,"context_line":""},{"line_number":154,"context_line":"    :param provider_config_dir: Path to a directory containing provider config"},{"line_number":155,"context_line":"        files to be loaded."}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_9d94148d","line":152,"range":{"start_line":152,"start_character":8,"end_line":152,"end_character":72},"in_reply_to":"7faddb67_90915c55","updated":"2019-08-14 22:40:34.000000000","message":"Per the spec, you\u0027re only allowed to specify a given provider once across all the files. So there should be no overriding or merging - we need to puke if we find a duplicate provider.\n\nPart of that could be done here, but it will also need to be rechecked in the RT after we\u0027ve got the provider_tree loaded up - otherwise we would miss a conflict where you used e.g. $COMPUTE_NODE and the real name/uuid of the compute node.","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":149,"context_line":""},{"line_number":150,"context_line":"def get_custom_resources(provider_config_dir):"},{"line_number":151,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":152,"context_line":"    and merges them into a single dict while checking for name conflicts."},{"line_number":153,"context_line":""},{"line_number":154,"context_line":"    :param provider_config_dir: Path to a directory containing provider config"},{"line_number":155,"context_line":"        files to be loaded."}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_90915c55","line":152,"range":{"start_line":152,"start_character":8,"end_line":152,"end_character":72},"in_reply_to":"7faddb67_e301fe6b","updated":"2019-08-14 21:58:49.000000000","message":"Fixed the merging.\n\nDo we need to check for name conflicts since we are requiring CUSTOM_ prefix, or do you mean conflicts between different custom providers? If we process the files in lexicographical order, can we just let subsequent files overwrite providers from previous files?","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":170,"context_line":"        # NOTE(dustinc): _verify_providers will remove invalid traits so we"},{"line_number":171,"context_line":"        #   want to use the return value here"},{"line_number":172,"context_line":"        provider_config \u003d _verify_providers(provider_config)"},{"line_number":173,"context_line":"        try:"},{"line_number":174,"context_line":"            for provider in provider_config[\"providers\"]:"},{"line_number":175,"context_line":"                try:"},{"line_number":176,"context_line":"                    custom_resources[\"traits\"].extend("}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_43ab3274","line":173,"updated":"2019-08-13 22:50:23.000000000","message":"Yeah, same comment about the nested tryZ. Could be what I\u0027m used to, but I prefer:\n\n for provider in provider_config.get(\u0027providers\u0027, []):\n     custom_resources[\u0027traits\u0027].extend(\n         provider.get(\u0027traits\u0027, {}).get(\u0027additional\u0027, []))\n     custom_resources[\u0027inventories\u0027].update(\n         provider.get(\u0027inventories\u0027, {}).get(\u0027additional\u0027, []))","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":170,"context_line":"        # NOTE(dustinc): _verify_providers will remove invalid traits so we"},{"line_number":171,"context_line":"        #   want to use the return value here"},{"line_number":172,"context_line":"        provider_config \u003d _verify_providers(provider_config)"},{"line_number":173,"context_line":"        try:"},{"line_number":174,"context_line":"            for provider in provider_config[\"providers\"]:"},{"line_number":175,"context_line":"                try:"},{"line_number":176,"context_line":"                    custom_resources[\"traits\"].extend("}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_10332cad","line":173,"in_reply_to":"7faddb67_43ab3274","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":71,"context_line":"        return yaml.safe_load(f)"},{"line_number":72,"context_line":""},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"def _verify_providers(yaml_file):"},{"line_number":75,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":76,"context_line":"     performs additional checks for format and required keys."},{"line_number":77,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_fe12acfc","line":74,"range":{"start_line":74,"start_character":4,"end_line":74,"end_character":21},"updated":"2019-09-03 22:35:28.000000000","message":"I would call this _validate_provider_config","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":71,"context_line":"        return yaml.safe_load(f)"},{"line_number":72,"context_line":""},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"def _verify_providers(yaml_file):"},{"line_number":75,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":76,"context_line":"     performs additional checks for format and required keys."},{"line_number":77,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_1e9b05c9","line":74,"range":{"start_line":74,"start_character":4,"end_line":74,"end_character":21},"in_reply_to":"7faddb67_fe12acfc","updated":"2019-09-04 05:35:14.000000000","message":"Done","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":76,"context_line":"     performs additional checks for format and required keys."},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    :param yaml_file: Dict containing a provider config file."},{"line_number":79,"context_line":"    :return: The original yaml_file minus any ignored traits"},{"line_number":80,"context_line":"    :raise:"},{"line_number":81,"context_line":"        jsonschema.exceptions.ValidationError if provider id is missing"},{"line_number":82,"context_line":"        nova.exception.ResourceProviderInUse if a provider id is defined twice"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_de2fb086","line":79,"range":{"start_line":79,"start_character":13,"end_line":79,"end_character":60},"updated":"2019-09-03 22:35:28.000000000","message":"To be clear, this edits the input parameter in place and also returns it. That being the case, I\u0027m not sure there\u0027s value in returning it, and it would make it clearer that this method is side-effecty if you didn\u0027t.\n\n[Later] But actually, we shouldn\u0027t be changing the thing. Invalid traits should result in an error - see below.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":76,"context_line":"     performs additional checks for format and required keys."},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"    :param yaml_file: Dict containing a provider config file."},{"line_number":79,"context_line":"    :return: The original yaml_file minus any ignored traits"},{"line_number":80,"context_line":"    :raise:"},{"line_number":81,"context_line":"        jsonschema.exceptions.ValidationError if provider id is missing"},{"line_number":82,"context_line":"        nova.exception.ResourceProviderInUse if a provider id is defined twice"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_3e3a8197","line":79,"range":{"start_line":79,"start_character":13,"end_line":79,"end_character":60},"in_reply_to":"7faddb67_de2fb086","updated":"2019-09-04 05:35:14.000000000","message":"See comment below.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":78,"context_line":"    :param yaml_file: Dict containing a provider config file."},{"line_number":79,"context_line":"    :return: The original yaml_file minus any ignored traits"},{"line_number":80,"context_line":"    :raise:"},{"line_number":81,"context_line":"        jsonschema.exceptions.ValidationError if provider id is missing"},{"line_number":82,"context_line":"        nova.exception.ResourceProviderInUse if a provider id is defined twice"},{"line_number":83,"context_line":"        nova.exception.InvalidResourceClass if a resource class name is invalid"},{"line_number":84,"context_line":"    \"\"\""},{"line_number":85,"context_line":"    providers \u003d yaml_file.get(\"providers\", [])"},{"line_number":86,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_fe5aac1b","line":83,"range":{"start_line":81,"start_character":0,"end_line":83,"end_character":79},"updated":"2019-09-03 22:35:28.000000000","message":"I like that you\u0027re reusing exceptions, but in the context where this gets run, I think that will actually make things more difficult to manage.\n\nFor example, ResourceProviderInUse is a thing that can happen during update_from_provider_tree, and we want to react differently in that case than if this verification method fails.\n\nWhat I would suggest is that you just have a new, single exception class (or if you must, individual subclasses of a new, single exception class) indicating that this validation went awry.\n\nMore below.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":91,"context_line":"        pid \u003d provider[\"identification\"]"},{"line_number":92,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":93,"context_line":"        if not provider_id:"},{"line_number":94,"context_line":"            raise jsonschema.exceptions.ValidationError("},{"line_number":95,"context_line":"                \"The Custom provider does not have known identification.\")"},{"line_number":96,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":97,"context_line":"            LOG.error(\"Provider %s is defined twice.\", provider_id)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_bed51445","line":94,"range":{"start_line":94,"start_character":40,"end_line":94,"end_character":55},"updated":"2019-09-03 22:35:28.000000000","message":"messages in exceptions need to be marked for translation via _(). I probably missed this in a number of places, including in the previous patch.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"e75fd60f04e2cff714ada904d3e84f97d73e1c17","unresolved":false,"context_lines":[{"line_number":91,"context_line":"        pid \u003d provider[\"identification\"]"},{"line_number":92,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":93,"context_line":"        if not provider_id:"},{"line_number":94,"context_line":"            raise jsonschema.exceptions.ValidationError("},{"line_number":95,"context_line":"                \"The Custom provider does not have known identification.\")"},{"line_number":96,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":97,"context_line":"            LOG.error(\"Provider %s is defined twice.\", provider_id)"}],"source_content_type":"text/x-python","patch_set":11,"id":"3fa7e38b_96877fd8","line":94,"range":{"start_line":94,"start_character":40,"end_line":94,"end_character":55},"in_reply_to":"7faddb67_bed51445","updated":"2019-09-24 15:53:01.000000000","message":"Done","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":92,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":93,"context_line":"        if not provider_id:"},{"line_number":94,"context_line":"            raise jsonschema.exceptions.ValidationError("},{"line_number":95,"context_line":"                \"The Custom provider does not have known identification.\")"},{"line_number":96,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":97,"context_line":"            LOG.error(\"Provider %s is defined twice.\", provider_id)"},{"line_number":98,"context_line":"            raise nova_exc.ResourceProviderInUse(provider_id)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_feddcc6c","line":95,"range":{"start_line":95,"start_character":21,"end_line":95,"end_character":36},"updated":"2019-09-03 22:35:28.000000000","message":"I think we\u0027ve discussed this before, but these aren\u0027t \"custom providers\". They\u0027re provider configuration blocks. This message should say something more like, \"Provider configuration is missing a required field: either \u0027name\u0027 or \u0027uuid\u0027 is required in the \u0027identification\u0027 section.\" And probably also dump the section so they know which one we\u0027re complaining about.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":93,"context_line":"        if not provider_id:"},{"line_number":94,"context_line":"            raise jsonschema.exceptions.ValidationError("},{"line_number":95,"context_line":"                \"The Custom provider does not have known identification.\")"},{"line_number":96,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":97,"context_line":"            LOG.error(\"Provider %s is defined twice.\", provider_id)"},{"line_number":98,"context_line":"            raise nova_exc.ResourceProviderInUse(provider_id)"},{"line_number":99,"context_line":"        processed_provider_ids.append(provider_id)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_7edc7c44","line":96,"range":{"start_line":96,"start_character":8,"end_line":96,"end_character":49},"updated":"2019-09-03 22:35:28.000000000","message":"This is only checking for duplicates *within* a single file. We need to check for duplicates across *all* files. So you could e.g. maintain the processed_provider_ids var at the caller and pass it into this method.\n\nBut we need to take it a step further and make sure we don\u0027t see the same provider e.g. identified by \u0027name\u0027 in one block and by \u0027uuid\u0027 in another; or by explicit UUID in one and $COMPUTE_NODE in another; etc. Perhaps you\u0027re doing that in the next patch...","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4d0c11079c02ecb0e797862b6886c2062632d4af","unresolved":false,"context_lines":[{"line_number":93,"context_line":"        if not provider_id:"},{"line_number":94,"context_line":"            raise jsonschema.exceptions.ValidationError("},{"line_number":95,"context_line":"                \"The Custom provider does not have known identification.\")"},{"line_number":96,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":97,"context_line":"            LOG.error(\"Provider %s is defined twice.\", provider_id)"},{"line_number":98,"context_line":"            raise nova_exc.ResourceProviderInUse(provider_id)"},{"line_number":99,"context_line":"        processed_provider_ids.append(provider_id)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_581d0d71","line":96,"range":{"start_line":96,"start_character":8,"end_line":96,"end_character":49},"in_reply_to":"7faddb67_5ebbbd0d","updated":"2019-09-04 19:34:42.000000000","message":"Yes, it needs to go in the next patch, because you need placement information to know e.g. whether a given `name` represents the same provider as a given `uuid`. In fact, it probably makes sense for the check to *just* go in the next patch, since anything you do here is necessarily incomplete for that reason.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"9f93294a586cc7d394f6a0d2ee5070e436d67871","unresolved":false,"context_lines":[{"line_number":93,"context_line":"        if not provider_id:"},{"line_number":94,"context_line":"            raise jsonschema.exceptions.ValidationError("},{"line_number":95,"context_line":"                \"The Custom provider does not have known identification.\")"},{"line_number":96,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":97,"context_line":"            LOG.error(\"Provider %s is defined twice.\", provider_id)"},{"line_number":98,"context_line":"            raise nova_exc.ResourceProviderInUse(provider_id)"},{"line_number":99,"context_line":"        processed_provider_ids.append(provider_id)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_3eada430","line":96,"range":{"start_line":96,"start_character":8,"end_line":96,"end_character":49},"in_reply_to":"7faddb67_7edc7c44","updated":"2019-09-03 23:07:39.000000000","message":"\u003e Perhaps you\u0027re doing that in the next patch...\n\nnope","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":93,"context_line":"        if not provider_id:"},{"line_number":94,"context_line":"            raise jsonschema.exceptions.ValidationError("},{"line_number":95,"context_line":"                \"The Custom provider does not have known identification.\")"},{"line_number":96,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":97,"context_line":"            LOG.error(\"Provider %s is defined twice.\", provider_id)"},{"line_number":98,"context_line":"            raise nova_exc.ResourceProviderInUse(provider_id)"},{"line_number":99,"context_line":"        processed_provider_ids.append(provider_id)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_5ebbbd0d","line":96,"range":{"start_line":96,"start_character":8,"end_line":96,"end_character":49},"in_reply_to":"7faddb67_7edc7c44","updated":"2019-09-04 05:35:14.000000000","message":"Partially done. It is now checking for duplicates across files, but I am still thinking about different ways to check for duplicates by differing identification methods. That will likely go in next patch.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":101,"context_line":"        #   names all start with CUSTOM_"},{"line_number":102,"context_line":"        traits \u003d set(provider.get(\"traits\", {}).get(\"additional\", []))"},{"line_number":103,"context_line":"        trait_conflicts \u003d {trait for trait in traits"},{"line_number":104,"context_line":"                           if not trait.startswith(\"CUSTOM_\")}"},{"line_number":105,"context_line":"        if trait_conflicts:"},{"line_number":106,"context_line":"            # NOTE(dustinc): per spec, ignore non-CUSTOM_* traits"},{"line_number":107,"context_line":"            LOG.warning(\"Invalid traits on provider [%s], traits must start \""}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_feb62c25","line":104,"range":{"start_line":104,"start_character":34,"end_line":104,"end_character":60},"updated":"2019-09-03 22:35:28.000000000","message":"use\n\n os_traits.is_custom(trait)\n\nhere instead.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":101,"context_line":"        #   names all start with CUSTOM_"},{"line_number":102,"context_line":"        traits \u003d set(provider.get(\"traits\", {}).get(\"additional\", []))"},{"line_number":103,"context_line":"        trait_conflicts \u003d {trait for trait in traits"},{"line_number":104,"context_line":"                           if not trait.startswith(\"CUSTOM_\")}"},{"line_number":105,"context_line":"        if trait_conflicts:"},{"line_number":106,"context_line":"            # NOTE(dustinc): per spec, ignore non-CUSTOM_* traits"},{"line_number":107,"context_line":"            LOG.warning(\"Invalid traits on provider [%s], traits must start \""}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_deeecd1f","line":104,"range":{"start_line":104,"start_character":34,"end_line":104,"end_character":60},"in_reply_to":"7faddb67_feb62c25","updated":"2019-09-04 05:35:14.000000000","message":"Done","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        trait_conflicts \u003d {trait for trait in traits"},{"line_number":104,"context_line":"                           if not trait.startswith(\"CUSTOM_\")}"},{"line_number":105,"context_line":"        if trait_conflicts:"},{"line_number":106,"context_line":"            # NOTE(dustinc): per spec, ignore non-CUSTOM_* traits"},{"line_number":107,"context_line":"            LOG.warning(\"Invalid traits on provider [%s], traits must start \""},{"line_number":108,"context_line":"                        \"with \u0027CUSTOM_\u0027. These traits will be ignored: %s\","},{"line_number":109,"context_line":"                        provider_id, trait_conflicts)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_5e5420c6","line":106,"range":{"start_line":106,"start_character":39,"end_line":106,"end_character":45},"updated":"2019-09-03 22:35:28.000000000","message":"Is that what we said? Hmph.\n\n[Later] Wait, where does it say that? We may have said the *schema* should permit non-CUSTOM traits, but I don\u0027t see where we said we would ignore them in the code.\n\nIMO we should fail here, just like for resource classes below.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        trait_conflicts \u003d {trait for trait in traits"},{"line_number":104,"context_line":"                           if not trait.startswith(\"CUSTOM_\")}"},{"line_number":105,"context_line":"        if trait_conflicts:"},{"line_number":106,"context_line":"            # NOTE(dustinc): per spec, ignore non-CUSTOM_* traits"},{"line_number":107,"context_line":"            LOG.warning(\"Invalid traits on provider [%s], traits must start \""},{"line_number":108,"context_line":"                        \"with \u0027CUSTOM_\u0027. These traits will be ignored: %s\","},{"line_number":109,"context_line":"                        provider_id, trait_conflicts)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_fe7ce971","line":106,"range":{"start_line":106,"start_character":39,"end_line":106,"end_character":45},"in_reply_to":"7faddb67_5e5420c6","updated":"2019-09-04 05:35:14.000000000","message":"The spec explicitly said to fail on conflicting resource classes, but does not say that explicitly on traits. I interpreted that to be do not fail on traits. I am fine changing it if you think failing is the intended behavior. It would simplify the code a bit.\n\n    Only CUSTOM_* resource classes are permitted.\n    Specifying inventory of a resource class natively managed by\n    nova-compute will cause the compute service to fail.\n\n    Only CUSTOM_* traits are permitted. The consuming code is\n    responsible for ensuring the existence of these traits in\n    Placement.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4d0c11079c02ecb0e797862b6886c2062632d4af","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        trait_conflicts \u003d {trait for trait in traits"},{"line_number":104,"context_line":"                           if not trait.startswith(\"CUSTOM_\")}"},{"line_number":105,"context_line":"        if trait_conflicts:"},{"line_number":106,"context_line":"            # NOTE(dustinc): per spec, ignore non-CUSTOM_* traits"},{"line_number":107,"context_line":"            LOG.warning(\"Invalid traits on provider [%s], traits must start \""},{"line_number":108,"context_line":"                        \"with \u0027CUSTOM_\u0027. These traits will be ignored: %s\","},{"line_number":109,"context_line":"                        provider_id, trait_conflicts)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_b82441c7","line":106,"range":{"start_line":106,"start_character":39,"end_line":106,"end_character":45},"in_reply_to":"7faddb67_fe7ce971","updated":"2019-09-04 19:34:42.000000000","message":"Yeah; we didn\u0027t specify in the spec, but I remember the context around only allowing custom traits for now.\n\nI think it makes sense to fail on invalid traits.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":109,"context_line":"                        provider_id, trait_conflicts)"},{"line_number":110,"context_line":"            provider[\"traits\"][\"additional\"] \u003d list(traits - trait_conflicts)"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"        additional_inventories \u003d \\"},{"line_number":113,"context_line":"            provider.get(\"inventories\", {}).get(\"additional\", [])"},{"line_number":114,"context_line":"        for inventory in additional_inventories:"},{"line_number":115,"context_line":"            inventory_conflicts \u003d [key for key in inventory"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_7e40fc06","line":112,"range":{"start_line":112,"start_character":33,"end_line":112,"end_character":34},"updated":"2019-09-03 22:35:28.000000000","message":"avoid backslash","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":109,"context_line":"                        provider_id, trait_conflicts)"},{"line_number":110,"context_line":"            provider[\"traits\"][\"additional\"] \u003d list(traits - trait_conflicts)"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"        additional_inventories \u003d \\"},{"line_number":113,"context_line":"            provider.get(\"inventories\", {}).get(\"additional\", [])"},{"line_number":114,"context_line":"        for inventory in additional_inventories:"},{"line_number":115,"context_line":"            inventory_conflicts \u003d [key for key in inventory"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_7e88f969","line":112,"range":{"start_line":112,"start_character":33,"end_line":112,"end_character":34},"in_reply_to":"7faddb67_7e40fc06","updated":"2019-09-04 05:35:14.000000000","message":"Done","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":113,"context_line":"            provider.get(\"inventories\", {}).get(\"additional\", [])"},{"line_number":114,"context_line":"        for inventory in additional_inventories:"},{"line_number":115,"context_line":"            inventory_conflicts \u003d [key for key in inventory"},{"line_number":116,"context_line":"                                   if not key.startswith(\"CUSTOM_\")]"},{"line_number":117,"context_line":"            if inventory_conflicts:"},{"line_number":118,"context_line":"                # NOTE(dustinc): per spec, fail if we have non-CUSTOM_*"},{"line_number":119,"context_line":"                #   resource class names"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_9e35b8aa","line":116,"range":{"start_line":116,"start_character":42,"end_line":116,"end_character":67},"updated":"2019-09-03 22:35:28.000000000","message":"likewise\n\n orc.is_custom(key)","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":113,"context_line":"            provider.get(\"inventories\", {}).get(\"additional\", [])"},{"line_number":114,"context_line":"        for inventory in additional_inventories:"},{"line_number":115,"context_line":"            inventory_conflicts \u003d [key for key in inventory"},{"line_number":116,"context_line":"                                   if not key.startswith(\"CUSTOM_\")]"},{"line_number":117,"context_line":"            if inventory_conflicts:"},{"line_number":118,"context_line":"                # NOTE(dustinc): per spec, fail if we have non-CUSTOM_*"},{"line_number":119,"context_line":"                #   resource class names"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_3eecc127","line":116,"range":{"start_line":116,"start_character":42,"end_line":116,"end_character":67},"in_reply_to":"7faddb67_9e35b8aa","updated":"2019-09-04 05:35:14.000000000","message":"Done","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":152,"context_line":"    return yaml_file"},{"line_number":153,"context_line":""},{"line_number":154,"context_line":""},{"line_number":155,"context_line":"def get_custom_resources(provider_config_dir):"},{"line_number":156,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":157,"context_line":"    and merges them into a single dict while checking for name conflicts."},{"line_number":158,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_fef94cc4","line":155,"range":{"start_line":155,"start_character":4,"end_line":155,"end_character":24},"updated":"2019-09-03 22:35:28.000000000","message":"get_provider_configs would be a better name","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":152,"context_line":"    return yaml_file"},{"line_number":153,"context_line":""},{"line_number":154,"context_line":""},{"line_number":155,"context_line":"def get_custom_resources(provider_config_dir):"},{"line_number":156,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":157,"context_line":"    and merges them into a single dict while checking for name conflicts."},{"line_number":158,"context_line":""}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_bef3d1e6","line":155,"range":{"start_line":155,"start_character":4,"end_line":155,"end_character":24},"in_reply_to":"7faddb67_fef94cc4","updated":"2019-09-04 05:35:14.000000000","message":"Done","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":154,"context_line":""},{"line_number":155,"context_line":"def get_custom_resources(provider_config_dir):"},{"line_number":156,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":157,"context_line":"    and merges them into a single dict while checking for name conflicts."},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    :param provider_config_dir: Path to a directory containing provider config"},{"line_number":160,"context_line":"        files to be loaded."}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_7e279c64","line":157,"range":{"start_line":157,"start_character":45,"end_line":157,"end_character":72},"updated":"2019-09-03 22:35:28.000000000","message":"other validation is also being done, and it will be easy for this docstring to get out of sync with _verify_providers, so this might as well just say something generic about doing extra checks","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":154,"context_line":""},{"line_number":155,"context_line":"def get_custom_resources(provider_config_dir):"},{"line_number":156,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":157,"context_line":"    and merges them into a single dict while checking for name conflicts."},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    :param provider_config_dir: Path to a directory containing provider config"},{"line_number":160,"context_line":"        files to be loaded."}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_5efe5daf","line":157,"range":{"start_line":157,"start_character":45,"end_line":157,"end_character":72},"in_reply_to":"7faddb67_7e279c64","updated":"2019-09-04 05:35:14.000000000","message":"Done","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    :param provider_config_dir: Path to a directory containing provider config"},{"line_number":160,"context_line":"        files to be loaded."},{"line_number":161,"context_line":"    :raise: OSError if unable to read provider config directory"},{"line_number":162,"context_line":"    :return: A dict representing the contents of all files in the path keyed by"},{"line_number":163,"context_line":"        file name"},{"line_number":164,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_5e78a07c","line":161,"range":{"start_line":161,"start_character":5,"end_line":161,"end_character":10},"updated":"2019-09-03 22:35:28.000000000","message":"As written, this can also raise various exceptions from _parse_provider_yaml and _verify_providers.\n\n...but continuing the discussion from above, I don\u0027t think it should do that. I think by the time we get out of this method, we need to have accumulated all possible exceptions - including OSError, JSON validation errors, and post-schema validation stuff - into a single rollup exception (or at least common unique base class thereof) that the caller can trap and react to in a consistent fashion.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":171,"context_line":"                  provider_config_dir)"},{"line_number":172,"context_line":"        raise"},{"line_number":173,"context_line":""},{"line_number":174,"context_line":"    custom_resources \u003d {}"},{"line_number":175,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":176,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":177,"context_line":"        provider_config \u003d _verify_providers(provider_config)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_3ef4c4ce","line":174,"range":{"start_line":174,"start_character":4,"end_line":174,"end_character":20},"updated":"2019-09-03 22:35:28.000000000","message":"provider_configs would be a better name","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":171,"context_line":"                  provider_config_dir)"},{"line_number":172,"context_line":"        raise"},{"line_number":173,"context_line":""},{"line_number":174,"context_line":"    custom_resources \u003d {}"},{"line_number":175,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":176,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":177,"context_line":"        provider_config \u003d _verify_providers(provider_config)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_de232d57","line":174,"range":{"start_line":174,"start_character":4,"end_line":174,"end_character":20},"in_reply_to":"7faddb67_3ef4c4ce","updated":"2019-09-04 05:35:14.000000000","message":"Done","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":177,"context_line":"        provider_config \u003d _verify_providers(provider_config)"},{"line_number":178,"context_line":"        # NOTE(dustinc): Not sure of the return format quite yet.."},{"line_number":179,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":180,"context_line":"            custom_resources[os.path.basename(provider_config_file)] \u003d provider"},{"line_number":181,"context_line":"    return custom_resources"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_1ef788d6","line":180,"range":{"start_line":180,"start_character":29,"end_line":180,"end_character":67},"updated":"2019-09-03 22:35:28.000000000","message":"Any particular reason we need to preserve this name here? Why isn\u0027t custom_resources just a list?","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"9f93294a586cc7d394f6a0d2ee5070e436d67871","unresolved":false,"context_lines":[{"line_number":177,"context_line":"        provider_config \u003d _verify_providers(provider_config)"},{"line_number":178,"context_line":"        # NOTE(dustinc): Not sure of the return format quite yet.."},{"line_number":179,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":180,"context_line":"            custom_resources[os.path.basename(provider_config_file)] \u003d provider"},{"line_number":181,"context_line":"    return custom_resources"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_fe462ca7","line":180,"range":{"start_line":180,"start_character":29,"end_line":180,"end_character":67},"in_reply_to":"7faddb67_1ef788d6","updated":"2019-09-03 23:07:39.000000000","message":"oic, so the caller can be helpful when spitting out messages.\n\nconsider injecting the filename into the config data somewhere (preferably in a way that it can\u0027t conflict with future schema changes) and using an ordered list here instead.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"3c73111e29f54f18a80590082f4892ff9d0c8f5b","unresolved":false,"context_lines":[{"line_number":177,"context_line":"        provider_config \u003d _verify_providers(provider_config)"},{"line_number":178,"context_line":"        # NOTE(dustinc): Not sure of the return format quite yet.."},{"line_number":179,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":180,"context_line":"            custom_resources[os.path.basename(provider_config_file)] \u003d provider"},{"line_number":181,"context_line":"    return custom_resources"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_5ec5fd5a","line":180,"range":{"start_line":180,"start_character":29,"end_line":180,"end_character":67},"in_reply_to":"7faddb67_fe462ca7","updated":"2019-09-04 05:35:14.000000000","message":"Yeah, it was only to make log messages more useful. I updated this to return a list and included the source file name in the provider itself.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":96,"context_line":"    for provider in providers:"},{"line_number":97,"context_line":"        # Check that the identification method is known since"},{"line_number":98,"context_line":"        # the schema only requires that some property be present"},{"line_number":99,"context_line":"        pid \u003d provider[\"identification\"]"},{"line_number":100,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":101,"context_line":"        if not provider_id:"},{"line_number":102,"context_line":"            message \u003d _(\"The provider does not have known identification.\")"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_a273cb4d","line":99,"range":{"start_line":99,"start_character":7,"end_line":99,"end_character":40},"updated":"2019-10-11 09:45:15.000000000","message":"check for null?","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"6c1b7c2e120ded0867a3f279d09fa2fea91ff370","unresolved":false,"context_lines":[{"line_number":96,"context_line":"    for provider in providers:"},{"line_number":97,"context_line":"        # Check that the identification method is known since"},{"line_number":98,"context_line":"        # the schema only requires that some property be present"},{"line_number":99,"context_line":"        pid \u003d provider[\"identification\"]"},{"line_number":100,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":101,"context_line":"        if not provider_id:"},{"line_number":102,"context_line":"            message \u003d _(\"The provider does not have known identification.\")"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_9eb56d35","line":99,"range":{"start_line":99,"start_character":7,"end_line":99,"end_character":40},"in_reply_to":"3fa7e38b_a273cb4d","updated":"2019-10-17 19:10:50.000000000","message":"can\u0027t be null, or it would have failed schema check","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":97,"context_line":"        # Check that the identification method is known since"},{"line_number":98,"context_line":"        # the schema only requires that some property be present"},{"line_number":99,"context_line":"        pid \u003d provider[\"identification\"]"},{"line_number":100,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":101,"context_line":"        if not provider_id:"},{"line_number":102,"context_line":"            message \u003d _(\"The provider does not have known identification.\")"},{"line_number":103,"context_line":"            raise ProviderConfigException(message)"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_82948f38","line":100,"range":{"start_line":100,"start_character":8,"end_line":100,"end_character":56},"updated":"2019-10-11 09:45:15.000000000","message":"Check if both are not provided","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"6c1b7c2e120ded0867a3f279d09fa2fea91ff370","unresolved":false,"context_lines":[{"line_number":97,"context_line":"        # Check that the identification method is known since"},{"line_number":98,"context_line":"        # the schema only requires that some property be present"},{"line_number":99,"context_line":"        pid \u003d provider[\"identification\"]"},{"line_number":100,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":101,"context_line":"        if not provider_id:"},{"line_number":102,"context_line":"            message \u003d _(\"The provider does not have known identification.\")"},{"line_number":103,"context_line":"            raise ProviderConfigException(message)"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_beedc9b8","line":100,"range":{"start_line":100,"start_character":8,"end_line":100,"end_character":56},"in_reply_to":"3fa7e38b_82948f38","updated":"2019-10-17 19:10:50.000000000","message":"What do you mean? If neither is provided, we fail below; if both are provided, we fail at the schema.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":104,"context_line":""},{"line_number":105,"context_line":"        # Ensure the provider ID has not been processed already"},{"line_number":106,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":107,"context_line":"            message \u003d _(\"Provider %s is defined twice.\") % provider_id"},{"line_number":108,"context_line":"            raise ProviderConfigException(message)"},{"line_number":109,"context_line":"        processed_provider_ids.append(provider_id)"},{"line_number":110,"context_line":""},{"line_number":111,"context_line":"        # Check that traits are custom"},{"line_number":112,"context_line":"        additional_traits \u003d set(provider.get(\"traits\", {}).get("}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_423c57e0","line":109,"range":{"start_line":107,"start_character":0,"end_line":109,"end_character":50},"updated":"2019-10-11 09:45:15.000000000","message":"@Eric, for simplicity, should this be a warning and we ignore let the first definition take precedence?\n\nI think we cannot or must not go back on the spec.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"6c1b7c2e120ded0867a3f279d09fa2fea91ff370","unresolved":false,"context_lines":[{"line_number":104,"context_line":""},{"line_number":105,"context_line":"        # Ensure the provider ID has not been processed already"},{"line_number":106,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":107,"context_line":"            message \u003d _(\"Provider %s is defined twice.\") % provider_id"},{"line_number":108,"context_line":"            raise ProviderConfigException(message)"},{"line_number":109,"context_line":"        processed_provider_ids.append(provider_id)"},{"line_number":110,"context_line":""},{"line_number":111,"context_line":"        # Check that traits are custom"},{"line_number":112,"context_line":"        additional_traits \u003d set(provider.get(\"traits\", {}).get("}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_7edf510c","line":109,"range":{"start_line":107,"start_character":0,"end_line":109,"end_character":50},"in_reply_to":"3fa7e38b_423c57e0","updated":"2019-10-17 19:10:50.000000000","message":"No, this was something we discussed and decided in the spec [1] (we should propose a spec update to clarify this).\n\n[1] https://review.opendev.org/#/c/612497/6/specs/train/approved/provider-config-file.rst@212","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":111,"context_line":"        # Check that traits are custom"},{"line_number":112,"context_line":"        additional_traits \u003d set(provider.get(\"traits\", {}).get("},{"line_number":113,"context_line":"            \"additional\", []))"},{"line_number":114,"context_line":"        trait_conflicts \u003d {trait for trait in additional_traits"},{"line_number":115,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":116,"context_line":"        if trait_conflicts:"},{"line_number":117,"context_line":"            message \u003d _(\u0027Invalid traits: %s\u0027) % trait_conflicts"},{"line_number":118,"context_line":"            raise ProviderConfigException(message)"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_026adf18","line":115,"range":{"start_line":114,"start_character":0,"end_line":115,"end_character":61},"updated":"2019-10-11 09:45:15.000000000","message":"What about comparing with pre-exising custom traits, the ones created via API/CLI.\n\nIf compute is restarted with the same file, without clearing traits/inventory already sent from provider config, we are overwriting.\n\nLooks like users should manually remove traits/inventories if they want to undo the effects of the file?","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"6c1b7c2e120ded0867a3f279d09fa2fea91ff370","unresolved":false,"context_lines":[{"line_number":111,"context_line":"        # Check that traits are custom"},{"line_number":112,"context_line":"        additional_traits \u003d set(provider.get(\"traits\", {}).get("},{"line_number":113,"context_line":"            \"additional\", []))"},{"line_number":114,"context_line":"        trait_conflicts \u003d {trait for trait in additional_traits"},{"line_number":115,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":116,"context_line":"        if trait_conflicts:"},{"line_number":117,"context_line":"            message \u003d _(\u0027Invalid traits: %s\u0027) % trait_conflicts"},{"line_number":118,"context_line":"            raise ProviderConfigException(message)"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_fe59015b","line":115,"range":{"start_line":114,"start_character":0,"end_line":115,"end_character":61},"in_reply_to":"3fa7e38b_026adf18","updated":"2019-10-17 19:10:50.000000000","message":"This is basically the point of the whole exercise. This feature will ensure that the traits in the file get set on the provider, regardless of what came from elsewhere. If you try to manually remove such a trait from the provider, the resource tracker will put it back on the next periodic.\n\n(We limited to custom traits for the current release so we could defer the decision of what to do about traits that nova-compute would otherwise *de*assert, which currently only happens with standard traits.)","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":122,"context_line":"            \"additional\", [])"},{"line_number":123,"context_line":"        for inventory in additional_inventories:"},{"line_number":124,"context_line":"            # TODO(dustinc): Find a better way to do this."},{"line_number":125,"context_line":"            inventory_conflicts \u003d [key for key in inventory"},{"line_number":126,"context_line":"                                   if not key.startswith(\u0027CUSTOM_\u0027)]"},{"line_number":127,"context_line":"            if inventory_conflicts:"},{"line_number":128,"context_line":"                message \u003d _(\"Invalid custom resource class name: %s\""},{"line_number":129,"context_line":"                            ) % inventory_conflicts"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_c24847b4","line":126,"range":{"start_line":125,"start_character":0,"end_line":126,"end_character":68},"updated":"2019-10-11 09:45:15.000000000","message":"Again, we might be ignoring CUSTOM_INVENTORIES created from API/CLI\n\nAlso what are we comparing against here, besides ruling out keys not starting with CUSTOM","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"6c1b7c2e120ded0867a3f279d09fa2fea91ff370","unresolved":false,"context_lines":[{"line_number":122,"context_line":"            \"additional\", [])"},{"line_number":123,"context_line":"        for inventory in additional_inventories:"},{"line_number":124,"context_line":"            # TODO(dustinc): Find a better way to do this."},{"line_number":125,"context_line":"            inventory_conflicts \u003d [key for key in inventory"},{"line_number":126,"context_line":"                                   if not key.startswith(\u0027CUSTOM_\u0027)]"},{"line_number":127,"context_line":"            if inventory_conflicts:"},{"line_number":128,"context_line":"                message \u003d _(\"Invalid custom resource class name: %s\""},{"line_number":129,"context_line":"                            ) % inventory_conflicts"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_b9d403eb","line":126,"range":{"start_line":125,"start_character":0,"end_line":126,"end_character":68},"in_reply_to":"3fa7e38b_c24847b4","updated":"2019-10-17 19:10:50.000000000","message":"Likewise: we\u0027re only positively asserting inventories, not allowing removal of any. In this case, since it\u0027s inventory, it\u0027s more than just binary -- which again is the point of the exercise: to override anything set from elsewhere, including by the driver. If there\u0027s an inventory that\u0027s already on the provider, we\u0027ll overwrite it with whatever values come from the file. And this allows us to use the same logic to account for a) inventories set up by the compute driver and b) inventories we set via this file on the last periodic: we just replace in either case.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":185,"context_line":"        provider_config_files \u003d glob.glob("},{"line_number":186,"context_line":"            os.path.join(provider_config_dir, \"*.yaml\"))"},{"line_number":187,"context_line":"        provider_config_files.sort()"},{"line_number":188,"context_line":"        processed_provider_ids \u003d []"},{"line_number":189,"context_line":"    except OSError as e:"},{"line_number":190,"context_line":"        message \u003d _(\"Failed to list provider config directory: %s\""},{"line_number":191,"context_line":"                    ) % provider_config_dir"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_025dff45","line":188,"range":{"start_line":188,"start_character":0,"end_line":188,"end_character":35},"updated":"2019-10-11 09:45:15.000000000","message":"What is the scope of this variable? Assuming there are no compile errors when you refer it outside the try block.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"6c1b7c2e120ded0867a3f279d09fa2fea91ff370","unresolved":false,"context_lines":[{"line_number":185,"context_line":"        provider_config_files \u003d glob.glob("},{"line_number":186,"context_line":"            os.path.join(provider_config_dir, \"*.yaml\"))"},{"line_number":187,"context_line":"        provider_config_files.sort()"},{"line_number":188,"context_line":"        processed_provider_ids \u003d []"},{"line_number":189,"context_line":"    except OSError as e:"},{"line_number":190,"context_line":"        message \u003d _(\"Failed to list provider config directory: %s\""},{"line_number":191,"context_line":"                    ) % provider_config_dir"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_99f02794","line":188,"range":{"start_line":188,"start_character":0,"end_line":188,"end_character":35},"in_reply_to":"3fa7e38b_025dff45","updated":"2019-10-17 19:10:50.000000000","message":"since L192 raises, this is guaranteed to be initialized if we get past the try/except. That said, it wouldn\u0027t hurt to initialize it above the try:.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":191,"context_line":"                    ) % provider_config_dir"},{"line_number":192,"context_line":"        raise ProviderConfigException(message)"},{"line_number":193,"context_line":""},{"line_number":194,"context_line":"    provider_configs \u003d []"},{"line_number":195,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":196,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":197,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_c2004705","line":194,"range":{"start_line":194,"start_character":4,"end_line":194,"end_character":20},"updated":"2019-10-11 09:45:15.000000000","message":"This list is not updated in the for loop below.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"ad5d9d1392acb0a7b4fa89bc729dc035d7c2a9dd","unresolved":false,"context_lines":[{"line_number":191,"context_line":"                    ) % provider_config_dir"},{"line_number":192,"context_line":"        raise ProviderConfigException(message)"},{"line_number":193,"context_line":""},{"line_number":194,"context_line":"    provider_configs \u003d []"},{"line_number":195,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":196,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":197,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_3501536b","line":194,"range":{"start_line":194,"start_character":4,"end_line":194,"end_character":20},"in_reply_to":"3fa7e38b_c2004705","updated":"2019-10-11 10:28:34.000000000","message":"Saw line 201. Please ignore.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":193,"context_line":""},{"line_number":194,"context_line":"    provider_configs \u003d []"},{"line_number":195,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":196,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":197,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"},{"line_number":198,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":199,"context_line":"            provider[\u0027_source_file\u0027] \u003d os.path.basename(provider_config_file)"},{"line_number":200,"context_line":"            provider_configs.append(provider)"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_a22aeb8d","line":197,"range":{"start_line":196,"start_character":8,"end_line":197,"end_character":74},"updated":"2019-10-11 09:45:15.000000000","message":"try catch missing for both these functions. These would lead to abort since we follow all or nothing rule","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"6c1b7c2e120ded0867a3f279d09fa2fea91ff370","unresolved":false,"context_lines":[{"line_number":193,"context_line":""},{"line_number":194,"context_line":"    provider_configs \u003d []"},{"line_number":195,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":196,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":197,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"},{"line_number":198,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":199,"context_line":"            provider[\u0027_source_file\u0027] \u003d os.path.basename(provider_config_file)"},{"line_number":200,"context_line":"            provider_configs.append(provider)"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_3937b350","line":197,"range":{"start_line":196,"start_character":8,"end_line":197,"end_character":74},"in_reply_to":"3fa7e38b_a22aeb8d","updated":"2019-10-17 19:10:50.000000000","message":"Yup, that\u0027s by design iiuc: we want errors (documented on L179) from these to bubble up to the caller.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":195,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":196,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":197,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"},{"line_number":198,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":199,"context_line":"            provider[\u0027_source_file\u0027] \u003d os.path.basename(provider_config_file)"},{"line_number":200,"context_line":"            provider_configs.append(provider)"},{"line_number":201,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_f50f3b2b","line":198,"range":{"start_line":198,"start_character":5,"end_line":198,"end_character":61},"updated":"2019-10-11 09:45:15.000000000","message":"Could be merged with validate block to avoid additional o(n) unless we to separate by functionality","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":195,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":196,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":197,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"},{"line_number":198,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":199,"context_line":"            provider[\u0027_source_file\u0027] \u003d os.path.basename(provider_config_file)"},{"line_number":200,"context_line":"            provider_configs.append(provider)"},{"line_number":201,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_e20d433e","line":198,"range":{"start_line":198,"start_character":24,"end_line":198,"end_character":39},"updated":"2019-10-11 09:45:15.000000000","message":"should this be provider_configs?","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"ad5d9d1392acb0a7b4fa89bc729dc035d7c2a9dd","unresolved":false,"context_lines":[{"line_number":195,"context_line":"    for provider_config_file in provider_config_files:"},{"line_number":196,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":197,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"},{"line_number":198,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":199,"context_line":"            provider[\u0027_source_file\u0027] \u003d os.path.basename(provider_config_file)"},{"line_number":200,"context_line":"            provider_configs.append(provider)"},{"line_number":201,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_55064f88","line":198,"range":{"start_line":198,"start_character":5,"end_line":198,"end_character":61},"in_reply_to":"3fa7e38b_f50f3b2b","updated":"2019-10-11 10:28:34.000000000","message":"Just noticed line 201, ignore these. Probably rename provider_config variable to indicate it is per file.","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":93,"context_line":"    :param processed_provider_ids: A list of previously processed provider ids"},{"line_number":94,"context_line":"        to check for conflicts and update with new provider ids."},{"line_number":95,"context_line":"    :raise: ProviderConfigException if provider id is missing, a provider id"},{"line_number":96,"context_line":"        is defined twice, or if a resource class name is invalid"},{"line_number":97,"context_line":"    \"\"\""},{"line_number":98,"context_line":"    providers \u003d yaml_file.get(\"providers\", [])"},{"line_number":99,"context_line":"    for provider in providers:"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_b14ac558","line":96,"range":{"start_line":96,"start_character":34,"end_line":96,"end_character":53},"updated":"2019-10-18 21:33:24.000000000","message":"or trait","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"978e27e659e0513f9fe79331f7835e017761e861","unresolved":false,"context_lines":[{"line_number":93,"context_line":"    :param processed_provider_ids: A list of previously processed provider ids"},{"line_number":94,"context_line":"        to check for conflicts and update with new provider ids."},{"line_number":95,"context_line":"    :raise: ProviderConfigException if provider id is missing, a provider id"},{"line_number":96,"context_line":"        is defined twice, or if a resource class name is invalid"},{"line_number":97,"context_line":"    \"\"\""},{"line_number":98,"context_line":"    providers \u003d yaml_file.get(\"providers\", [])"},{"line_number":99,"context_line":"    for provider in providers:"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_a74a8758","line":96,"range":{"start_line":96,"start_character":34,"end_line":96,"end_character":53},"in_reply_to":"3fa7e38b_b14ac558","updated":"2019-10-19 01:17:54.000000000","message":"Done","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":105,"context_line":"            message \u003d _(\"The provider does not have known identification.\")"},{"line_number":106,"context_line":"            raise ProviderConfigException(message)"},{"line_number":107,"context_line":""},{"line_number":108,"context_line":"        # Ensure the provider ID has not been processed already"},{"line_number":109,"context_line":"        if provider_id in processed_provider_ids:"},{"line_number":110,"context_line":"            message \u003d _(\"Provider %s is defined twice.\") % provider_id"},{"line_number":111,"context_line":"            raise ProviderConfigException(message)"},{"line_number":112,"context_line":"        processed_provider_ids.append(provider_id)"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"        # Check that traits are custom"},{"line_number":115,"context_line":"        additional_traits \u003d set(provider.get(\"traits\", {}).get("}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_5164b1e5","line":112,"range":{"start_line":108,"start_character":0,"end_line":112,"end_character":50},"updated":"2019-10-18 21:33:24.000000000","message":"Need to come back to this, but it might not be worth doing here, since it won\u0027t detect a conflict between e.g. a provider\u0027s uuid and the same provider\u0027s name. And since we have to check that via placement data anyway, why duplicate the effort?\n\nNote for that, though: what do we do if we see $COMPUTE_NODE and also a UUID for a compute node? In the ironic case, that would be valid, the intent being \"do X with all my $COMPUTE_NODEs, except these specific ones which should do Y\". But for non-ironic it would almost certainly be bogus. Further thought needed.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":117,"context_line":"        trait_conflicts \u003d {trait for trait in additional_traits"},{"line_number":118,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":119,"context_line":"        if trait_conflicts:"},{"line_number":120,"context_line":"            message \u003d _(\u0027Invalid traits: %s\u0027) % trait_conflicts"},{"line_number":121,"context_line":"            raise ProviderConfigException(message)"},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"        # Check that resource classes are custom"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_f1603dd2","line":120,"range":{"start_line":120,"start_character":25,"end_line":120,"end_character":39},"updated":"2019-10-18 21:33:24.000000000","message":"This should mention that it\u0027s because only custom traits are allowed.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"978e27e659e0513f9fe79331f7835e017761e861","unresolved":false,"context_lines":[{"line_number":117,"context_line":"        trait_conflicts \u003d {trait for trait in additional_traits"},{"line_number":118,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":119,"context_line":"        if trait_conflicts:"},{"line_number":120,"context_line":"            message \u003d _(\u0027Invalid traits: %s\u0027) % trait_conflicts"},{"line_number":121,"context_line":"            raise ProviderConfigException(message)"},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"        # Check that resource classes are custom"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_473b93c7","line":120,"range":{"start_line":120,"start_character":25,"end_line":120,"end_character":39},"in_reply_to":"3fa7e38b_f1603dd2","updated":"2019-10-19 01:17:54.000000000","message":"Done","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":124,"context_line":"        additional_inventories \u003d provider.get(\"inventories\", {}).get("},{"line_number":125,"context_line":"            \"additional\", [])"},{"line_number":126,"context_line":"        for inventory in additional_inventories:"},{"line_number":127,"context_line":"            # TODO(dustinc): Find a better way to do this."},{"line_number":128,"context_line":"            inventory_conflicts \u003d [key for key in inventory"},{"line_number":129,"context_line":"                                   if not key.startswith(\u0027CUSTOM_\u0027)]"},{"line_number":130,"context_line":"            if inventory_conflicts:"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_91a7890c","line":127,"range":{"start_line":127,"start_character":0,"end_line":127,"end_character":58},"updated":"2019-10-18 21:33:24.000000000","message":"os_resource_classes.is_custom()","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"978e27e659e0513f9fe79331f7835e017761e861","unresolved":false,"context_lines":[{"line_number":124,"context_line":"        additional_inventories \u003d provider.get(\"inventories\", {}).get("},{"line_number":125,"context_line":"            \"additional\", [])"},{"line_number":126,"context_line":"        for inventory in additional_inventories:"},{"line_number":127,"context_line":"            # TODO(dustinc): Find a better way to do this."},{"line_number":128,"context_line":"            inventory_conflicts \u003d [key for key in inventory"},{"line_number":129,"context_line":"                                   if not key.startswith(\u0027CUSTOM_\u0027)]"},{"line_number":130,"context_line":"            if inventory_conflicts:"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_8743cb13","line":127,"range":{"start_line":127,"start_character":0,"end_line":127,"end_character":58},"in_reply_to":"3fa7e38b_91a7890c","updated":"2019-10-19 01:17:54.000000000","message":"Done","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":128,"context_line":"            inventory_conflicts \u003d [key for key in inventory"},{"line_number":129,"context_line":"                                   if not key.startswith(\u0027CUSTOM_\u0027)]"},{"line_number":130,"context_line":"            if inventory_conflicts:"},{"line_number":131,"context_line":"                message \u003d _(\"Invalid custom resource class name: %s\""},{"line_number":132,"context_line":"                            ) % inventory_conflicts"},{"line_number":133,"context_line":"                raise ProviderConfigException(message)"},{"line_number":134,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_b1816550","line":131,"range":{"start_line":131,"start_character":29,"end_line":131,"end_character":67},"updated":"2019-10-18 21:33:24.000000000","message":"This should mention that it\u0027s because only custom resource classes are allowed.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"978e27e659e0513f9fe79331f7835e017761e861","unresolved":false,"context_lines":[{"line_number":128,"context_line":"            inventory_conflicts \u003d [key for key in inventory"},{"line_number":129,"context_line":"                                   if not key.startswith(\u0027CUSTOM_\u0027)]"},{"line_number":130,"context_line":"            if inventory_conflicts:"},{"line_number":131,"context_line":"                message \u003d _(\"Invalid custom resource class name: %s\""},{"line_number":132,"context_line":"                            ) % inventory_conflicts"},{"line_number":133,"context_line":"                raise ProviderConfigException(message)"},{"line_number":134,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_2748d72c","line":131,"range":{"start_line":131,"start_character":29,"end_line":131,"end_character":67},"in_reply_to":"3fa7e38b_b1816550","updated":"2019-10-19 01:17:54.000000000","message":"Done","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":188,"context_line":""},{"line_number":189,"context_line":"    :param provider_config_dir: Path to a directory containing provider config"},{"line_number":190,"context_line":"        files to be loaded."},{"line_number":191,"context_line":"    :raise: ProviderConfigException if unable to read provider config directory"},{"line_number":192,"context_line":"    :return: A list with the parsed and validated contents of all files in the"},{"line_number":193,"context_line":"    provided dir. Each item on the list will include the source file name in"},{"line_number":194,"context_line":"    the key _source_file."}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_31da5579","line":191,"range":{"start_line":191,"start_character":0,"end_line":191,"end_character":79},"updated":"2019-10-18 21:33:24.000000000","message":"Or any of the loading/validation errors. Should probably list those out. (If they weren\u0027t private, I would say you could just reference the docstrings for _parse_provider_yaml et al, but this is the first public touchpoint, so it should be complete.)","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"978e27e659e0513f9fe79331f7835e017761e861","unresolved":false,"context_lines":[{"line_number":188,"context_line":""},{"line_number":189,"context_line":"    :param provider_config_dir: Path to a directory containing provider config"},{"line_number":190,"context_line":"        files to be loaded."},{"line_number":191,"context_line":"    :raise: ProviderConfigException if unable to read provider config directory"},{"line_number":192,"context_line":"    :return: A list with the parsed and validated contents of all files in the"},{"line_number":193,"context_line":"    provided dir. Each item on the list will include the source file name in"},{"line_number":194,"context_line":"    the key _source_file."}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_07435bb1","line":191,"range":{"start_line":191,"start_character":0,"end_line":191,"end_character":79},"in_reply_to":"3fa7e38b_31da5579","updated":"2019-10-19 01:17:54.000000000","message":"Done","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"a84c72753f50dd3aa5fb0983d8436e971883a4d7","unresolved":false,"context_lines":[{"line_number":194,"context_line":"    the key _source_file."},{"line_number":195,"context_line":"    \"\"\""},{"line_number":196,"context_line":"    try:"},{"line_number":197,"context_line":"        provider_config_files \u003d glob.glob("},{"line_number":198,"context_line":"            os.path.join(provider_config_dir, \"*.yaml\"))"},{"line_number":199,"context_line":"        provider_config_files.sort()"},{"line_number":200,"context_line":"        processed_provider_ids \u003d []"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_4cd73a51","line":197,"range":{"start_line":197,"start_character":32,"end_line":197,"end_character":41},"updated":"2019-10-18 21:48:46.000000000","message":"The spec says we\u0027ll sort the files, but glob is arbitrarily ordered by default [1].\n\nThat said, if we\u0027re strictly forbidding dups, I\u0027m not sure it really matters what order we process the files in. If we decide that\u0027s the case, we should update the spec [2] and adjust the conf opt doc [3] accordingly.\n\n[1] https://docs.python.org/3/library/glob.html\n[2] http://specs.openstack.org/openstack/nova-specs/specs/ussuri/approved/provider-config-file.html#provider-config-consumption-from-nova\n[3] https://review.opendev.org/#/c/676522/21/nova/conf/compute.py@310","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"978e27e659e0513f9fe79331f7835e017761e861","unresolved":false,"context_lines":[{"line_number":194,"context_line":"    the key _source_file."},{"line_number":195,"context_line":"    \"\"\""},{"line_number":196,"context_line":"    try:"},{"line_number":197,"context_line":"        provider_config_files \u003d glob.glob("},{"line_number":198,"context_line":"            os.path.join(provider_config_dir, \"*.yaml\"))"},{"line_number":199,"context_line":"        provider_config_files.sort()"},{"line_number":200,"context_line":"        processed_provider_ids \u003d []"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_e71e3fba","line":197,"range":{"start_line":197,"start_character":32,"end_line":197,"end_character":41},"in_reply_to":"3fa7e38b_4cd73a51","updated":"2019-10-19 01:17:54.000000000","message":"Sorted at line 199.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e9a9ad165eaea571d5f18cd8f54977dd63e59fdf","unresolved":false,"context_lines":[{"line_number":194,"context_line":"    the key _source_file."},{"line_number":195,"context_line":"    \"\"\""},{"line_number":196,"context_line":"    try:"},{"line_number":197,"context_line":"        provider_config_files \u003d glob.glob("},{"line_number":198,"context_line":"            os.path.join(provider_config_dir, \"*.yaml\"))"},{"line_number":199,"context_line":"        provider_config_files.sort()"},{"line_number":200,"context_line":"        processed_provider_ids \u003d []"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_c9f3b108","line":197,"range":{"start_line":197,"start_character":32,"end_line":197,"end_character":41},"in_reply_to":"3fa7e38b_e71e3fba","updated":"2019-10-25 20:13:34.000000000","message":"d\u0027oh","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":197,"context_line":"        provider_config_files \u003d glob.glob("},{"line_number":198,"context_line":"            os.path.join(provider_config_dir, \"*.yaml\"))"},{"line_number":199,"context_line":"        provider_config_files.sort()"},{"line_number":200,"context_line":"        processed_provider_ids \u003d []"},{"line_number":201,"context_line":"    except OSError as e:"},{"line_number":202,"context_line":"        message \u003d _(\"Failed to list provider config directory: %s\""},{"line_number":203,"context_line":"                    ) % provider_config_dir"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_f1e35d33","line":200,"range":{"start_line":200,"start_character":33,"end_line":200,"end_character":35},"updated":"2019-10-18 21:33:24.000000000","message":"nit: make this a set so searches are O(1)\n\n[Later] Or make provider_configs a dict, keyed by identifier, and do the duplicate check with `in`, and then you can get rid of this.\n\nThat\u0027s assuming we keep the dup check here.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":201,"context_line":"    except OSError as e:"},{"line_number":202,"context_line":"        message \u003d _(\"Failed to list provider config directory: %s\""},{"line_number":203,"context_line":"                    ) % provider_config_dir"},{"line_number":204,"context_line":"        raise ProviderConfigException(message)"},{"line_number":205,"context_line":""},{"line_number":206,"context_line":"    provider_configs \u003d []"},{"line_number":207,"context_line":"    for provider_config_file in provider_config_files:"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_118dd9d2","line":204,"range":{"start_line":204,"start_character":14,"end_line":204,"end_character":46},"updated":"2019-10-18 21:33:24.000000000","message":"Is there a test for this?","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8f2ba9683c5ad5e27165c0d4eac32db8dcc79e94","unresolved":false,"context_lines":[{"line_number":201,"context_line":"    except OSError as e:"},{"line_number":202,"context_line":"        message \u003d _(\"Failed to list provider config directory: %s\""},{"line_number":203,"context_line":"                    ) % provider_config_dir"},{"line_number":204,"context_line":"        raise ProviderConfigException(message)"},{"line_number":205,"context_line":""},{"line_number":206,"context_line":"    provider_configs \u003d []"},{"line_number":207,"context_line":"    for provider_config_file in provider_config_files:"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_f9c30689","line":204,"range":{"start_line":204,"start_character":14,"end_line":204,"end_character":46},"in_reply_to":"3fa7e38b_118dd9d2","updated":"2019-10-24 16:55:06.000000000","message":"This is actually no longer needed, refactored out and updated existing test to cover.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":208,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":209,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"},{"line_number":210,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":211,"context_line":"            provider[\u0027_source_file\u0027] \u003d os.path.basename(provider_config_file)"},{"line_number":212,"context_line":"            provider_configs.append(provider)"},{"line_number":213,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_11bab909","line":211,"range":{"start_line":211,"start_character":21,"end_line":211,"end_character":35},"updated":"2019-10-18 21:33:24.000000000","message":"Technically this is allowed by the schema and could theoretically wind up conflicting later. Probably excessively paranoid, but you could make this a forbidden key via the schema so you\u0027re guaranteed not to be overwriting something \"important\" here. Might also consider making it even more explicitly private (double underscore)?","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8f2ba9683c5ad5e27165c0d4eac32db8dcc79e94","unresolved":false,"context_lines":[{"line_number":208,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_file)"},{"line_number":209,"context_line":"        _validate_provider_config(provider_config, processed_provider_ids)"},{"line_number":210,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":211,"context_line":"            provider[\u0027_source_file\u0027] \u003d os.path.basename(provider_config_file)"},{"line_number":212,"context_line":"            provider_configs.append(provider)"},{"line_number":213,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_1c2a7ee6","line":211,"range":{"start_line":211,"start_character":21,"end_line":211,"end_character":35},"in_reply_to":"3fa7e38b_11bab909","updated":"2019-10-24 16:55:06.000000000","message":"Done","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e9a9ad165eaea571d5f18cd8f54977dd63e59fdf","unresolved":false,"context_lines":[{"line_number":121,"context_line":"        additional_inventories \u003d provider.get(\"inventories\", {}).get("},{"line_number":122,"context_line":"            \"additional\", [])"},{"line_number":123,"context_line":"        for inventory in additional_inventories:"},{"line_number":124,"context_line":"            # TODO(dustinc): Find a better way to do this."},{"line_number":125,"context_line":"            inventory_conflicts \u003d [rc for rc in inventory"},{"line_number":126,"context_line":"                                   if not os_resource_classes.is_custom(rc)]"},{"line_number":127,"context_line":"            if inventory_conflicts:"}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_8994d98c","line":124,"range":{"start_line":124,"start_character":12,"end_line":124,"end_character":58},"updated":"2019-10-25 20:13:34.000000000","message":"you can remove this TODO now.","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e9a9ad165eaea571d5f18cd8f54977dd63e59fdf","unresolved":false,"context_lines":[{"line_number":122,"context_line":"            \"additional\", [])"},{"line_number":123,"context_line":"        for inventory in additional_inventories:"},{"line_number":124,"context_line":"            # TODO(dustinc): Find a better way to do this."},{"line_number":125,"context_line":"            inventory_conflicts \u003d [rc for rc in inventory"},{"line_number":126,"context_line":"                                   if not os_resource_classes.is_custom(rc)]"},{"line_number":127,"context_line":"            if inventory_conflicts:"},{"line_number":128,"context_line":"                raise nova_exc.ProviderConfigException("}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_e9e8ed16","line":125,"range":{"start_line":125,"start_character":34,"end_line":125,"end_character":35},"updated":"2019-10-25 20:13:34.000000000","message":"nit: you used a set for traits (L113-4).","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8bdbcaaf0681b93f71fdf934d2db45063c705796","unresolved":false,"context_lines":[{"line_number":122,"context_line":"            \"additional\", [])"},{"line_number":123,"context_line":"        for inventory in additional_inventories:"},{"line_number":124,"context_line":"            # TODO(dustinc): Find a better way to do this."},{"line_number":125,"context_line":"            inventory_conflicts \u003d [rc for rc in inventory"},{"line_number":126,"context_line":"                                   if not os_resource_classes.is_custom(rc)]"},{"line_number":127,"context_line":"            if inventory_conflicts:"},{"line_number":128,"context_line":"                raise nova_exc.ProviderConfigException("}],"source_content_type":"text/x-python","patch_set":24,"id":"3fa7e38b_58fb8d14","line":125,"range":{"start_line":125,"start_character":34,"end_line":125,"end_character":35},"in_reply_to":"3fa7e38b_e9e8ed16","updated":"2019-11-05 19:05:25.000000000","message":"Done","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"aed61537a7e78972d499afdd4c1c89fbc4f37a30","unresolved":false,"context_lines":[{"line_number":196,"context_line":"    provider_configs \u003d {}"},{"line_number":197,"context_line":"    for provider_config_path in provider_config_paths:"},{"line_number":198,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_path)"},{"line_number":199,"context_line":"        _validate_provider_config(provider_config)"},{"line_number":200,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":201,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":202,"context_line":"            pid \u003d provider[\"identification\"]"}],"source_content_type":"text/x-python","patch_set":31,"id":"3fa7e38b_fcdc9f72","line":199,"range":{"start_line":199,"start_character":8,"end_line":199,"end_character":33},"updated":"2020-01-13 21:13:02.000000000","message":"Let\u0027s add the check for a no-op section (discussed at [1]) somewhere around here, and somehow use that to avoid adding the section on L207.\n\n[1] https://review.opendev.org/#/c/676522/34/nova/compute/resource_tracker.py@1742","commit_id":"cd73b4c3aaa1a49f34e551b783540f7962f95d91"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8f919f5a28a4bac830ce973f2344a170b9a5e7fc","unresolved":false,"context_lines":[{"line_number":196,"context_line":"    provider_configs \u003d {}"},{"line_number":197,"context_line":"    for provider_config_path in provider_config_paths:"},{"line_number":198,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_path)"},{"line_number":199,"context_line":"        _validate_provider_config(provider_config)"},{"line_number":200,"context_line":"        for provider in provider_config.get(\"providers\", []):"},{"line_number":201,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":202,"context_line":"            pid \u003d provider[\"identification\"]"}],"source_content_type":"text/x-python","patch_set":31,"id":"3fa7e38b_5d259bbe","line":199,"range":{"start_line":199,"start_character":8,"end_line":199,"end_character":33},"in_reply_to":"3fa7e38b_fcdc9f72","updated":"2020-01-15 02:22:29.000000000","message":"Done","commit_id":"cd73b4c3aaa1a49f34e551b783540f7962f95d91"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1bd0598a7ed54b43765cc44055449bd7ca903a73","unresolved":false,"context_lines":[{"line_number":79,"context_line":"            error\u003d\"Unable to read yaml config file: [%s]\" % path)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"def _validate_provider_config(yaml_file, provider_config_path):"},{"line_number":83,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":84,"context_line":"     performs additional checks for format and required keys."},{"line_number":85,"context_line":""}],"source_content_type":"text/x-python","patch_set":32,"id":"3fa7e38b_a8ca4c9d","line":82,"range":{"start_line":82,"start_character":41,"end_line":82,"end_character":61},"updated":"2020-01-14 21:57:18.000000000","message":"doc this (as just used for logging)","commit_id":"ad50c8f8ffddb5450443af0164762202bd679116"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1bd0598a7ed54b43765cc44055449bd7ca903a73","unresolved":false,"context_lines":[{"line_number":129,"context_line":"            LOG.warning(message)"},{"line_number":130,"context_line":"            noop_providers.append(provider)"},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"    # Remove no-op providers"},{"line_number":133,"context_line":"    for nop in noop_providers:"},{"line_number":134,"context_line":"        providers.remove(nop)"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":""},{"line_number":137,"context_line":"def _parse_provider_yaml(path):"}],"source_content_type":"text/x-python","patch_set":32,"id":"3fa7e38b_c830e8ba","line":134,"range":{"start_line":132,"start_character":0,"end_line":134,"end_character":29},"updated":"2020-01-14 21:57:18.000000000","message":"✔ we have to do it this way (or use a copy on L92) because you\u0027re not allowed to modify the thing you\u0027re iterating over","commit_id":"ad50c8f8ffddb5450443af0164762202bd679116"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"4350ad7336d51cbf6032d00c9dde4c71cb05fadb","unresolved":false,"context_lines":[{"line_number":180,"context_line":"    return yaml_file"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"# TODO(dustinc): Tests for cross-file conflict checking"},{"line_number":184,"context_line":"def get_provider_configs(provider_config_dir):"},{"line_number":185,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":186,"context_line":"    and merges them into a list while checking for a number of possible"}],"source_content_type":"text/x-python","patch_set":33,"id":"3fa7e38b_123614ea","line":183,"range":{"start_line":183,"start_character":0,"end_line":183,"end_character":55},"updated":"2020-01-16 00:10:15.000000000","message":"whoops, this does still appear to be missing.","commit_id":"a1d16c6c2e97ea2857b3868603dec62c1ab3bd5c"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"704700777218598d5767628913d1e37b68e86045","unresolved":false,"context_lines":[{"line_number":180,"context_line":"    return yaml_file"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"# TODO(dustinc): Tests for cross-file conflict checking"},{"line_number":184,"context_line":"def get_provider_configs(provider_config_dir):"},{"line_number":185,"context_line":"    \"\"\"Gathers files in the provided path and calls the parser for each file"},{"line_number":186,"context_line":"    and merges them into a list while checking for a number of possible"}],"source_content_type":"text/x-python","patch_set":33,"id":"3fa7e38b_e7a84adb","line":183,"range":{"start_line":183,"start_character":0,"end_line":183,"end_character":55},"in_reply_to":"3fa7e38b_123614ea","updated":"2020-01-16 21:49:26.000000000","message":"Done","commit_id":"a1d16c6c2e97ea2857b3868603dec62c1ab3bd5c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":81,"context_line":""},{"line_number":82,"context_line":"def _validate_provider_config(yaml_file, provider_config_path):"},{"line_number":83,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":84,"context_line":"     performs additional checks for format and required keys."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    :param yaml_file: Dict containing a provider config file"},{"line_number":87,"context_line":"    :param provider_config_path: Path to the provider config, used for logging"}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_73ebaedc","line":84,"range":{"start_line":84,"start_character":14,"end_line":84,"end_character":61},"updated":"2020-01-17 20:13:32.000000000","message":"Please note that this function has a side effect. It modifies (removes) the noop providers from the config.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"76555589b9f24f3a143cea192a1332532ab22329","unresolved":false,"context_lines":[{"line_number":81,"context_line":""},{"line_number":82,"context_line":"def _validate_provider_config(yaml_file, provider_config_path):"},{"line_number":83,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":84,"context_line":"     performs additional checks for format and required keys."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    :param yaml_file: Dict containing a provider config file"},{"line_number":87,"context_line":"    :param provider_config_path: Path to the provider config, used for logging"}],"source_content_type":"text/x-python","patch_set":34,"id":"1fa4df85_7c6066a6","line":84,"range":{"start_line":84,"start_character":14,"end_line":84,"end_character":61},"in_reply_to":"3fa7e38b_73ebaedc","updated":"2020-02-28 15:10:36.000000000","message":"i do not like that so im going to refactor this to return a tupple of the providers an noop providres and then remove the providers later.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":83,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":84,"context_line":"     performs additional checks for format and required keys."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    :param yaml_file: Dict containing a provider config file"},{"line_number":87,"context_line":"    :param provider_config_path: Path to the provider config, used for logging"},{"line_number":88,"context_line":"    :raise nova.exception.ProviderConfigException: If provider id is missing,"},{"line_number":89,"context_line":"        or a resource class or trait name is invalid."}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_93e66a13","line":86,"range":{"start_line":86,"start_character":11,"end_line":86,"end_character":20},"updated":"2020-01-17 20:13:32.000000000","message":"this is misleading as it is not a file any more. I suggest \u0027config\u0027","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"76555589b9f24f3a143cea192a1332532ab22329","unresolved":false,"context_lines":[{"line_number":83,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":84,"context_line":"     performs additional checks for format and required keys."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    :param yaml_file: Dict containing a provider config file"},{"line_number":87,"context_line":"    :param provider_config_path: Path to the provider config, used for logging"},{"line_number":88,"context_line":"    :raise nova.exception.ProviderConfigException: If provider id is missing,"},{"line_number":89,"context_line":"        or a resource class or trait name is invalid."}],"source_content_type":"text/x-python","patch_set":34,"id":"1fa4df85_1c79322e","line":86,"range":{"start_line":86,"start_character":11,"end_line":86,"end_character":20},"in_reply_to":"3fa7e38b_93e66a13","updated":"2020-02-28 15:10:36.000000000","message":"Done","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        # Check that traits are custom"},{"line_number":103,"context_line":"        additional_traits \u003d set(provider.get(\"traits\", {}).get("},{"line_number":104,"context_line":"            \"additional\", []))"},{"line_number":105,"context_line":"        trait_conflicts \u003d {trait for trait in additional_traits"},{"line_number":106,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":107,"context_line":"        if trait_conflicts:"},{"line_number":108,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":109,"context_line":"                error\u003d\"Invalid traits, only custom \""}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_3300d6b1","line":106,"range":{"start_line":105,"start_character":1,"end_line":106,"end_character":61},"updated":"2020-01-17 20:13:32.000000000","message":"Is there a specific reason we check this by python instead of by the schema?","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"fccbd5c7158ed9d03879e5d72485f51fad7f9a3d","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        # Check that traits are custom"},{"line_number":103,"context_line":"        additional_traits \u003d set(provider.get(\"traits\", {}).get("},{"line_number":104,"context_line":"            \"additional\", []))"},{"line_number":105,"context_line":"        trait_conflicts \u003d {trait for trait in additional_traits"},{"line_number":106,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":107,"context_line":"        if trait_conflicts:"},{"line_number":108,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":109,"context_line":"                error\u003d\"Invalid traits, only custom \""}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_a990ab50","line":106,"range":{"start_line":105,"start_character":1,"end_line":106,"end_character":61},"in_reply_to":"3fa7e38b_3300d6b1","updated":"2020-01-21 22:20:22.000000000","message":"Forward compatibility, when we later want to allow mucking with standard traits (or resource classes, below). If we schema-restricted v1.0 to CUSTOM_*, and removed that restriction in v1.1, it would mean a v1.1-compliant yaml file would refuse to parse when fed to the v1.0 schema. This was one of the things Dan made a big deal about at design time.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"5448d2a2402454b02b0e092c91e1911ec5282af4","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        # Check that traits are custom"},{"line_number":103,"context_line":"        additional_traits \u003d set(provider.get(\"traits\", {}).get("},{"line_number":104,"context_line":"            \"additional\", []))"},{"line_number":105,"context_line":"        trait_conflicts \u003d {trait for trait in additional_traits"},{"line_number":106,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":107,"context_line":"        if trait_conflicts:"},{"line_number":108,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":109,"context_line":"                error\u003d\"Invalid traits, only custom \""}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_f622cfb6","line":106,"range":{"start_line":105,"start_character":1,"end_line":106,"end_character":61},"in_reply_to":"3fa7e38b_a990ab50","updated":"2020-01-24 15:21:07.000000000","message":"OK","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":113,"context_line":"        additional_inventories \u003d provider.get(\"inventories\", {}).get("},{"line_number":114,"context_line":"            \"additional\", [])"},{"line_number":115,"context_line":"        for inventory in additional_inventories:"},{"line_number":116,"context_line":"            inventory_conflicts \u003d {rc for rc in inventory"},{"line_number":117,"context_line":"                                   if not os_resource_classes.is_custom(rc)}"},{"line_number":118,"context_line":"            if inventory_conflicts:"},{"line_number":119,"context_line":"                raise nova_exc.ProviderConfigException("},{"line_number":120,"context_line":"                    error\u003d\"Invalid resource class, only custom resource \""}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_530312be","line":117,"range":{"start_line":116,"start_character":0,"end_line":117,"end_character":76},"updated":"2020-01-17 20:13:32.000000000","message":"ditto","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    # Remove no-op providers"},{"line_number":134,"context_line":"    for nop in noop_providers:"},{"line_number":135,"context_line":"        providers.remove(nop)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"def _parse_provider_yaml(path):"},{"line_number":139,"context_line":"    \"\"\"Loads, schema-validates, and parses a provider.yaml file into a dict."}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_b31cc614","line":136,"updated":"2020-01-17 20:13:32.000000000","message":"This function feels a bit dense. I suggest to extract each check as a separate function","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"76555589b9f24f3a143cea192a1332532ab22329","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    # Remove no-op providers"},{"line_number":134,"context_line":"    for nop in noop_providers:"},{"line_number":135,"context_line":"        providers.remove(nop)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"def _parse_provider_yaml(path):"},{"line_number":139,"context_line":"    \"\"\"Loads, schema-validates, and parses a provider.yaml file into a dict."}],"source_content_type":"text/x-python","patch_set":34,"id":"1fa4df85_3c350e47","line":136,"in_reply_to":"3fa7e38b_b31cc614","updated":"2020-02-28 15:10:36.000000000","message":"ill extract the traits and rc validation into two seperate inner functions but i dont think they need to be top level functions.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":194,"context_line":"        A specific resource provider is identified twice."},{"line_number":195,"context_line":"        A resource class or trait name is invalid or not custom."},{"line_number":196,"context_line":"        A general schema validation error occurs (required fields, types, etc)"},{"line_number":197,"context_line":"    :return: A list with the parsed and validated contents of all files in the"},{"line_number":198,"context_line":"    provided dir. Each item on the list will include the source file name in"},{"line_number":199,"context_line":"    the key __source_file."},{"line_number":200,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_53bc726a","line":197,"range":{"start_line":197,"start_character":15,"end_line":197,"end_character":19},"updated":"2020-01-17 20:13:32.000000000","message":"I think it is a dict keyed by uuid_or_name","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":215,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":216,"context_line":"            pid \u003d provider[\"identification\"]"},{"line_number":217,"context_line":"            uuid_or_name \u003d pid.get(\"uuid\") or pid.get(\"name\")"},{"line_number":218,"context_line":"            # raise exception if this provider was already processed"},{"line_number":219,"context_line":"            if uuid_or_name in provider_configs:"},{"line_number":220,"context_line":"                raise nova_exc.ProviderConfigException("},{"line_number":221,"context_line":"                    error\u003d\"Provider %(provider_id)s has multiple definitions \""}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_5361d20f","line":218,"range":{"start_line":218,"start_character":12,"end_line":218,"end_character":68},"updated":"2020-01-17 20:13:32.000000000","message":"This is an incomplete check. The same provider can be identified 3 times in different places, once with uuid, once with name and once with $COMPUTE_NODE\n\nI think this also shows a weakness of the chosen validation strategy. With the current architecture we will need multiple levels of validation code.\n1) schema validation to enforce syntax\n2) validate basic semantic like pure uuid or name collision (like in this patch)\n3) later we need to resolve $COMPUTE_NODE to uuid and RP name to uuid THEN do another level of semantic validation to see if a single RP is not mentioned more than once.\n\nI think after #1) we should load everything as is, then resolve every possible ambiguity of identification and then do the semantic validation in a single run. I think this will lead to a less fragmented validation logic and it allow us to emit better error messages.\n\nI know that this is a significant implementation change so I\u0027m totally open for discussion.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"2fd88224f8e9ad175c803cdd11499fff1b8a5822","unresolved":false,"context_lines":[{"line_number":215,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":216,"context_line":"            pid \u003d provider[\"identification\"]"},{"line_number":217,"context_line":"            uuid_or_name \u003d pid.get(\"uuid\") or pid.get(\"name\")"},{"line_number":218,"context_line":"            # raise exception if this provider was already processed"},{"line_number":219,"context_line":"            if uuid_or_name in provider_configs:"},{"line_number":220,"context_line":"                raise nova_exc.ProviderConfigException("},{"line_number":221,"context_line":"                    error\u003d\"Provider %(provider_id)s has multiple definitions \""}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_a52478c4","line":218,"range":{"start_line":218,"start_character":12,"end_line":218,"end_character":68},"in_reply_to":"3fa7e38b_5361d20f","updated":"2020-01-18 17:55:36.000000000","message":"I run an experiment[1] on my idea (a quick and dirty refactoring to my taste) to resolve references early to avoid the need of multiple layer of semantic validation. During the experiment I realized that the current patch does the multi layer validation to be able to prevent the compute service starting with clearly invalid config. However the current patch cannot do a full validation at compute startup as that would require a populated provider_tree object which requires a fully initialized compute service. I guess it is a chicken and egg problem. We might be able to call get_provider_tree_and_ensure_root() early but I felt that would need too deep surgery.\n\nAnyhow the original problem still remains the current patch does not detect if the same provider is identified by different methods.\n\n[1] https://review.opendev.org/703249","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"fccbd5c7158ed9d03879e5d72485f51fad7f9a3d","unresolved":false,"context_lines":[{"line_number":215,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":216,"context_line":"            pid \u003d provider[\"identification\"]"},{"line_number":217,"context_line":"            uuid_or_name \u003d pid.get(\"uuid\") or pid.get(\"name\")"},{"line_number":218,"context_line":"            # raise exception if this provider was already processed"},{"line_number":219,"context_line":"            if uuid_or_name in provider_configs:"},{"line_number":220,"context_line":"                raise nova_exc.ProviderConfigException("},{"line_number":221,"context_line":"                    error\u003d\"Provider %(provider_id)s has multiple definitions \""}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_a9842bb3","line":218,"range":{"start_line":218,"start_character":12,"end_line":218,"end_character":68},"in_reply_to":"3fa7e38b_a52478c4","updated":"2020-01-21 22:20:22.000000000","message":"We\u0027ve struggled with this over several iterations.\n\nThis check, at load time, is designed to make sure you never specify the same actual identifier (including the special $COMPUTE_NODE value) twice. Then later, at runtime, we decide whether to use the explicit entry or the $COMPUTE_NODE entry to apply to a given provider.\n\nBecause it was going to be really hard to do otherwise, we decided to take advantage of the fact that the RP name and UUID are the same for ironic nodes, which this bit will also catch.\n\nSo then we would just have to worry about a (non ironic node) provider being specified by both name and ID. That\u0027s something we also can\u0027t detect until runtime. So that check should go in the subsequent patch.\n\n...which I don\u0027t see there. I\u0027ll add some notes in an appropriate spot.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"cf415a5b0d5ce45aba689a657e0f31cfbe331053","unresolved":false,"context_lines":[{"line_number":105,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":106,"context_line":"     performs additional checks for format and required keys."},{"line_number":107,"context_line":""},{"line_number":108,"context_line":"    This function has the sideeffect of removing noop_providres"},{"line_number":109,"context_line":"    from the config provided."},{"line_number":110,"context_line":""},{"line_number":111,"context_line":"    :param config: Dict containing a provider config file"}],"source_content_type":"text/x-python","patch_set":35,"id":"1fa4df85_feb94578","line":108,"updated":"2020-03-06 09:06:27.000000000","message":"You did a refactor that removed this side effect.","commit_id":"994ec5b2ac1dd9d2c0c3bcaa34a8e6dd2ce59538"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"76f069505e6c0a6f411364337da8546b1bf8ff6c","unresolved":false,"context_lines":[{"line_number":105,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":106,"context_line":"     performs additional checks for format and required keys."},{"line_number":107,"context_line":""},{"line_number":108,"context_line":"    This function has the sideeffect of removing noop_providres"},{"line_number":109,"context_line":"    from the config provided."},{"line_number":110,"context_line":""},{"line_number":111,"context_line":"    :param config: Dict containing a provider config file"}],"source_content_type":"text/x-python","patch_set":35,"id":"1fa4df85_6d6b40f0","line":108,"in_reply_to":"1fa4df85_feb94578","updated":"2020-03-12 12:39:49.000000000","message":"ah yes.\ni wrote the comment as you asked first and then if felt wrong. i guess i forgot to remove this.","commit_id":"994ec5b2ac1dd9d2c0c3bcaa34a8e6dd2ce59538"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"76f069505e6c0a6f411364337da8546b1bf8ff6c","unresolved":false,"context_lines":[{"line_number":103,"context_line":"def _validate_provider_config(config, provider_config_path):"},{"line_number":104,"context_line":"    \"\"\"Accepts a schema-verified provider config in the form of a dict and"},{"line_number":105,"context_line":"     performs additional checks for format and required keys."},{"line_number":106,"context_line":""},{"line_number":107,"context_line":"    This function has the sideeffect of removing noop_providres"},{"line_number":108,"context_line":"    from the config provided."},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"    :param config: Dict containing a provider config file"},{"line_number":111,"context_line":"    :param provider_config_path: Path to the provider config, used for logging"}],"source_content_type":"text/x-python","patch_set":36,"id":"1fa4df85_77e521dc","line":108,"range":{"start_line":106,"start_character":0,"end_line":108,"end_character":29},"updated":"2020-03-12 12:39:49.000000000","message":"i forgot to remove this","commit_id":"166e33526ff3eff74c1e9ec26facc460d1ee6eb7"},{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"b2c0c162cda984b5f3717623a16ed290bfaf2f01","unresolved":false,"context_lines":[{"line_number":10,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"import functools"},{"line_number":15,"context_line":"import glob"},{"line_number":16,"context_line":"import logging"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_e0eec4eb","line":13,"updated":"2020-07-21 14:05:18.000000000","message":"unrelated change","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":10,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"import functools"},{"line_number":15,"context_line":"import glob"},{"line_number":16,"context_line":"import logging"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_cfe5a1de","line":13,"in_reply_to":"bf51134e_e0eec4eb","updated":"2020-07-30 03:48:31.000000000","message":"Will fix.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5a54120619e25a73dd74381e6880182fbecf2d44","unresolved":false,"context_lines":[{"line_number":116,"context_line":"        if trait_conflicts:"},{"line_number":117,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":118,"context_line":"                error\u003d\"Invalid traits, only custom \""},{"line_number":119,"context_line":"                      \"traits are allowed: %s\" % trait_conflicts)"},{"line_number":120,"context_line":"        return additional_traits"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":"    def _validate_rc(provider):"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_b65ebde6","line":119,"range":{"start_line":119,"start_character":49,"end_line":119,"end_character":64},"updated":"2020-07-22 13:15:28.000000000","message":"How about\n\n  \u0027, \u0027.join(trait_conflicts)","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5a54120619e25a73dd74381e6880182fbecf2d44","unresolved":false,"context_lines":[{"line_number":115,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":116,"context_line":"        if trait_conflicts:"},{"line_number":117,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":118,"context_line":"                error\u003d\"Invalid traits, only custom \""},{"line_number":119,"context_line":"                      \"traits are allowed: %s\" % trait_conflicts)"},{"line_number":120,"context_line":"        return additional_traits"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":"    def _validate_rc(provider):"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_f63f9584","line":119,"range":{"start_line":118,"start_character":22,"end_line":119,"end_character":46},"updated":"2020-07-22 13:15:28.000000000","message":"missing translation","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":116,"context_line":"        if trait_conflicts:"},{"line_number":117,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":118,"context_line":"                error\u003d\"Invalid traits, only custom \""},{"line_number":119,"context_line":"                      \"traits are allowed: %s\" % trait_conflicts)"},{"line_number":120,"context_line":"        return additional_traits"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":"    def _validate_rc(provider):"}],"source_content_type":"text/x-python","patch_set":47,"id":"9f560f44_fc279c63","line":119,"range":{"start_line":119,"start_character":49,"end_line":119,"end_character":64},"in_reply_to":"bf51134e_b65ebde6","updated":"2020-07-30 03:48:31.000000000","message":"good idea. will fix.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":115,"context_line":"                           if not os_traits.is_custom(trait)}"},{"line_number":116,"context_line":"        if trait_conflicts:"},{"line_number":117,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":118,"context_line":"                error\u003d\"Invalid traits, only custom \""},{"line_number":119,"context_line":"                      \"traits are allowed: %s\" % trait_conflicts)"},{"line_number":120,"context_line":"        return additional_traits"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":"    def _validate_rc(provider):"}],"source_content_type":"text/x-python","patch_set":47,"id":"9f560f44_3c21144f","line":119,"range":{"start_line":118,"start_character":22,"end_line":119,"end_character":46},"in_reply_to":"bf51134e_f63f9584","updated":"2020-07-30 03:48:31.000000000","message":"will translate it.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5a54120619e25a73dd74381e6880182fbecf2d44","unresolved":false,"context_lines":[{"line_number":128,"context_line":"                                   if not os_resource_classes.is_custom(rc)}"},{"line_number":129,"context_line":"            if inventory_conflicts:"},{"line_number":130,"context_line":"                raise nova_exc.ProviderConfigException("},{"line_number":131,"context_line":"                    error\u003d\"Invalid resource class, only custom resource \""},{"line_number":132,"context_line":"                          \"classes are allowed: %s\" % inventory_conflicts)"},{"line_number":133,"context_line":"        return additional_inventories"},{"line_number":134,"context_line":""},{"line_number":135,"context_line":"    providers \u003d config.get(\"providers\", [])"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_564e4138","line":132,"range":{"start_line":131,"start_character":27,"end_line":132,"end_character":51},"updated":"2020-07-22 13:15:28.000000000","message":"translation","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":128,"context_line":"                                   if not os_resource_classes.is_custom(rc)}"},{"line_number":129,"context_line":"            if inventory_conflicts:"},{"line_number":130,"context_line":"                raise nova_exc.ProviderConfigException("},{"line_number":131,"context_line":"                    error\u003d\"Invalid resource class, only custom resource \""},{"line_number":132,"context_line":"                          \"classes are allowed: %s\" % inventory_conflicts)"},{"line_number":133,"context_line":"        return additional_inventories"},{"line_number":134,"context_line":""},{"line_number":135,"context_line":"    providers \u003d config.get(\"providers\", [])"}],"source_content_type":"text/x-python","patch_set":47,"id":"9f560f44_3ce63418","line":132,"range":{"start_line":131,"start_character":27,"end_line":132,"end_character":51},"in_reply_to":"bf51134e_564e4138","updated":"2020-07-30 03:48:31.000000000","message":"will do it.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"b2c0c162cda984b5f3717623a16ed290bfaf2f01","unresolved":false,"context_lines":[{"line_number":139,"context_line":"        # the schema only requires that some property be present"},{"line_number":140,"context_line":"        pid \u003d provider[\"identification\"]"},{"line_number":141,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":142,"context_line":"        if not provider_id:"},{"line_number":143,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":144,"context_line":"                error\u003d\"The provider does not have known identification.\")"},{"line_number":145,"context_line":""},{"line_number":146,"context_line":"        additional_traits \u003d _validate_traits(provider)"},{"line_number":147,"context_line":"        additional_inventories \u003d _validate_rc(provider)"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_80cb8848","line":144,"range":{"start_line":142,"start_character":9,"end_line":144,"end_character":73},"updated":"2020-07-21 14:05:18.000000000","message":"the schema should be able to ensure this https://review.opendev.org/#/c/673341/50/nova/compute/provider_config_schemas/provider_config_schema_v1.yaml@81, if yes, then we needn\u0027t this check","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":139,"context_line":"        # the schema only requires that some property be present"},{"line_number":140,"context_line":"        pid \u003d provider[\"identification\"]"},{"line_number":141,"context_line":"        provider_id \u003d pid.get(\"name\") or pid.get(\"uuid\")"},{"line_number":142,"context_line":"        if not provider_id:"},{"line_number":143,"context_line":"            raise nova_exc.ProviderConfigException("},{"line_number":144,"context_line":"                error\u003d\"The provider does not have known identification.\")"},{"line_number":145,"context_line":""},{"line_number":146,"context_line":"        additional_traits \u003d _validate_traits(provider)"},{"line_number":147,"context_line":"        additional_inventories \u003d _validate_rc(provider)"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_af5dcd7a","line":144,"range":{"start_line":142,"start_character":9,"end_line":144,"end_character":73},"in_reply_to":"bf51134e_80cb8848","updated":"2020-07-30 03:48:31.000000000","message":"yes, remove the code which never hits and add a comment to explain why we don\u0027t check the validity of provider_id.\n141         # Not checking the validity of provider_id since\n142         # the schema has already ensured that.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"b2c0c162cda984b5f3717623a16ed290bfaf2f01","unresolved":false,"context_lines":[{"line_number":158,"context_line":"            LOG.warning(message)"},{"line_number":159,"context_line":"            noop_providers.append(provider)"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    return (providers, noop_providers)"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":""},{"line_number":164,"context_line":"def _parse_provider_yaml(path):"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_a0532c6c","line":161,"range":{"start_line":161,"start_character":23,"end_line":161,"end_character":37},"updated":"2020-07-21 14:05:18.000000000","message":"it looks like useless to return the noop_providers, we can just return the valid providers from this method.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5a54120619e25a73dd74381e6880182fbecf2d44","unresolved":false,"context_lines":[{"line_number":158,"context_line":"            LOG.warning(message)"},{"line_number":159,"context_line":"            noop_providers.append(provider)"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    return (providers, noop_providers)"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":""},{"line_number":164,"context_line":"def _parse_provider_yaml(path):"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_d65b71f3","line":161,"range":{"start_line":161,"start_character":23,"end_line":161,"end_character":37},"in_reply_to":"bf51134e_a0532c6c","updated":"2020-07-22 13:15:28.000000000","message":"Agree. A simple warning seems sufficient","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":158,"context_line":"            LOG.warning(message)"},{"line_number":159,"context_line":"            noop_providers.append(provider)"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    return (providers, noop_providers)"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":""},{"line_number":164,"context_line":"def _parse_provider_yaml(path):"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_ef8185a2","line":161,"range":{"start_line":161,"start_character":23,"end_line":161,"end_character":37},"in_reply_to":"bf51134e_a0532c6c","updated":"2020-07-30 03:48:31.000000000","message":"agree. remove noop_providers related code.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":158,"context_line":"            LOG.warning(message)"},{"line_number":159,"context_line":"            noop_providers.append(provider)"},{"line_number":160,"context_line":""},{"line_number":161,"context_line":"    return (providers, noop_providers)"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":""},{"line_number":164,"context_line":"def _parse_provider_yaml(path):"}],"source_content_type":"text/x-python","patch_set":47,"id":"9f560f44_7cc9cc76","line":161,"range":{"start_line":161,"start_character":23,"end_line":161,"end_character":37},"in_reply_to":"bf51134e_d65b71f3","updated":"2020-07-30 03:48:31.000000000","message":"Thanks for the confirmation. will remove noop_providers.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"a3034f389e759e7afbe4d1462e2df9989df288d0","unresolved":false,"context_lines":[{"line_number":220,"context_line":"        config directory or if one of a number of validation checks fail:"},{"line_number":221,"context_line":"        Unknown, unsupported, or missing schema major version."},{"line_number":222,"context_line":"        Unknown, unsupported, or missing resource provider identification."},{"line_number":223,"context_line":"        A specific resource provider is identified twice."},{"line_number":224,"context_line":"        A resource class or trait name is invalid or not custom."},{"line_number":225,"context_line":"        A general schema validation error occurs (required fields, types, etc)"},{"line_number":226,"context_line":"    :return: A dict of dicts keyed by uuid_or_name with the parsed and"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_40b970e7","line":223,"range":{"start_line":223,"start_character":8,"end_line":223,"end_character":57},"updated":"2020-07-21 14:39:33.000000000","message":"I would add: \"identified twice with the same method. If the same provider identified by different methods then such conflict will be detected in a later stage.\"","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":220,"context_line":"        config directory or if one of a number of validation checks fail:"},{"line_number":221,"context_line":"        Unknown, unsupported, or missing schema major version."},{"line_number":222,"context_line":"        Unknown, unsupported, or missing resource provider identification."},{"line_number":223,"context_line":"        A specific resource provider is identified twice."},{"line_number":224,"context_line":"        A resource class or trait name is invalid or not custom."},{"line_number":225,"context_line":"        A general schema validation error occurs (required fields, types, etc)"},{"line_number":226,"context_line":"    :return: A dict of dicts keyed by uuid_or_name with the parsed and"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_4f7fd1aa","line":223,"range":{"start_line":223,"start_character":8,"end_line":223,"end_character":57},"in_reply_to":"bf51134e_40b970e7","updated":"2020-07-30 03:48:31.000000000","message":"agree. will improve the wording.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":5754,"name":"Alex Xu","email":"hejie.xu@intel.com","username":"xuhj"},"change_message_id":"b2c0c162cda984b5f3717623a16ed290bfaf2f01","unresolved":false,"context_lines":[{"line_number":259,"context_line":"                           \"source_files\": sorted({"},{"line_number":260,"context_line":"                               provider_configs[uuid_or_name][\"__source_file\"],"},{"line_number":261,"context_line":"                               provider_config_path})})"},{"line_number":262,"context_line":"            provider_configs[uuid_or_name] \u003d provider"},{"line_number":263,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_40d4d0bd","line":262,"range":{"start_line":262,"start_character":13,"end_line":262,"end_character":53},"updated":"2020-07-21 14:05:18.000000000","message":"just note to myself, there should be a check to ensure the name and uuid won\u0027t point to same resource provider id, and that probably be checked in later patch","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"a3034f389e759e7afbe4d1462e2df9989df288d0","unresolved":false,"context_lines":[{"line_number":259,"context_line":"                           \"source_files\": sorted({"},{"line_number":260,"context_line":"                               provider_configs[uuid_or_name][\"__source_file\"],"},{"line_number":261,"context_line":"                               provider_config_path})})"},{"line_number":262,"context_line":"            provider_configs[uuid_or_name] \u003d provider"},{"line_number":263,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_db745101","line":262,"range":{"start_line":262,"start_character":13,"end_line":262,"end_character":53},"in_reply_to":"bf51134e_40d4d0bd","updated":"2020-07-21 14:39:33.000000000","message":"There is a check in a later patch as far as I remember","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":259,"context_line":"                           \"source_files\": sorted({"},{"line_number":260,"context_line":"                               provider_configs[uuid_or_name][\"__source_file\"],"},{"line_number":261,"context_line":"                               provider_config_path})})"},{"line_number":262,"context_line":"            provider_configs[uuid_or_name] \u003d provider"},{"line_number":263,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_da071d18","line":262,"range":{"start_line":262,"start_character":13,"end_line":262,"end_character":53},"in_reply_to":"bf51134e_40d4d0bd","updated":"2020-07-30 03:48:31.000000000","message":"no patch change","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":259,"context_line":"                           \"source_files\": sorted({"},{"line_number":260,"context_line":"                               provider_configs[uuid_or_name][\"__source_file\"],"},{"line_number":261,"context_line":"                               provider_config_path})})"},{"line_number":262,"context_line":"            provider_configs[uuid_or_name] \u003d provider"},{"line_number":263,"context_line":"    return provider_configs"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_ba0a291d","line":262,"range":{"start_line":262,"start_character":13,"end_line":262,"end_character":53},"in_reply_to":"bf51134e_db745101","updated":"2020-07-30 03:48:31.000000000","message":"no patch change","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5534d2aa6674ebc851600d91677ee10e91c81649","unresolved":false,"context_lines":[{"line_number":256,"context_line":"        if trait_conflicts:"},{"line_number":257,"context_line":"            # sort for more predictable message for testing"},{"line_number":258,"context_line":"            message \u003d _(\"Invalid traits, only custom \""},{"line_number":259,"context_line":"                      \"traits are allowed: %s\") % \u0027, \u0027.join("},{"line_number":260,"context_line":"                          sorted(trait_conflicts))"},{"line_number":261,"context_line":"            raise nova_exc.ProviderConfigException(error\u003dmessage)"},{"line_number":262,"context_line":"        return additional_traits"}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_210fe489","line":259,"range":{"start_line":259,"start_character":21,"end_line":259,"end_character":22},"updated":"2020-07-31 14:25:30.000000000","message":"indentation, can you just drop the above line down?\n\n  message \u003d _(\n      \u0027Invalid traits, only custom traits are allowed\u0027\n  ) % \u0027, \u0027.join(sorted(trait_conflicts))","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"69cc294f8d768a2cbfc9b1fcf5be480f5af7c1cf","unresolved":false,"context_lines":[{"line_number":256,"context_line":"        if trait_conflicts:"},{"line_number":257,"context_line":"            # sort for more predictable message for testing"},{"line_number":258,"context_line":"            message \u003d _(\"Invalid traits, only custom \""},{"line_number":259,"context_line":"                      \"traits are allowed: %s\") % \u0027, \u0027.join("},{"line_number":260,"context_line":"                          sorted(trait_conflicts))"},{"line_number":261,"context_line":"            raise nova_exc.ProviderConfigException(error\u003dmessage)"},{"line_number":262,"context_line":"        return additional_traits"}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_c177f69f","line":259,"range":{"start_line":259,"start_character":21,"end_line":259,"end_character":22},"in_reply_to":"9f560f44_210fe489","updated":"2020-08-03 02:26:14.000000000","message":"will fix.","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5534d2aa6674ebc851600d91677ee10e91c81649","unresolved":false,"context_lines":[{"line_number":268,"context_line":"        all_inventory_conflicts \u003d []"},{"line_number":269,"context_line":"        for inventory in additional_inventories:"},{"line_number":270,"context_line":"            inventory_conflicts \u003d [rc for rc in inventory"},{"line_number":271,"context_line":"                                  if not os_resource_classes.is_custom(rc)]"},{"line_number":272,"context_line":"            if inventory_conflicts:"},{"line_number":273,"context_line":"                all_inventory_conflicts +\u003d inventory_conflicts"},{"line_number":274,"context_line":""}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_e1796cfc","line":271,"range":{"start_line":271,"start_character":33,"end_line":271,"end_character":34},"updated":"2020-07-31 14:25:30.000000000","message":"indentation","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"69cc294f8d768a2cbfc9b1fcf5be480f5af7c1cf","unresolved":false,"context_lines":[{"line_number":268,"context_line":"        all_inventory_conflicts \u003d []"},{"line_number":269,"context_line":"        for inventory in additional_inventories:"},{"line_number":270,"context_line":"            inventory_conflicts \u003d [rc for rc in inventory"},{"line_number":271,"context_line":"                                  if not os_resource_classes.is_custom(rc)]"},{"line_number":272,"context_line":"            if inventory_conflicts:"},{"line_number":273,"context_line":"                all_inventory_conflicts +\u003d inventory_conflicts"},{"line_number":274,"context_line":""}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_a17c8283","line":271,"range":{"start_line":271,"start_character":33,"end_line":271,"end_character":34},"in_reply_to":"9f560f44_e1796cfc","updated":"2020-08-03 02:26:14.000000000","message":"add one extra space.","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5534d2aa6674ebc851600d91677ee10e91c81649","unresolved":false,"context_lines":[{"line_number":283,"context_line":"    # store valid providers"},{"line_number":284,"context_line":"    valid_providers \u003d []"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    providers \u003d config.get(\"providers\", [])"},{"line_number":287,"context_line":"    for provider in providers:"},{"line_number":288,"context_line":"        # Check that the identification method is known since"},{"line_number":289,"context_line":"        # the schema only requires that some property be present"},{"line_number":290,"context_line":"        pid \u003d provider[\"identification\"]"}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_018740d9","line":287,"range":{"start_line":286,"start_character":0,"end_line":287,"end_character":30},"updated":"2020-07-31 14:25:30.000000000","message":"nit: could be one line","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"69cc294f8d768a2cbfc9b1fcf5be480f5af7c1cf","unresolved":false,"context_lines":[{"line_number":283,"context_line":"    # store valid providers"},{"line_number":284,"context_line":"    valid_providers \u003d []"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"    providers \u003d config.get(\"providers\", [])"},{"line_number":287,"context_line":"    for provider in providers:"},{"line_number":288,"context_line":"        # Check that the identification method is known since"},{"line_number":289,"context_line":"        # the schema only requires that some property be present"},{"line_number":290,"context_line":"        pid \u003d provider[\"identification\"]"}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_e172faac","line":287,"range":{"start_line":286,"start_character":0,"end_line":287,"end_character":30},"in_reply_to":"9f560f44_018740d9","updated":"2020-08-03 02:26:14.000000000","message":"combine the two lines into one line","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5534d2aa6674ebc851600d91677ee10e91c81649","unresolved":false,"context_lines":[{"line_number":392,"context_line":"    provider_configs \u003d {}"},{"line_number":393,"context_line":"    for provider_config_path in provider_config_paths:"},{"line_number":394,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_path)"},{"line_number":395,"context_line":"        providers \u003d _validate_provider_config("},{"line_number":396,"context_line":"            provider_config, provider_config_path)"},{"line_number":397,"context_line":""},{"line_number":398,"context_line":"        for provider in providers:"},{"line_number":399,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":400,"context_line":"            pid \u003d provider[\"identification\"]"},{"line_number":401,"context_line":"            uuid_or_name \u003d pid.get(\"uuid\") or pid.get(\"name\")"}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_e1620c3e","line":398,"range":{"start_line":395,"start_character":0,"end_line":398,"end_character":34},"updated":"2020-07-31 14:25:30.000000000","message":"nit: could be one line","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"69cc294f8d768a2cbfc9b1fcf5be480f5af7c1cf","unresolved":false,"context_lines":[{"line_number":392,"context_line":"    provider_configs \u003d {}"},{"line_number":393,"context_line":"    for provider_config_path in provider_config_paths:"},{"line_number":394,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_path)"},{"line_number":395,"context_line":"        providers \u003d _validate_provider_config("},{"line_number":396,"context_line":"            provider_config, provider_config_path)"},{"line_number":397,"context_line":""},{"line_number":398,"context_line":"        for provider in providers:"},{"line_number":399,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":400,"context_line":"            pid \u003d provider[\"identification\"]"},{"line_number":401,"context_line":"            uuid_or_name \u003d pid.get(\"uuid\") or pid.get(\"name\")"}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_615eea12","line":398,"range":{"start_line":395,"start_character":0,"end_line":398,"end_character":34},"in_reply_to":"9f560f44_e1620c3e","updated":"2020-08-03 02:26:14.000000000","message":"combine two lines into one line","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5534d2aa6674ebc851600d91677ee10e91c81649","unresolved":false,"context_lines":[{"line_number":402,"context_line":"            # raise exception if this provider was already processed"},{"line_number":403,"context_line":"            if uuid_or_name in provider_configs:"},{"line_number":404,"context_line":"                raise nova_exc.ProviderConfigException("},{"line_number":405,"context_line":"                    error\u003d\"Provider %(provider_id)s has multiple definitions \""},{"line_number":406,"context_line":"                          \"in source file(s): %(source_files)s.\" %"},{"line_number":407,"context_line":"                          {\"provider_id\": uuid_or_name,"},{"line_number":408,"context_line":"                           # sorted set for deduplication and consistent order"},{"line_number":409,"context_line":"                           \"source_files\": sorted({"}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_c1654847","line":406,"range":{"start_line":405,"start_character":26,"end_line":406,"end_character":64},"updated":"2020-07-31 14:25:30.000000000","message":"needs translations","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"69cc294f8d768a2cbfc9b1fcf5be480f5af7c1cf","unresolved":false,"context_lines":[{"line_number":402,"context_line":"            # raise exception if this provider was already processed"},{"line_number":403,"context_line":"            if uuid_or_name in provider_configs:"},{"line_number":404,"context_line":"                raise nova_exc.ProviderConfigException("},{"line_number":405,"context_line":"                    error\u003d\"Provider %(provider_id)s has multiple definitions \""},{"line_number":406,"context_line":"                          \"in source file(s): %(source_files)s.\" %"},{"line_number":407,"context_line":"                          {\"provider_id\": uuid_or_name,"},{"line_number":408,"context_line":"                           # sorted set for deduplication and consistent order"},{"line_number":409,"context_line":"                           \"source_files\": sorted({"}],"source_content_type":"text/x-python","patch_set":49,"id":"9f560f44_01a3ae01","line":406,"range":{"start_line":405,"start_character":26,"end_line":406,"end_character":64},"in_reply_to":"9f560f44_c1654847","updated":"2020-08-03 02:26:14.000000000","message":"will translate","commit_id":"b297b73a67f2a496eb042b0edeb4a1cd97dc1402"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"2ae8ec3c2789971560fb65e590e63ebb44fd8c51","unresolved":false,"context_lines":[{"line_number":257,"context_line":"            # sort for more predictable message for testing"},{"line_number":258,"context_line":"            message \u003d _("},{"line_number":259,"context_line":"                \"Invalid traits, only custom traits are allowed: %s\""},{"line_number":260,"context_line":"            ) % \u0027, \u0027.join(sorted(trait_conflicts))"},{"line_number":261,"context_line":"            raise nova_exc.ProviderConfigException(error\u003dmessage)"},{"line_number":262,"context_line":"        return additional_traits"},{"line_number":263,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_758b08c2","line":260,"updated":"2020-08-06 09:07:13.000000000","message":"traits are guaranteed to be strings so no need to convert here, thankfully","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"405c32f295c3808a6719f90076ff3382e171e95b","unresolved":false,"context_lines":[{"line_number":257,"context_line":"            # sort for more predictable message for testing"},{"line_number":258,"context_line":"            message \u003d _("},{"line_number":259,"context_line":"                \"Invalid traits, only custom traits are allowed: %s\""},{"line_number":260,"context_line":"            ) % \u0027, \u0027.join(sorted(trait_conflicts))"},{"line_number":261,"context_line":"            raise nova_exc.ProviderConfigException(error\u003dmessage)"},{"line_number":262,"context_line":"        return additional_traits"},{"line_number":263,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_b02abc7b","line":260,"in_reply_to":"9f560f44_758b08c2","updated":"2020-08-07 02:05:50.000000000","message":"remove \u0027, \u0027.join() call.","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"2ae8ec3c2789971560fb65e590e63ebb44fd8c51","unresolved":false,"context_lines":[{"line_number":274,"context_line":""},{"line_number":275,"context_line":"        if all_inventory_conflicts:"},{"line_number":276,"context_line":"            # sort for more predictable message for testing"},{"line_number":277,"context_line":"            message \u003d _(\"Invalid resource class, only custom resource \""},{"line_number":278,"context_line":"                        \"classes are allowed: %s\") % \u0027, \u0027.join("},{"line_number":279,"context_line":"                            sorted(all_inventory_conflicts))"},{"line_number":280,"context_line":"            raise nova_exc.ProviderConfigException(error\u003dmessage)"}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_b59120f4","line":277,"updated":"2020-08-06 09:07:13.000000000","message":"nit: would be nicer wrapped on a new line","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"405c32f295c3808a6719f90076ff3382e171e95b","unresolved":false,"context_lines":[{"line_number":274,"context_line":""},{"line_number":275,"context_line":"        if all_inventory_conflicts:"},{"line_number":276,"context_line":"            # sort for more predictable message for testing"},{"line_number":277,"context_line":"            message \u003d _(\"Invalid resource class, only custom resource \""},{"line_number":278,"context_line":"                        \"classes are allowed: %s\") % \u0027, \u0027.join("},{"line_number":279,"context_line":"                            sorted(all_inventory_conflicts))"},{"line_number":280,"context_line":"            raise nova_exc.ProviderConfigException(error\u003dmessage)"}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_f020b49d","line":277,"in_reply_to":"9f560f44_b59120f4","updated":"2020-08-07 02:05:50.000000000","message":"create a new line","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"2ae8ec3c2789971560fb65e590e63ebb44fd8c51","unresolved":false,"context_lines":[{"line_number":386,"context_line":"            \"No provider configs found in %s. If files are present, \""},{"line_number":387,"context_line":"            \"ensure the Nova process has access.\""},{"line_number":388,"context_line":"        )"},{"line_number":389,"context_line":"        LOG.info(message, provider_config_dir)"},{"line_number":390,"context_line":""},{"line_number":391,"context_line":"    provider_configs \u003d {}"},{"line_number":392,"context_line":"    for provider_config_path in provider_config_paths:"}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_15ba8c6c","line":389,"updated":"2020-08-06 09:07:13.000000000","message":"nit: it might be clearer to add an early return here. The loop below will never trigger but it takes a beat to understand that","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"405c32f295c3808a6719f90076ff3382e171e95b","unresolved":false,"context_lines":[{"line_number":386,"context_line":"            \"No provider configs found in %s. If files are present, \""},{"line_number":387,"context_line":"            \"ensure the Nova process has access.\""},{"line_number":388,"context_line":"        )"},{"line_number":389,"context_line":"        LOG.info(message, provider_config_dir)"},{"line_number":390,"context_line":""},{"line_number":391,"context_line":"    provider_configs \u003d {}"},{"line_number":392,"context_line":"    for provider_config_path in provider_config_paths:"}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_907b388a","line":389,"in_reply_to":"9f560f44_15ba8c6c","updated":"2020-08-07 02:05:50.000000000","message":"yes. add an early return after log to make the code logic more clearer.","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"2ae8ec3c2789971560fb65e590e63ebb44fd8c51","unresolved":false,"context_lines":[{"line_number":393,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_path)"},{"line_number":394,"context_line":""},{"line_number":395,"context_line":"        for provider in _validate_provider_config("},{"line_number":396,"context_line":"                provider_config, provider_config_path):"},{"line_number":397,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":398,"context_line":"            pid \u003d provider[\"identification\"]"},{"line_number":399,"context_line":"            uuid_or_name \u003d pid.get(\"uuid\") or pid.get(\"name\")"}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_55afe428","line":396,"updated":"2020-08-06 09:07:13.000000000","message":"nit:\n\n  for provider in _validate_provider_config(\n      provider_config, provider_config_path,\n  ):","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"405c32f295c3808a6719f90076ff3382e171e95b","unresolved":false,"context_lines":[{"line_number":393,"context_line":"        provider_config \u003d _parse_provider_yaml(provider_config_path)"},{"line_number":394,"context_line":""},{"line_number":395,"context_line":"        for provider in _validate_provider_config("},{"line_number":396,"context_line":"                provider_config, provider_config_path):"},{"line_number":397,"context_line":"            provider[\u0027__source_file\u0027] \u003d os.path.basename(provider_config_path)"},{"line_number":398,"context_line":"            pid \u003d provider[\"identification\"]"},{"line_number":399,"context_line":"            uuid_or_name \u003d pid.get(\"uuid\") or pid.get(\"name\")"}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_7062e4d9","line":396,"in_reply_to":"9f560f44_55afe428","updated":"2020-08-07 02:05:50.000000000","message":"change code as comment","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"385fa8762cce4323d39b066e280417351f89582d","unresolved":false,"context_lines":[{"line_number":269,"context_line":"        for inventory in additional_inventories:"},{"line_number":270,"context_line":"            inventory_conflicts \u003d [rc for rc in inventory"},{"line_number":271,"context_line":"                                   if not os_resource_classes.is_custom(rc)]"},{"line_number":272,"context_line":"            if inventory_conflicts:"},{"line_number":273,"context_line":"                all_inventory_conflicts +\u003d inventory_conflicts"},{"line_number":274,"context_line":""},{"line_number":275,"context_line":"        if all_inventory_conflicts:"}],"source_content_type":"text/x-python","patch_set":51,"id":"9f560f44_7147931e","line":272,"range":{"start_line":272,"start_character":12,"end_line":272,"end_character":35},"updated":"2020-08-25 13:32:30.000000000","message":"micro nit: the if is not necessary as you can concatenate the empty list below without issue.","commit_id":"8c69c86f18a390f12e941ea04c5cfa0dc6c92039"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"4d885249ceaafafddfb15d608a180baf069f82f4","unresolved":false,"context_lines":[{"line_number":269,"context_line":"        for inventory in additional_inventories:"},{"line_number":270,"context_line":"            inventory_conflicts \u003d [rc for rc in inventory"},{"line_number":271,"context_line":"                                   if not os_resource_classes.is_custom(rc)]"},{"line_number":272,"context_line":"            if inventory_conflicts:"},{"line_number":273,"context_line":"                all_inventory_conflicts +\u003d inventory_conflicts"},{"line_number":274,"context_line":""},{"line_number":275,"context_line":"        if all_inventory_conflicts:"}],"source_content_type":"text/x-python","patch_set":51,"id":"9f560f44_9eb6a23d","line":272,"range":{"start_line":272,"start_character":12,"end_line":272,"end_character":35},"in_reply_to":"9f560f44_7147931e","updated":"2020-08-26 09:14:44.000000000","message":"+1","commit_id":"8c69c86f18a390f12e941ea04c5cfa0dc6c92039"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"4d885249ceaafafddfb15d608a180baf069f82f4","unresolved":false,"context_lines":[{"line_number":388,"context_line":"            \"No provider configs found in %s. If files are present, \""},{"line_number":389,"context_line":"            \"ensure the Nova process has access.\""},{"line_number":390,"context_line":"        )"},{"line_number":391,"context_line":"        LOG.info(message, provider_config_dir)"},{"line_number":392,"context_line":""},{"line_number":393,"context_line":"        # return an empty dict as no provider configs found"},{"line_number":394,"context_line":"        return provider_configs"}],"source_content_type":"text/x-python","patch_set":51,"id":"9f560f44_deeada0c","line":391,"updated":"2020-08-26 09:14:44.000000000","message":"This is nice, but then the caller of get_provider_configs() needs to verify that the config option is already set or if not, *EVERY* compute will get this.","commit_id":"8c69c86f18a390f12e941ea04c5cfa0dc6c92039"}],"nova/compute/resource_tracker.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b2e17faebc0a4b8bd1fc89365767d5f9966220e5","unresolved":false,"context_lines":[{"line_number":153,"context_line":"        self.cpu_allocation_ratio \u003d CONF.cpu_allocation_ratio"},{"line_number":154,"context_line":"        self.disk_allocation_ratio \u003d CONF.disk_allocation_ratio"},{"line_number":155,"context_line":""},{"line_number":156,"context_line":"        # TODO(dustinc): Load path from config and pass here and more tests."},{"line_number":157,"context_line":"        #  Once the config option is in place, the try/except can be removed"},{"line_number":158,"context_line":"        try:"},{"line_number":159,"context_line":"            self.custom_resources \u003d provider_config.get_custom_resources("}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_63018e06","line":156,"updated":"2019-08-13 22:50:23.000000000","message":"I would do this part in a separate patch","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"98c35c691ac58127808438b81a4e4aa8f948c24f","unresolved":false,"context_lines":[{"line_number":153,"context_line":"        self.cpu_allocation_ratio \u003d CONF.cpu_allocation_ratio"},{"line_number":154,"context_line":"        self.disk_allocation_ratio \u003d CONF.disk_allocation_ratio"},{"line_number":155,"context_line":""},{"line_number":156,"context_line":"        # TODO(dustinc): Load path from config and pass here and more tests."},{"line_number":157,"context_line":"        #  Once the config option is in place, the try/except can be removed"},{"line_number":158,"context_line":"        try:"},{"line_number":159,"context_line":"            self.custom_resources \u003d provider_config.get_custom_resources("}],"source_content_type":"text/x-python","patch_set":3,"id":"7faddb67_309ae86e","line":156,"in_reply_to":"7faddb67_63018e06","updated":"2019-08-14 21:58:49.000000000","message":"Done","commit_id":"f330ea5b17f15e12ce67de308e95da8cf45c8cd5"}],"nova/tests/unit/compute/provider_config_data/v1/example_provider.yaml":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    traits:"},{"line_number":31,"context_line":"      additional:"},{"line_number":32,"context_line":"        - \u0027CUSTOM_TRAIT_ONE\u0027"},{"line_number":33,"context_line":"        - \u0027CUSTOM_TRAIT2\u0027"}],"source_content_type":"text/x-yaml","patch_set":11,"id":"7faddb67_9eba98de","line":33,"updated":"2019-09-03 22:35:28.000000000","message":"what\u0027s this delta?","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"}],"nova/tests/unit/compute/provider_config_data/validate_provider_test_data.yaml":[{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":12,"context_line":""},{"line_number":13,"context_line":"# NOTE(dustinc): Sample and expected are required for each test. Expected"},{"line_number":14,"context_line":"#   should be set to the identification value used for the test case."},{"line_number":15,"context_line":"no_trait_or_inventory_keys:"},{"line_number":16,"context_line":"  sample:"},{"line_number":17,"context_line":"    providers:"},{"line_number":18,"context_line":"      - identification:"}],"source_content_type":"text/x-yaml","patch_set":16,"id":"3fa7e38b_95460750","line":15,"updated":"2019-10-11 09:45:15.000000000","message":"If you want to cover duplicates or invalid inventories/traits.\n\nI also see some tests under v1/","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"# NOTE(dustinc): Sample and expected are required for each test. Expected"},{"line_number":14,"context_line":"#   should be set to the identification value used for the test case."},{"line_number":15,"context_line":"no_trait_or_inventory_keys:"},{"line_number":16,"context_line":"  sample:"},{"line_number":17,"context_line":"    providers:"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"3fa7e38b_71252d5c","line":14,"updated":"2019-10-18 21:33:24.000000000","message":"Okay, so this file could do more to test\n- UUIDs\n- Multiple providers\n\n(fwiw, I don\u0027t think there\u0027s value in all these cases being identical in terms of providers.identification, which is the only thing you\u0027re actually testing right now. But no harm keeping the variations in place if you also vary the providers.identification bits.)","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"e914d3441445765cbb0046082ef80462c4c1b76a","unresolved":false,"context_lines":[{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"# NOTE(dustinc): Sample and expected are required for each test. Expected"},{"line_number":14,"context_line":"#   should be set to the identification value used for the test case."},{"line_number":15,"context_line":"no_trait_or_inventory_keys:"},{"line_number":16,"context_line":"  sample:"},{"line_number":17,"context_line":"    providers:"}],"source_content_type":"text/x-yaml","patch_set":19,"id":"3fa7e38b_02e8d813","line":14,"in_reply_to":"3fa7e38b_71252d5c","updated":"2019-10-24 18:29:56.000000000","message":"This was initially just a smoke test that I think is no longer useful in its current state with the other DDT tests I added. I went ahead and varied and expanded the test cases to make them useful again.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e9a9ad165eaea571d5f18cd8f54977dd63e59fdf","unresolved":false,"context_lines":[{"line_number":9,"context_line":"#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the"},{"line_number":10,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"# NOTE(dustinc): Sample and expected are required for each test. Expected"},{"line_number":14,"context_line":"#   should be set to the identification value used for the test case."},{"line_number":15,"context_line":"no_trait_or_inventory_keys:"}],"source_content_type":"text/x-yaml","patch_set":24,"id":"3fa7e38b_29efe5b1","line":12,"updated":"2019-10-25 20:13:34.000000000","message":"Could use more words about how this file is consumed by the test harness. AFAICT it\u0027s something like:\n\nThis file contains ddt data for testing good paths through the _validate_provider_config method. For each entry, the `sample` is treated as post-schema-validated data (that is, it does *not* go through any part of _parse_provider_yaml) and `expected` is the list of identifiers (names and uuids) in the sample.","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8bdbcaaf0681b93f71fdf934d2db45063c705796","unresolved":false,"context_lines":[{"line_number":9,"context_line":"#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the"},{"line_number":10,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"# NOTE(dustinc): Sample and expected are required for each test. Expected"},{"line_number":14,"context_line":"#   should be set to the identification value used for the test case."},{"line_number":15,"context_line":"no_trait_or_inventory_keys:"}],"source_content_type":"text/x-yaml","patch_set":24,"id":"3fa7e38b_b8b16147","line":12,"in_reply_to":"3fa7e38b_29efe5b1","updated":"2019-11-05 19:05:25.000000000","message":"Done","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e9a9ad165eaea571d5f18cd8f54977dd63e59fdf","unresolved":false,"context_lines":[{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"# NOTE(dustinc): Sample and expected are required for each test. Expected"},{"line_number":14,"context_line":"#   should be set to the identification value used for the test case."},{"line_number":15,"context_line":"no_trait_or_inventory_keys:"},{"line_number":16,"context_line":"  sample:"},{"line_number":17,"context_line":"    providers:"}],"source_content_type":"text/x-yaml","patch_set":24,"id":"3fa7e38b_6994fd44","line":14,"range":{"start_line":14,"start_character":40,"end_line":14,"end_character":45},"updated":"2019-10-25 20:13:34.000000000","message":"(s)","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8bdbcaaf0681b93f71fdf934d2db45063c705796","unresolved":false,"context_lines":[{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"# NOTE(dustinc): Sample and expected are required for each test. Expected"},{"line_number":14,"context_line":"#   should be set to the identification value used for the test case."},{"line_number":15,"context_line":"no_trait_or_inventory_keys:"},{"line_number":16,"context_line":"  sample:"},{"line_number":17,"context_line":"    providers:"}],"source_content_type":"text/x-yaml","patch_set":24,"id":"3fa7e38b_387fb167","line":14,"range":{"start_line":14,"start_character":40,"end_line":14,"end_character":45},"in_reply_to":"3fa7e38b_6994fd44","updated":"2019-11-05 19:05:25.000000000","message":"Done","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":16,"context_line":"# is raised, the test passes."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"no_trait_or_inventory_keys:"},{"line_number":19,"context_line":"  sample:"},{"line_number":20,"context_line":"    providers:"},{"line_number":21,"context_line":"      - identification:"},{"line_number":22,"context_line":"          name: name"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"3fa7e38b_f340fe61","line":19,"updated":"2020-01-17 20:13:32.000000000","message":"In the previous patch it was called \u0027config\u0027 lets make it consistent","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":67,"context_line":"            - CUSTOM_RESOURCE_CLASS:"},{"line_number":68,"context_line":"                total: 1"},{"line_number":69,"context_line":"      - identification:"},{"line_number":70,"context_line":"          uuid: uuid1"},{"line_number":71,"context_line":"        inventories:"},{"line_number":72,"context_line":"          additional:"},{"line_number":73,"context_line":"            - CUSTOM_RESOURCE_CLASS:"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"3fa7e38b_b6c0347f","line":70,"range":{"start_line":70,"start_character":16,"end_line":70,"end_character":21},"updated":"2020-01-17 20:13:32.000000000","message":"this is not valid uuid by the schema","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":92,"context_line":"          additional:"},{"line_number":93,"context_line":"            - CUSTOM_TRAIT"},{"line_number":94,"context_line":"      - identification:"},{"line_number":95,"context_line":"          uuid: uuid1"},{"line_number":96,"context_line":"        traits:"},{"line_number":97,"context_line":"          additional:"},{"line_number":98,"context_line":"            - CUSTOM_TRAIT"}],"source_content_type":"text/x-yaml","patch_set":34,"id":"3fa7e38b_3600c4b1","line":95,"range":{"start_line":95,"start_character":16,"end_line":95,"end_character":21},"updated":"2020-01-17 20:13:32.000000000","message":"ditto","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"}],"nova/tests/unit/compute/test_provider_config.py":[{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":83,"context_line":"    the subclass that call the run_test_ methods in this class. This should"},{"line_number":84,"context_line":"    keep things simple as more schema versions are added."},{"line_number":85,"context_line":"    \"\"\""},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    def setUp(self):"},{"line_number":88,"context_line":"        super(SchemaValidationMixin, self).setUp()"},{"line_number":89,"context_line":"        self.mock_load_yaml \u003d self.useFixture("}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_7eb55cec","line":86,"updated":"2019-09-03 22:35:28.000000000","message":"unrelated whitespace change","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"7641f488d15beb83c83842a10f1aa515ed14c4e8","unresolved":false,"context_lines":[{"line_number":175,"context_line":""},{"line_number":176,"context_line":"    def test_schema_version_matching(self):"},{"line_number":177,"context_line":"        self.run_schema_version_matching(self.MIN_SCHEMA_VERSION,"},{"line_number":178,"context_line":"                                         self.MAX_SCHEMA_VERSION)"},{"line_number":179,"context_line":""},{"line_number":180,"context_line":""},{"line_number":181,"context_line":"@ddt.ddt"}],"source_content_type":"text/x-python","patch_set":11,"id":"7faddb67_3ecb6472","line":178,"updated":"2019-09-03 22:35:28.000000000","message":"need test cases for duplicated provider name/uuid.","commit_id":"3a67f2076b71d1a23d82c7e346e46aa8b2e00eff"},{"author":{"_account_id":29334,"name":"Dakshina Ilangovan","email":"dakshina.ilangovan@intel.com","username":"dakshinai"},"change_message_id":"e3477b746495beab50e2830bbab0a88ce331b169","unresolved":false,"context_lines":[{"line_number":271,"context_line":""},{"line_number":272,"context_line":"    @mock.patch.object(provider_config, \u0027glob\u0027)"},{"line_number":273,"context_line":"    @mock.patch.object(provider_config, \u0027_parse_provider_yaml\u0027)"},{"line_number":274,"context_line":"    def test_get_provider_configs_two_files(self, mock_parser, mock_glob):"},{"line_number":275,"context_line":"        expected \u003d ["},{"line_number":276,"context_line":"            {"},{"line_number":277,"context_line":"                \"_source_file\": \"file1.yaml\","}],"source_content_type":"text/x-python","patch_set":16,"id":"3fa7e38b_554def6f","line":274,"range":{"start_line":274,"start_character":8,"end_line":274,"end_character":43},"updated":"2019-10-11 09:45:15.000000000","message":"Also a test for multiple files with duplicates","commit_id":"c1cf58013c8e9ffe9438a64f57bb08f0ed17b4f8"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":183,"context_line":"        processed_provider_ids \u003d []"},{"line_number":184,"context_line":"        provider_config._validate_provider_config(sample,"},{"line_number":185,"context_line":"                                                  processed_provider_ids)"},{"line_number":186,"context_line":"        self.assertEqual(processed_provider_ids, expected)"},{"line_number":187,"context_line":""},{"line_number":188,"context_line":"    def test_validate_provider_one_invalid_additional_inventory(self):"},{"line_number":189,"context_line":"        config \u003d {"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_516ef196","line":186,"range":{"start_line":186,"start_character":25,"end_line":186,"end_character":57},"updated":"2019-10-18 21:33:24.000000000","message":"reverse these","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8f2ba9683c5ad5e27165c0d4eac32db8dcc79e94","unresolved":false,"context_lines":[{"line_number":183,"context_line":"        processed_provider_ids \u003d []"},{"line_number":184,"context_line":"        provider_config._validate_provider_config(sample,"},{"line_number":185,"context_line":"                                                  processed_provider_ids)"},{"line_number":186,"context_line":"        self.assertEqual(processed_provider_ids, expected)"},{"line_number":187,"context_line":""},{"line_number":188,"context_line":"    def test_validate_provider_one_invalid_additional_inventory(self):"},{"line_number":189,"context_line":"        config \u003d {"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_418278a7","line":186,"range":{"start_line":186,"start_character":25,"end_line":186,"end_character":57},"in_reply_to":"3fa7e38b_516ef196","updated":"2019-10-24 16:55:06.000000000","message":"Done","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":270,"context_line":"    @mock.patch.object(provider_config, \u0027_parse_provider_yaml\u0027)"},{"line_number":271,"context_line":"    def test_get_provider_configs_two_files(self, mock_parser, mock_glob):"},{"line_number":272,"context_line":"        expected \u003d ["},{"line_number":273,"context_line":"            {"},{"line_number":274,"context_line":"                \"_source_file\": \"file1.yaml\","},{"line_number":275,"context_line":"                \"identification\": {"},{"line_number":276,"context_line":"                    \"name\": \"EXAMPLE_RESOURCE_PROVIDER1\""}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_b1872513","line":273,"updated":"2019-10-18 21:33:24.000000000","message":"you could DRY the expected contents of the sample file pretty good by defining it once at top of file and using\n\n dict(_THAT_CONST, _source_file\u003d\u0027file1.yaml\u0027)\n\nkind of thing to create variants.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"e914d3441445765cbb0046082ef80462c4c1b76a","unresolved":false,"context_lines":[{"line_number":270,"context_line":"    @mock.patch.object(provider_config, \u0027_parse_provider_yaml\u0027)"},{"line_number":271,"context_line":"    def test_get_provider_configs_two_files(self, mock_parser, mock_glob):"},{"line_number":272,"context_line":"        expected \u003d ["},{"line_number":273,"context_line":"            {"},{"line_number":274,"context_line":"                \"_source_file\": \"file1.yaml\","},{"line_number":275,"context_line":"                \"identification\": {"},{"line_number":276,"context_line":"                    \"name\": \"EXAMPLE_RESOURCE_PROVIDER1\""}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_0278d8f5","line":273,"in_reply_to":"3fa7e38b_b1872513","updated":"2019-10-24 18:29:56.000000000","message":"I considered that previously, but since there are differences throughout the config (not just in file name) and it is only used in a couple places, the solution ended up being worse than just repeating it imo.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":333,"context_line":"                                                            \u0027*.yaml\u0027))"},{"line_number":334,"context_line":"        mock_parser.assert_has_calls([mock.call(param)"},{"line_number":335,"context_line":"                                     for param in mock_glob_return])"},{"line_number":336,"context_line":"        self.assertEqual(expected, actual)"},{"line_number":337,"context_line":""},{"line_number":338,"context_line":"    def test_get_provider_configs_no_configs(self):"},{"line_number":339,"context_line":"        actual \u003d provider_config.get_provider_configs(\u0027invalid_path!@#\u0027)"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_9102296f","line":336,"updated":"2019-10-18 21:33:24.000000000","message":"This test really isn\u0027t doing much, since you\u0027re mocking the globbing and the parsing. If you want to test multiple files, you could use a fixtures.TempDir().path and actually write some, and not have to mock anything.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"e914d3441445765cbb0046082ef80462c4c1b76a","unresolved":false,"context_lines":[{"line_number":333,"context_line":"                                                            \u0027*.yaml\u0027))"},{"line_number":334,"context_line":"        mock_parser.assert_has_calls([mock.call(param)"},{"line_number":335,"context_line":"                                     for param in mock_glob_return])"},{"line_number":336,"context_line":"        self.assertEqual(expected, actual)"},{"line_number":337,"context_line":""},{"line_number":338,"context_line":"    def test_get_provider_configs_no_configs(self):"},{"line_number":339,"context_line":"        actual \u003d provider_config.get_provider_configs(\u0027invalid_path!@#\u0027)"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_0261b839","line":336,"in_reply_to":"3fa7e38b_9102296f","updated":"2019-10-24 18:29:56.000000000","message":"I was intentionally avoiding accessing the disk in the unit test to keep it fast. My intention here was to make sure that when glob returns multiple files, the parser is called for each.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e2fc253445a656feba95885d65db39baaea702fb","unresolved":false,"context_lines":[{"line_number":338,"context_line":"    def test_get_provider_configs_no_configs(self):"},{"line_number":339,"context_line":"        actual \u003d provider_config.get_provider_configs(\u0027invalid_path!@#\u0027)"},{"line_number":340,"context_line":""},{"line_number":341,"context_line":"        self.assertEqual([], actual)"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_f1735d15","line":341,"range":{"start_line":341,"start_character":0,"end_line":341,"end_character":36},"updated":"2019-10-18 21:33:24.000000000","message":"this shows we\u0027re probably being too lenient with bogus directories in get_provider_configs\n\n[Later] Were you expecting to hit that OSError and have this raise ProviderConfigException?","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e9a9ad165eaea571d5f18cd8f54977dd63e59fdf","unresolved":false,"context_lines":[{"line_number":338,"context_line":"    def test_get_provider_configs_no_configs(self):"},{"line_number":339,"context_line":"        actual \u003d provider_config.get_provider_configs(\u0027invalid_path!@#\u0027)"},{"line_number":340,"context_line":""},{"line_number":341,"context_line":"        self.assertEqual([], actual)"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_49c26155","line":341,"range":{"start_line":341,"start_character":0,"end_line":341,"end_character":36},"in_reply_to":"3fa7e38b_39e51edd","updated":"2019-10-25 20:13:34.000000000","message":"Oh, interesting. Then perhaps it\u0027s worth doing an explicit existence/access check first. But if we do that, we may want to make the default of the conf opt None so we don\u0027t go raising an exception in the common (no provider configs) case.\n\nI\u0027m probably overengineering again. What you have is fine.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8f2ba9683c5ad5e27165c0d4eac32db8dcc79e94","unresolved":false,"context_lines":[{"line_number":338,"context_line":"    def test_get_provider_configs_no_configs(self):"},{"line_number":339,"context_line":"        actual \u003d provider_config.get_provider_configs(\u0027invalid_path!@#\u0027)"},{"line_number":340,"context_line":""},{"line_number":341,"context_line":"        self.assertEqual([], actual)"}],"source_content_type":"text/x-python","patch_set":19,"id":"3fa7e38b_39e51edd","line":341,"range":{"start_line":341,"start_character":0,"end_line":341,"end_character":36},"in_reply_to":"3fa7e38b_f1735d15","updated":"2019-10-24 16:55:06.000000000","message":"glob.glob catches all OSErrors (etc) and just returns an empty list. This means it is a bit harder to tell the difference between say a permissions error on the file/dir and an empty directory. I updated that bit of code to log on an empty list to help if an admin is debugging. Since this is called from rt.__init__, it shouldn\u0027t trigger repeatedly. Let me know what you think.","commit_id":"056ec515f6ff8d91d9340b9dbb19bf926541bc5b"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e9a9ad165eaea571d5f18cd8f54977dd63e59fdf","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":24,"id":"3fa7e38b_69ae3de8","line":354,"updated":"2019-10-25 20:13:34.000000000","message":"pep8 dislikes this extra blank line","commit_id":"450a850ef6f41f04fc3dfbf8889feeae6f79b27c"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"e320db87acd4ffac0b2677160c00a3b9cb9dc11d","unresolved":false,"context_lines":[{"line_number":201,"context_line":"        actual \u003d self.assertRaises(nova_exc.ProviderConfigException,"},{"line_number":202,"context_line":"                                   provider_config._validate_provider_config,"},{"line_number":203,"context_line":"                                   config).message"},{"line_number":204,"context_line":"        # The __str__ for sets is different in py27 vs py3:"},{"line_number":205,"context_line":"        # Py37: {\u0027INVALID_RESOURCE_CLASS\u0027}"},{"line_number":206,"context_line":"        # Py27: set([\u0027INVALID_RESOURCE_CLASS\u0027]"},{"line_number":207,"context_line":"        # This is a little funky but works around that."}],"source_content_type":"text/x-python","patch_set":31,"id":"3fa7e38b_19caed46","line":204,"range":{"start_line":204,"start_character":47,"end_line":204,"end_character":51},"updated":"2020-01-13 20:29:39.000000000","message":"As of [1] we don\u0027t have to worry about py2 anymore.\n\n[1] Ie1a0cbd82a617dbcc15729647218ac3e9cd0e5a9","commit_id":"cd73b4c3aaa1a49f34e551b783540f7962f95d91"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8f919f5a28a4bac830ce973f2344a170b9a5e7fc","unresolved":false,"context_lines":[{"line_number":201,"context_line":"        actual \u003d self.assertRaises(nova_exc.ProviderConfigException,"},{"line_number":202,"context_line":"                                   provider_config._validate_provider_config,"},{"line_number":203,"context_line":"                                   config).message"},{"line_number":204,"context_line":"        # The __str__ for sets is different in py27 vs py3:"},{"line_number":205,"context_line":"        # Py37: {\u0027INVALID_RESOURCE_CLASS\u0027}"},{"line_number":206,"context_line":"        # Py27: set([\u0027INVALID_RESOURCE_CLASS\u0027]"},{"line_number":207,"context_line":"        # This is a little funky but works around that."}],"source_content_type":"text/x-python","patch_set":31,"id":"3fa7e38b_fd132767","line":204,"range":{"start_line":204,"start_character":47,"end_line":204,"end_character":51},"in_reply_to":"3fa7e38b_19caed46","updated":"2020-01-15 02:22:29.000000000","message":"Done","commit_id":"cd73b4c3aaa1a49f34e551b783540f7962f95d91"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1bd0598a7ed54b43765cc44055449bd7ca903a73","unresolved":false,"context_lines":[{"line_number":185,"context_line":"                    \"inventories\": {"},{"line_number":186,"context_line":"                        \"additional\": ["},{"line_number":187,"context_line":"                            {\"CUSTOM_RESOURCE_CLASS\": {}},"},{"line_number":188,"context_line":"                            {\"INVALID_RESOURCE_CLASS_2546254\": {}}"},{"line_number":189,"context_line":"                        ]"},{"line_number":190,"context_line":"                    }"},{"line_number":191,"context_line":"                }"}],"source_content_type":"text/x-python","patch_set":32,"id":"3fa7e38b_8853d0de","line":188,"range":{"start_line":188,"start_character":52,"end_line":188,"end_character":61},"updated":"2020-01-14 21:57:18.000000000","message":"curious why these happened","commit_id":"ad50c8f8ffddb5450443af0164762202bd679116"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8f919f5a28a4bac830ce973f2344a170b9a5e7fc","unresolved":false,"context_lines":[{"line_number":185,"context_line":"                    \"inventories\": {"},{"line_number":186,"context_line":"                        \"additional\": ["},{"line_number":187,"context_line":"                            {\"CUSTOM_RESOURCE_CLASS\": {}},"},{"line_number":188,"context_line":"                            {\"INVALID_RESOURCE_CLASS_2546254\": {}}"},{"line_number":189,"context_line":"                        ]"},{"line_number":190,"context_line":"                    }"},{"line_number":191,"context_line":"                }"}],"source_content_type":"text/x-python","patch_set":32,"id":"3fa7e38b_b95a9c7f","line":188,"range":{"start_line":188,"start_character":52,"end_line":188,"end_character":61},"in_reply_to":"3fa7e38b_8853d0de","updated":"2020-01-15 02:22:29.000000000","message":"Simply to make failures easier to spot and associate in test logs. I will remove them since someone noticed and I am updating this commit anyway :)","commit_id":"ad50c8f8ffddb5450443af0164762202bd679116"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"1bd0598a7ed54b43765cc44055449bd7ca903a73","unresolved":false,"context_lines":[{"line_number":260,"context_line":"            \"Provider NAME_453764 defined in \""},{"line_number":261,"context_line":"            \"fake_path has no additional \""},{"line_number":262,"context_line":"            \"inventories or traits and will be ignored.\""},{"line_number":263,"context_line":"        )"},{"line_number":264,"context_line":""},{"line_number":265,"context_line":""},{"line_number":266,"context_line":"class GetProviderConfigsTestCases(base.BaseTestCase):"}],"source_content_type":"text/x-python","patch_set":32,"id":"3fa7e38b_e85e04e7","line":263,"updated":"2020-01-14 21:57:18.000000000","message":"and assert that we ended up with `expected`","commit_id":"ad50c8f8ffddb5450443af0164762202bd679116"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"8f919f5a28a4bac830ce973f2344a170b9a5e7fc","unresolved":false,"context_lines":[{"line_number":260,"context_line":"            \"Provider NAME_453764 defined in \""},{"line_number":261,"context_line":"            \"fake_path has no additional \""},{"line_number":262,"context_line":"            \"inventories or traits and will be ignored.\""},{"line_number":263,"context_line":"        )"},{"line_number":264,"context_line":""},{"line_number":265,"context_line":""},{"line_number":266,"context_line":"class GetProviderConfigsTestCases(base.BaseTestCase):"}],"source_content_type":"text/x-python","patch_set":32,"id":"3fa7e38b_3946aca9","line":263,"in_reply_to":"3fa7e38b_e85e04e7","updated":"2020-01-15 02:22:29.000000000","message":"Oops, thanks!","commit_id":"ad50c8f8ffddb5450443af0164762202bd679116"},{"author":{"_account_id":29745,"name":"Dustin Cowles","email":"cowlesd@gmail.com","username":"dustinc","status":"inactive"},"change_message_id":"b3991cbbfbbbe4975b8726697c183faaf202ec5b","unresolved":false,"context_lines":[{"line_number":169,"context_line":"        self.run_schema_version_matching(self.MIN_SCHEMA_VERSION,"},{"line_number":170,"context_line":"                                         self.MAX_SCHEMA_VERSION)"},{"line_number":171,"context_line":""},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"@ddt.ddt"},{"line_number":174,"context_line":"class ValidateProviderConfigTestCases(base.BaseTestCase):"},{"line_number":175,"context_line":"    @ddt.unpack"}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_e7d60a55","line":172,"updated":"2020-01-17 04:52:51.000000000","message":"There is a fair amount of duplication in the config/expected values in these two classes, but there are minor differences in each use and I feel like leaving it duplicated makes the tests less complicated and easier to follow.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":171,"context_line":""},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"@ddt.ddt"},{"line_number":174,"context_line":"class ValidateProviderConfigTestCases(base.BaseTestCase):"},{"line_number":175,"context_line":"    @ddt.unpack"},{"line_number":176,"context_line":"    @ddt.file_data(\u0027provider_config_data/validate_provider_test_data.yaml\u0027)"},{"line_number":177,"context_line":"    def test__validate_provider_config(self, sample):"}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_56ba20e0","line":174,"updated":"2020-01-17 20:13:32.000000000","message":"In the previous patch the negative test was also in a yaml file. Here only the positive tests are form the yaml but negatives are directly in python. Can we make this test suite consistent?","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"cf415a5b0d5ce45aba689a657e0f31cfbe331053","unresolved":false,"context_lines":[{"line_number":171,"context_line":""},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"@ddt.ddt"},{"line_number":174,"context_line":"class ValidateProviderConfigTestCases(base.BaseTestCase):"},{"line_number":175,"context_line":"    @ddt.unpack"},{"line_number":176,"context_line":"    @ddt.file_data(\u0027provider_config_data/validate_provider_test_data.yaml\u0027)"},{"line_number":177,"context_line":"    def test__validate_provider_config(self, sample):"}],"source_content_type":"text/x-python","patch_set":34,"id":"1fa4df85_1e4f8193","line":174,"in_reply_to":"1fa4df85_7f7938fa","updated":"2020-03-06 09:06:27.000000000","message":"In the previous patch for negative tests the exception messages was specified in the yaml test file. https://review.opendev.org/#/c/673341/39/nova/tests/unit/compute/provider_config_data/v1/validation_error_test_data.yaml\n\nI can live with either a python based or a yaml based test suite but I don\u0027t really want to have a mixed one.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"76555589b9f24f3a143cea192a1332532ab22329","unresolved":false,"context_lines":[{"line_number":171,"context_line":""},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"@ddt.ddt"},{"line_number":174,"context_line":"class ValidateProviderConfigTestCases(base.BaseTestCase):"},{"line_number":175,"context_line":"    @ddt.unpack"},{"line_number":176,"context_line":"    @ddt.file_data(\u0027provider_config_data/validate_provider_test_data.yaml\u0027)"},{"line_number":177,"context_line":"    def test__validate_provider_config(self, sample):"}],"source_content_type":"text/x-python","patch_set":34,"id":"1fa4df85_7f7938fa","line":174,"in_reply_to":"3fa7e38b_56ba20e0","updated":"2020-02-28 15:10:36.000000000","message":"i dont really like using the yaml files. i get why its convient to have tests as data but it is quite hard to debug.\n\nim going to leave this change for someone else.\nim not sure there is a good way to model raising excpeiton via the yaml file and i wont have time today to convert all the yaml based test to python so im going to focus on the other comments.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":300,"context_line":"                __name__, \u0027provider_config_data/v1/example_provider.yaml\u0027)]"},{"line_number":301,"context_line":"        actual \u003d provider_config.get_provider_configs(\u0027path\u0027)"},{"line_number":302,"context_line":""},{"line_number":303,"context_line":"        self.assertEqual(expected, actual)"},{"line_number":304,"context_line":""},{"line_number":305,"context_line":"    @mock.patch.object(provider_config, \u0027glob\u0027)"},{"line_number":306,"context_line":"    @mock.patch.object(provider_config, \u0027_parse_provider_yaml\u0027)"}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_b6c6f449","line":303,"updated":"2020-01-17 20:13:32.000000000","message":"I think you can also assert that the glob is called with the \u0027path\u0027","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":310,"context_line":"        providers \u003d ["},{"line_number":311,"context_line":"            {\"__source_file\": \"file1.yaml\","},{"line_number":312,"context_line":"             \"identification\": {"},{"line_number":313,"context_line":"                 \"uuid\": \"uuid1\""},{"line_number":314,"context_line":"             },"},{"line_number":315,"context_line":"             \"inventories\": {"},{"line_number":316,"context_line":"                 \"additional\": ["}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_3601a46e","line":313,"range":{"start_line":313,"start_character":26,"end_line":313,"end_character":31},"updated":"2020-01-17 20:13:32.000000000","message":"this is unrealistic as it should be uuid. You can use oslo_utils.fixture.uuidsentinel to generate named uuids for the tests.","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4e9ace735ac3a574cdd701bcad10d0762c0523f2","unresolved":false,"context_lines":[{"line_number":422,"context_line":"                }"},{"line_number":423,"context_line":"            }"},{"line_number":424,"context_line":"        }"},{"line_number":425,"context_line":"        mock_parser.side_effect \u003d [{\"providers\": [expected[provider]]}"},{"line_number":426,"context_line":"                                   for provider in expected]"},{"line_number":427,"context_line":"        mock_glob_return \u003d [\u0027file1.yaml\u0027, \u0027file2.yaml\u0027]"},{"line_number":428,"context_line":"        mock_glob.glob.return_value \u003d mock_glob_return"},{"line_number":429,"context_line":"        dummy_path \u003d \u0027dummy_path\u0027"}],"source_content_type":"text/x-python","patch_set":34,"id":"3fa7e38b_b6227401","line":426,"range":{"start_line":425,"start_character":34,"end_line":426,"end_character":60},"updated":"2020-01-17 20:13:32.000000000","message":"do you mean? \n\n    [{\"providers\": [provider]} for provider in expected.values()]","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"76555589b9f24f3a143cea192a1332532ab22329","unresolved":false,"context_lines":[{"line_number":422,"context_line":"                }"},{"line_number":423,"context_line":"            }"},{"line_number":424,"context_line":"        }"},{"line_number":425,"context_line":"        mock_parser.side_effect \u003d [{\"providers\": [expected[provider]]}"},{"line_number":426,"context_line":"                                   for provider in expected]"},{"line_number":427,"context_line":"        mock_glob_return \u003d [\u0027file1.yaml\u0027, \u0027file2.yaml\u0027]"},{"line_number":428,"context_line":"        mock_glob.glob.return_value \u003d mock_glob_return"},{"line_number":429,"context_line":"        dummy_path \u003d \u0027dummy_path\u0027"}],"source_content_type":"text/x-python","patch_set":34,"id":"1fa4df85_3a5aeef2","line":426,"range":{"start_line":425,"start_character":34,"end_line":426,"end_character":60},"in_reply_to":"3fa7e38b_b6227401","updated":"2020-02-28 15:10:36.000000000","message":"Done","commit_id":"4ce0af574c71d205652f22932542aa176c40f38c"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"5a54120619e25a73dd74381e6880182fbecf2d44","unresolved":false,"context_lines":[{"line_number":13,"context_line":"import copy"},{"line_number":14,"context_line":"import os"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"from unittest import mock"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"import ddt"},{"line_number":19,"context_line":"import fixtures"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_766c259c","line":16,"updated":"2020-07-22 13:15:28.000000000","message":"This should be part of the below group","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":13,"context_line":"import copy"},{"line_number":14,"context_line":"import os"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"from unittest import mock"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"import ddt"},{"line_number":19,"context_line":"import fixtures"}],"source_content_type":"text/x-python","patch_set":47,"id":"9f560f44_51280a85","line":16,"in_reply_to":"bf51134e_766c259c","updated":"2020-07-30 03:48:31.000000000","message":"moved per my understanding... if not correct, move again.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"a3034f389e759e7afbe4d1462e2df9989df288d0","unresolved":false,"context_lines":[{"line_number":178,"context_line":"        self.run_schema_version_matching(self.MIN_SCHEMA_VERSION,"},{"line_number":179,"context_line":"                                         self.MAX_SCHEMA_VERSION)"},{"line_number":180,"context_line":""},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"@ddt.ddt"},{"line_number":183,"context_line":"class ValidateProviderConfigTestCases(base.BaseTestCase):"},{"line_number":184,"context_line":"    @ddt.unpack"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_8050a860","line":181,"updated":"2020-07-21 14:39:33.000000000","message":"I still think that the negative tests should be in the same format as the other test for the provider config. Please continue work on this as a follow up.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"a2ff36def4055fcc74b8fbd6dd0af27d8ef5b665","unresolved":false,"context_lines":[{"line_number":178,"context_line":"        self.run_schema_version_matching(self.MIN_SCHEMA_VERSION,"},{"line_number":179,"context_line":"                                         self.MAX_SCHEMA_VERSION)"},{"line_number":180,"context_line":""},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"@ddt.ddt"},{"line_number":183,"context_line":"class ValidateProviderConfigTestCases(base.BaseTestCase):"},{"line_number":184,"context_line":"    @ddt.unpack"}],"source_content_type":"text/x-python","patch_set":47,"id":"bf51134e_5a62edd9","line":181,"in_reply_to":"bf51134e_8050a860","updated":"2020-07-30 03:48:31.000000000","message":"will add a TODO(tony) according to gibi: negative tests should be in the same format as the other test for the provider config.","commit_id":"7cf5fdce723cc191461ccdfd85f432ca0c746370"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"2ae8ec3c2789971560fb65e590e63ebb44fd8c51","unresolved":false,"context_lines":[{"line_number":15,"context_line":"import fixtures"},{"line_number":16,"context_line":"import microversion_parse"},{"line_number":17,"context_line":"import os"},{"line_number":18,"context_line":"import pkg_resources"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"from unittest import mock"},{"line_number":21,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_156f2cfc","line":18,"updated":"2020-08-06 09:07:13.000000000","message":"nit: this isn\u0027t a first-party library","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"405c32f295c3808a6719f90076ff3382e171e95b","unresolved":false,"context_lines":[{"line_number":15,"context_line":"import fixtures"},{"line_number":16,"context_line":"import microversion_parse"},{"line_number":17,"context_line":"import os"},{"line_number":18,"context_line":"import pkg_resources"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"from unittest import mock"},{"line_number":21,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_1071e876","line":18,"in_reply_to":"9f560f44_156f2cfc","updated":"2020-08-07 02:05:50.000000000","message":"remove code using pkg_resources; instead, using os.path functions","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"2ae8ec3c2789971560fb65e590e63ebb44fd8c51","unresolved":false,"context_lines":[{"line_number":18,"context_line":"import pkg_resources"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"from unittest import mock"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"from oslo_utils.fixture import uuidsentinel"},{"line_number":23,"context_line":"from oslotest import base"},{"line_number":24,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_d56814f6","line":21,"updated":"2020-08-06 09:07:13.000000000","message":"nit: drop space","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"405c32f295c3808a6719f90076ff3382e171e95b","unresolved":false,"context_lines":[{"line_number":18,"context_line":"import pkg_resources"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"from unittest import mock"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"from oslo_utils.fixture import uuidsentinel"},{"line_number":23,"context_line":"from oslotest import base"},{"line_number":24,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_903338ab","line":21,"in_reply_to":"9f560f44_d56814f6","updated":"2020-08-07 02:05:50.000000000","message":"keep no code change here. \n\nafter dropping space of line 21, I had to move \u0027from unittest import mock\u0027 just below line 23 or line 26 to pass PEP8 check, which looks a little bit wird as unittest is actually a standard library but other two groups are oslo library and nova package.","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"2ae8ec3c2789971560fb65e590e63ebb44fd8c51","unresolved":false,"context_lines":[{"line_number":310,"context_line":"            }}"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        mock_glob.glob.return_value \u003d ["},{"line_number":313,"context_line":"            pkg_resources.resource_filename("},{"line_number":314,"context_line":"                __name__, \u0027provider_config_data/v1/example_provider.yaml\u0027)]"},{"line_number":315,"context_line":"        actual \u003d provider_config.get_provider_configs(\u0027path\u0027)"},{"line_number":316,"context_line":""},{"line_number":317,"context_line":"        self.assertEqual(expected, actual)"}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_f5339812","line":314,"range":{"start_line":313,"start_character":0,"end_line":314,"end_character":75},"updated":"2020-08-06 09:07:13.000000000","message":"Do we need this? pkg_resources is slow and all you want is to get the file relative to the current directory, right? If so, could we just give a relative path? Alternatively, we could get the directory this test file is stored in (see [1]) and build an absolute path from that\n\n[1] https://stackoverflow.com/a/9350788/613428","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"},{"author":{"_account_id":30192,"name":"Tony Su","email":"tao.su@intel.com","username":"tsu5"},"change_message_id":"405c32f295c3808a6719f90076ff3382e171e95b","unresolved":false,"context_lines":[{"line_number":310,"context_line":"            }}"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        mock_glob.glob.return_value \u003d ["},{"line_number":313,"context_line":"            pkg_resources.resource_filename("},{"line_number":314,"context_line":"                __name__, \u0027provider_config_data/v1/example_provider.yaml\u0027)]"},{"line_number":315,"context_line":"        actual \u003d provider_config.get_provider_configs(\u0027path\u0027)"},{"line_number":316,"context_line":""},{"line_number":317,"context_line":"        self.assertEqual(expected, actual)"}],"source_content_type":"text/x-python","patch_set":50,"id":"9f560f44_b062bcac","line":314,"range":{"start_line":313,"start_character":0,"end_line":314,"end_character":75},"in_reply_to":"9f560f44_f5339812","updated":"2020-08-07 02:05:50.000000000","message":"remove code using pkg_resource, instead use more common os.path functions.","commit_id":"9c597379a2a103877a4b29e5aea574243fcc1b57"}]}
