)]}'
{"doc/source/contributor/webapi-version-history.rst":[{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"7141c73275e378e0c1818d570f9d9a80d27c9a65","unresolved":false,"context_lines":[{"line_number":5,"context_line":"1.55 (Stein, master)"},{"line_number":6,"context_line":"--------------------"},{"line_number":7,"context_line":""},{"line_number":8,"context_line":"Added new the following new endpoints for deploy templates:"},{"line_number":9,"context_line":""},{"line_number":10,"context_line":"* GET /v1/deploy-templates"},{"line_number":11,"context_line":"* GET /v1/deploy-templates/\u003cdeploy template identifier\u003e"}],"source_content_type":"text/x-rst","patch_set":6,"id":"9fdfeff1_00d39902","line":8,"updated":"2019-02-27 18:03:51.000000000","message":"s/Added new/Added/","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"93b8e073d2c407aa1ee0fb768c6c2307a7ea3c14","unresolved":false,"context_lines":[{"line_number":5,"context_line":"1.55 (Stein, master)"},{"line_number":6,"context_line":"--------------------"},{"line_number":7,"context_line":""},{"line_number":8,"context_line":"Added new the following new endpoints for deploy templates:"},{"line_number":9,"context_line":""},{"line_number":10,"context_line":"* GET /v1/deploy-templates"},{"line_number":11,"context_line":"* GET /v1/deploy-templates/\u003cdeploy template identifier\u003e"}],"source_content_type":"text/x-rst","patch_set":6,"id":"9fdfeff1_2b323911","line":8,"in_reply_to":"9fdfeff1_00d39902","updated":"2019-02-28 10:34:08.000000000","message":"Done","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":24828,"name":"Kaifeng Wang","email":"kaifeng.w@gmail.com","username":"wangkf"},"change_message_id":"384b19992ffbbd0e3cf2753761a8ecc05beb511e","unresolved":false,"context_lines":[{"line_number":7,"context_line":""},{"line_number":8,"context_line":"Added new the following new endpoints for deploy templates:"},{"line_number":9,"context_line":""},{"line_number":10,"context_line":"* GET /v1/deploy-templates"},{"line_number":11,"context_line":"* GET /v1/deploy-templates/\u003cdeploy template identifier\u003e"},{"line_number":12,"context_line":"* POST /v1/deploy-templates"},{"line_number":13,"context_line":"* PATCH /v1/deploy-templates/\u003cdeploy template identifier\u003e"}],"source_content_type":"text/x-rst","patch_set":6,"id":"9fdfeff1_2197cc47","line":10,"range":{"start_line":10,"start_character":10,"end_line":10,"end_character":26},"updated":"2019-02-27 09:43:27.000000000","message":"I think the endpoint should be deploy_templates (the underline).","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"a95fe7dfbb7531ad043fd954713da82d2c2a5875","unresolved":false,"context_lines":[{"line_number":7,"context_line":""},{"line_number":8,"context_line":"Added new the following new endpoints for deploy templates:"},{"line_number":9,"context_line":""},{"line_number":10,"context_line":"* GET /v1/deploy-templates"},{"line_number":11,"context_line":"* GET /v1/deploy-templates/\u003cdeploy template identifier\u003e"},{"line_number":12,"context_line":"* POST /v1/deploy-templates"},{"line_number":13,"context_line":"* PATCH /v1/deploy-templates/\u003cdeploy template identifier\u003e"}],"source_content_type":"text/x-rst","patch_set":6,"id":"9fdfeff1_87b3289a","line":10,"range":{"start_line":10,"start_character":10,"end_line":10,"end_character":26},"in_reply_to":"9fdfeff1_2197cc47","updated":"2019-02-27 10:54:44.000000000","message":"Done","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"7141c73275e378e0c1818d570f9d9a80d27c9a65","unresolved":false,"context_lines":[{"line_number":11,"context_line":"* GET /v1/deploy-templates/\u003cdeploy template identifier\u003e"},{"line_number":12,"context_line":"* POST /v1/deploy-templates"},{"line_number":13,"context_line":"* PATCH /v1/deploy-templates/\u003cdeploy template identifier\u003e"},{"line_number":14,"context_line":"* DELETE /v1/deploy-templates/\u003cdeploy template identifier\u003e"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"1.54 (Stein, master)"},{"line_number":17,"context_line":"--------------------"}],"source_content_type":"text/x-rst","patch_set":6,"id":"9fdfeff1_00ddd9db","line":14,"updated":"2019-02-27 18:03:51.000000000","message":"I was looking at the output and other descriptions (eg L37 or L151). Wonder if it would be good to add more info\n\nGET /v1/deploy_templates to list all deploy templates\netc\n\nBut then there\u0027s L296. Although I guess more description is better than less...","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"93b8e073d2c407aa1ee0fb768c6c2307a7ea3c14","unresolved":false,"context_lines":[{"line_number":11,"context_line":"* GET /v1/deploy-templates/\u003cdeploy template identifier\u003e"},{"line_number":12,"context_line":"* POST /v1/deploy-templates"},{"line_number":13,"context_line":"* PATCH /v1/deploy-templates/\u003cdeploy template identifier\u003e"},{"line_number":14,"context_line":"* DELETE /v1/deploy-templates/\u003cdeploy template identifier\u003e"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"1.54 (Stein, master)"},{"line_number":17,"context_line":"--------------------"}],"source_content_type":"text/x-rst","patch_set":6,"id":"9fdfeff1_8b51e532","line":14,"in_reply_to":"9fdfeff1_00ddd9db","updated":"2019-02-28 10:34:08.000000000","message":"Done","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":11,"context_line":"* GET /v1/deploy_templates/\u003cdeploy template identifier\u003e"},{"line_number":12,"context_line":"* POST /v1/deploy_templates"},{"line_number":13,"context_line":"* PATCH /v1/deploy_templates/\u003cdeploy template identifier\u003e"},{"line_number":14,"context_line":"* DELETE /v1/deploy_templates/\u003cdeploy template identifier\u003e"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"1.54 (Stein, master)"},{"line_number":17,"context_line":"--------------------"}],"source_content_type":"text/x-rst","patch_set":7,"id":"9fdfeff1_219fa3b4","line":14,"updated":"2019-02-28 15:00:12.000000000","message":"The spec uses dashes instead of underscores, and I quite agree it seems more organic. But it seems that we\u0027re already using underscores everywhere. Sigh.","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":11,"context_line":"* GET /v1/deploy_templates/\u003cdeploy template identifier\u003e"},{"line_number":12,"context_line":"* POST /v1/deploy_templates"},{"line_number":13,"context_line":"* PATCH /v1/deploy_templates/\u003cdeploy template identifier\u003e"},{"line_number":14,"context_line":"* DELETE /v1/deploy_templates/\u003cdeploy template identifier\u003e"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"1.54 (Stein, master)"},{"line_number":17,"context_line":"--------------------"}],"source_content_type":"text/x-rst","patch_set":7,"id":"9fdfeff1_ce558d1f","line":14,"in_reply_to":"9fdfeff1_219fa3b4","updated":"2019-03-01 12:05:33.000000000","message":"Yeah, dashes \u003e underscores, but I had issues getting dashes to work. Also, the few other examples in the API all use underscores.","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"}],"ironic/api/controllers/base.py":[{"author":{"_account_id":24828,"name":"Kaifeng Wang","email":"kaifeng.w@gmail.com","username":"wangkf"},"change_message_id":"384b19992ffbbd0e3cf2753761a8ecc05beb511e","unresolved":false,"context_lines":[{"line_number":34,"context_line":"            # Recursively evaluate objects that support as_dict()."},{"line_number":35,"context_line":"            try:"},{"line_number":36,"context_line":"                return attr.as_dict()"},{"line_number":37,"context_line":"            except AttributeError:"},{"line_number":38,"context_line":"                return attr"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"        return dict((k, _attr_as_pod(getattr(self, k)))"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_a10f3cde","line":37,"range":{"start_line":37,"start_character":19,"end_line":37,"end_character":33},"updated":"2019-02-27 09:43:27.000000000","message":"It appears this would never happen, we can just return attr.as_dict().","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"a95fe7dfbb7531ad043fd954713da82d2c2a5875","unresolved":false,"context_lines":[{"line_number":34,"context_line":"            # Recursively evaluate objects that support as_dict()."},{"line_number":35,"context_line":"            try:"},{"line_number":36,"context_line":"                return attr.as_dict()"},{"line_number":37,"context_line":"            except AttributeError:"},{"line_number":38,"context_line":"                return attr"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"        return dict((k, _attr_as_pod(getattr(self, k)))"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_475f8040","line":37,"range":{"start_line":37,"start_character":19,"end_line":37,"end_character":33},"in_reply_to":"9fdfeff1_a10f3cde","updated":"2019-02-27 10:54:44.000000000","message":"If the attribute is a plain data type (e.g. int), it won\u0027t support as_dict. We can just return those types directly.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"}],"ironic/api/controllers/v1/deploy_template.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":47,"context_line":"    wtypes.text, *conductor_utils.DEPLOYING_INTERFACE_PRIORITY)"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def get_deploy_templates_controller_reserved_names():"},{"line_number":51,"context_line":"    global _DEPLOY_TEMPLATES_CONTROLLER_RESERVED_WORDS"},{"line_number":52,"context_line":"    if _DEPLOY_TEMPLATES_CONTROLLER_RESERVED_WORDS is None:"},{"line_number":53,"context_line":"        _DEPLOY_TEMPLATES_CONTROLLER_RESERVED_WORDS \u003d ("}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_a247f54b","line":50,"updated":"2019-02-18 11:54:43.000000000","message":"Please remove. This is workaround for the ugly /detail design which we should not cargo-cult to new endpoints (also see below).","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"f9cafd47c1e61a79c30ffd94c0c85ee587900598","unresolved":false,"context_lines":[{"line_number":47,"context_line":"    wtypes.text, *conductor_utils.DEPLOYING_INTERFACE_PRIORITY)"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"def get_deploy_templates_controller_reserved_names():"},{"line_number":51,"context_line":"    global _DEPLOY_TEMPLATES_CONTROLLER_RESERVED_WORDS"},{"line_number":52,"context_line":"    if _DEPLOY_TEMPLATES_CONTROLLER_RESERVED_WORDS is None:"},{"line_number":53,"context_line":"        _DEPLOY_TEMPLATES_CONTROLLER_RESERVED_WORDS \u003d ("}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_93f437f3","line":50,"in_reply_to":"9fdfeff1_a247f54b","updated":"2019-02-27 09:27:40.000000000","message":"Done","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":61,"context_line":"        raise exception.NotFound()"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"def _check_policy(policy_name):"},{"line_number":65,"context_line":"    cdict \u003d pecan.request.context.to_policy_values()"},{"line_number":66,"context_line":"    policy.authorize(policy_name, cdict, cdict)"},{"line_number":67,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_c242393b","line":64,"updated":"2019-02-18 11:54:43.000000000","message":"Let us move this to API utils for the other controllers to use.","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"f9cafd47c1e61a79c30ffd94c0c85ee587900598","unresolved":false,"context_lines":[{"line_number":61,"context_line":"        raise exception.NotFound()"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"def _check_policy(policy_name):"},{"line_number":65,"context_line":"    cdict \u003d pecan.request.context.to_policy_values()"},{"line_number":66,"context_line":"    policy.authorize(policy_name, cdict, cdict)"},{"line_number":67,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_26caeb4e","line":64,"in_reply_to":"9fdfeff1_c242393b","updated":"2019-02-27 09:27:40.000000000","message":"Done","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    links \u003d wsme.wsattr([link.Link])"},{"line_number":100,"context_line":"    \"\"\"A list containing a self link and associated deploy template links.\"\"\""},{"line_number":101,"context_line":""},{"line_number":102,"context_line":"    def __init__(self, **kwargs):"},{"line_number":103,"context_line":"        self.fields \u003d []"},{"line_number":104,"context_line":"        fields \u003d list(objects.DeployTemplate.fields)"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_6277cda1","line":101,"updated":"2019-02-18 11:54:43.000000000","message":"This misses the semi-standard \u0027extra\u0027 field. Is it intentional?","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"f9cafd47c1e61a79c30ffd94c0c85ee587900598","unresolved":false,"context_lines":[{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    links \u003d wsme.wsattr([link.Link])"},{"line_number":100,"context_line":"    \"\"\"A list containing a self link and associated deploy template links.\"\"\""},{"line_number":101,"context_line":""},{"line_number":102,"context_line":"    def __init__(self, **kwargs):"},{"line_number":103,"context_line":"        self.fields \u003d []"},{"line_number":104,"context_line":"        fields \u003d list(objects.DeployTemplate.fields)"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_66e553dc","line":101,"in_reply_to":"9fdfeff1_6277cda1","updated":"2019-02-27 09:27:40.000000000","message":"It wasn\u0027t in the spec, so I didn\u0027t add it. Do you think it would be useful?","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":193,"context_line":"    \"\"\"A list containing deploy template objects\"\"\""},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"    def __init__(self, **kwargs):"},{"line_number":196,"context_line":"        self._type \u003d \u0027deploy_templates\u0027"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    @staticmethod"},{"line_number":199,"context_line":"    def convert_with_links(templates, limit, url\u003dNone, fields\u003dNone, **kwargs):"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_827af184","line":196,"updated":"2019-02-18 11:54:43.000000000","message":"nit: move to a class-level constant?","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"f9cafd47c1e61a79c30ffd94c0c85ee587900598","unresolved":false,"context_lines":[{"line_number":193,"context_line":"    \"\"\"A list containing deploy template objects\"\"\""},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"    def __init__(self, **kwargs):"},{"line_number":196,"context_line":"        self._type \u003d \u0027deploy_templates\u0027"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"    @staticmethod"},{"line_number":199,"context_line":"    def convert_with_links(templates, limit, url\u003dNone, fields\u003dNone, **kwargs):"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_e6d8631f","line":196,"in_reply_to":"9fdfeff1_827af184","updated":"2019-02-27 09:27:40.000000000","message":"Done","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":220,"context_line":"    \"\"\"REST controller for deploy templates.\"\"\""},{"line_number":221,"context_line":""},{"line_number":222,"context_line":"    _custom_actions \u003d {"},{"line_number":223,"context_line":"        \u0027detail\u0027: [\u0027GET\u0027],"},{"line_number":224,"context_line":"    }"},{"line_number":225,"context_line":""},{"line_number":226,"context_line":"    invalid_sort_key_list \u003d [\u0027steps\u0027]"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_226d45cb","line":223,"updated":"2019-02-18 11:54:43.000000000","message":"Please don\u0027t do it like this, use detail\u003d{True,False} instead.","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"f9cafd47c1e61a79c30ffd94c0c85ee587900598","unresolved":false,"context_lines":[{"line_number":220,"context_line":"    \"\"\"REST controller for deploy templates.\"\"\""},{"line_number":221,"context_line":""},{"line_number":222,"context_line":"    _custom_actions \u003d {"},{"line_number":223,"context_line":"        \u0027detail\u0027: [\u0027GET\u0027],"},{"line_number":224,"context_line":"    }"},{"line_number":225,"context_line":""},{"line_number":226,"context_line":"    invalid_sort_key_list \u003d [\u0027steps\u0027]"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_46660f58","line":223,"in_reply_to":"9fdfeff1_226d45cb","updated":"2019-02-27 09:27:40.000000000","message":"Done","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":267,"context_line":"        :raises: exception.NotAcceptable"},{"line_number":268,"context_line":"        :raises: wsme.exc.ClientSideError"},{"line_number":269,"context_line":"        \"\"\""},{"line_number":270,"context_line":"        reserved_names \u003d get_deploy_templates_controller_reserved_names()"},{"line_number":271,"context_line":"        for name in names:"},{"line_number":272,"context_line":"            if not api_utils.is_valid_deploy_template_name(name):"},{"line_number":273,"context_line":"                raise wsme.exc.ClientSideError("}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_427089a4","line":270,"updated":"2019-02-18 11:54:43.000000000","message":"Please remove (see above)","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"f9cafd47c1e61a79c30ffd94c0c85ee587900598","unresolved":false,"context_lines":[{"line_number":267,"context_line":"        :raises: exception.NotAcceptable"},{"line_number":268,"context_line":"        :raises: wsme.exc.ClientSideError"},{"line_number":269,"context_line":"        \"\"\""},{"line_number":270,"context_line":"        reserved_names \u003d get_deploy_templates_controller_reserved_names()"},{"line_number":271,"context_line":"        for name in names:"},{"line_number":272,"context_line":"            if not api_utils.is_valid_deploy_template_name(name):"},{"line_number":273,"context_line":"                raise wsme.exc.ClientSideError("}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_a6933b00","line":270,"in_reply_to":"9fdfeff1_427089a4","updated":"2019-02-27 09:27:40.000000000","message":"Done","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":319,"context_line":"        _check_api_version()"},{"line_number":320,"context_line":"        _check_policy(\u0027baremetal:deploy_template:get\u0027)"},{"line_number":321,"context_line":""},{"line_number":322,"context_line":"        api_utils.check_allow_specify_fields(fields)"},{"line_number":323,"context_line":"        api_utils.check_allowed_fields(fields)"},{"line_number":324,"context_line":"        api_utils.check_allowed_fields([sort_key])"},{"line_number":325,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_e26addb0","line":322,"updated":"2019-02-18 11:54:43.000000000","message":"This call checks for API \u003e\u003d 1.8, which is obviously true after _check_api_version. Please remove from all methods.","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"f9cafd47c1e61a79c30ffd94c0c85ee587900598","unresolved":false,"context_lines":[{"line_number":319,"context_line":"        _check_api_version()"},{"line_number":320,"context_line":"        _check_policy(\u0027baremetal:deploy_template:get\u0027)"},{"line_number":321,"context_line":""},{"line_number":322,"context_line":"        api_utils.check_allow_specify_fields(fields)"},{"line_number":323,"context_line":"        api_utils.check_allowed_fields(fields)"},{"line_number":324,"context_line":"        api_utils.check_allowed_fields([sort_key])"},{"line_number":325,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_e6a94324","line":322,"in_reply_to":"9fdfeff1_e26addb0","updated":"2019-02-27 09:27:40.000000000","message":"Done","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":332,"context_line":"    @METRICS.timer(\u0027DeployTemplatesController.detail\u0027)"},{"line_number":333,"context_line":"    @expose.expose(DeployTemplateCollection, types.uuid_or_name,"},{"line_number":334,"context_line":"                   types.uuid, wtypes.text, wtypes.text)"},{"line_number":335,"context_line":"    def detail(self, marker\u003dNone, limit\u003dNone, sort_key\u003d\u0027id\u0027, sort_dir\u003d\u0027asc\u0027):"},{"line_number":336,"context_line":"        \"\"\"Retrieve a list of deploy templates with detail."},{"line_number":337,"context_line":""},{"line_number":338,"context_line":"        :param marker: pagination marker for large data sets."}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_026601ee","line":335,"updated":"2019-02-18 11:54:43.000000000","message":"Please merge into get_all(detail\u003dTrue)","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"f9cafd47c1e61a79c30ffd94c0c85ee587900598","unresolved":false,"context_lines":[{"line_number":332,"context_line":"    @METRICS.timer(\u0027DeployTemplatesController.detail\u0027)"},{"line_number":333,"context_line":"    @expose.expose(DeployTemplateCollection, types.uuid_or_name,"},{"line_number":334,"context_line":"                   types.uuid, wtypes.text, wtypes.text)"},{"line_number":335,"context_line":"    def detail(self, marker\u003dNone, limit\u003dNone, sort_key\u003d\u0027id\u0027, sort_dir\u003d\u0027asc\u0027):"},{"line_number":336,"context_line":"        \"\"\"Retrieve a list of deploy templates with detail."},{"line_number":337,"context_line":""},{"line_number":338,"context_line":"        :param marker: pagination marker for large data sets."}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_0653273b","line":335,"in_reply_to":"9fdfeff1_026601ee","updated":"2019-02-27 09:27:40.000000000","message":"Done","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ea067d7338d5386830110d8ce468012ebfaec3f","unresolved":false,"context_lines":[{"line_number":348,"context_line":""},{"line_number":349,"context_line":"        api_utils.check_allowed_fields([sort_key])"},{"line_number":350,"context_line":""},{"line_number":351,"context_line":"        # NOTE: /detail should only work against collections"},{"line_number":352,"context_line":"        parent \u003d pecan.request.path.split(\u0027/\u0027)[:-1][-1]"},{"line_number":353,"context_line":"        if parent !\u003d \"deploy_templates\":"},{"line_number":354,"context_line":"            raise exception.HTTPNotFound()"}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_a26055d0","line":351,"updated":"2019-02-18 11:54:43.000000000","message":"And this is yet another reason to not do it :)","commit_id":"bd1a56ce3376787c8952c025de20249e421647ff"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"7141c73275e378e0c1818d570f9d9a80d27c9a65","unresolved":false,"context_lines":[{"line_number":148,"context_line":"            raise exception.InvalidDeployTemplate(err\u003derr)"},{"line_number":149,"context_line":""},{"line_number":150,"context_line":"        # Check for duplicate steps. Each interface/step combination can be"},{"line_number":151,"context_line":"        # specified at most once."},{"line_number":152,"context_line":"        counter \u003d collections.Counter([(step.interface, step.step)"},{"line_number":153,"context_line":"                                       for step in value.steps])"},{"line_number":154,"context_line":"        duplicates \u003d {key for key, count in counter.items() if count \u003e 1}"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_7abd6daf","line":151,"updated":"2019-02-27 18:03:51.000000000","message":"I thought I saw somewhere, that it can be specified more than once. In the spec [1]:\nIt is acceptable to request the same deploy step more than once. This could be done to execute a deploy step multiple times with different arguments, for example to partition multiple disks.\n\n[1] https://github.com/openstack/ironic-specs/blob/master/specs/approved/deploy-templates.rst","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"4ed8bb1bdc8870c4db7112c7dfebcdeb6e1608ec","unresolved":false,"context_lines":[{"line_number":148,"context_line":"            raise exception.InvalidDeployTemplate(err\u003derr)"},{"line_number":149,"context_line":""},{"line_number":150,"context_line":"        # Check for duplicate steps. Each interface/step combination can be"},{"line_number":151,"context_line":"        # specified at most once."},{"line_number":152,"context_line":"        counter \u003d collections.Counter([(step.interface, step.step)"},{"line_number":153,"context_line":"                                       for step in value.steps])"},{"line_number":154,"context_line":"        duplicates \u003d {key for key, count in counter.items() if count \u003e 1}"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_21cb231e","line":151,"in_reply_to":"9fdfeff1_06cc0cb9","updated":"2019-02-28 16:03:06.000000000","message":"I\u0027m good with only allowing unique steps for the first round. Maybe put a #TODO or something?","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":148,"context_line":"            raise exception.InvalidDeployTemplate(err\u003derr)"},{"line_number":149,"context_line":""},{"line_number":150,"context_line":"        # Check for duplicate steps. Each interface/step combination can be"},{"line_number":151,"context_line":"        # specified at most once."},{"line_number":152,"context_line":"        counter \u003d collections.Counter([(step.interface, step.step)"},{"line_number":153,"context_line":"                                       for step in value.steps])"},{"line_number":154,"context_line":"        duplicates \u003d {key for key, count in counter.items() if count \u003e 1}"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_6effc165","line":151,"in_reply_to":"9fdfeff1_21cb231e","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"93b8e073d2c407aa1ee0fb768c6c2307a7ea3c14","unresolved":false,"context_lines":[{"line_number":148,"context_line":"            raise exception.InvalidDeployTemplate(err\u003derr)"},{"line_number":149,"context_line":""},{"line_number":150,"context_line":"        # Check for duplicate steps. Each interface/step combination can be"},{"line_number":151,"context_line":"        # specified at most once."},{"line_number":152,"context_line":"        counter \u003d collections.Counter([(step.interface, step.step)"},{"line_number":153,"context_line":"                                       for step in value.steps])"},{"line_number":154,"context_line":"        duplicates \u003d {key for key, count in counter.items() if count \u003e 1}"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_06cc0cb9","line":151,"in_reply_to":"9fdfeff1_7abd6daf","updated":"2019-02-28 10:34:08.000000000","message":"Eagle eyed as ever :)\n\nA previous revision of the spec stated that it would work this way - steps must be unique. I updated it to allow duplicates, to allow calling the same deploy step multiple times.\n\nDuring implementation I realised that this could get a bit weird - what if one has a zero priority and another has non-zero? For (non-core) steps enabled by default, does a step in a deploy template override it or add a second invocation?\n\nRather than thinking too hard about this I cowardly reverted to the simple design of not allowing duplicates, figuring it would be easier to allow duplicates in future than the reverse.\n\nIt would probably not be too much effort to change it, but I wanted to get the framework in place and ready for review.\n\nWhile I\u0027ve got you thinking about this, what\u0027s your opinion?","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"7141c73275e378e0c1818d570f9d9a80d27c9a65","unresolved":false,"context_lines":[{"line_number":198,"context_line":"        :type fields: list of str"},{"line_number":199,"context_line":"        \"\"\""},{"line_number":200,"context_line":"        if fields is not None:"},{"line_number":201,"context_line":"            self.unset_fields_except(fields)"},{"line_number":202,"context_line":""},{"line_number":203,"context_line":"    @classmethod"},{"line_number":204,"context_line":"    def sample(cls, expand\u003dTrue):"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_5a1e69bb","line":201,"updated":"2019-02-27 18:03:51.000000000","message":"Wondering if an operator would specify a password as an arg to a deploy step.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"93b8e073d2c407aa1ee0fb768c6c2307a7ea3c14","unresolved":false,"context_lines":[{"line_number":198,"context_line":"        :type fields: list of str"},{"line_number":199,"context_line":"        \"\"\""},{"line_number":200,"context_line":"        if fields is not None:"},{"line_number":201,"context_line":"            self.unset_fields_except(fields)"},{"line_number":202,"context_line":""},{"line_number":203,"context_line":"    @classmethod"},{"line_number":204,"context_line":"    def sample(cls, expand\u003dTrue):"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_669b9872","line":201,"in_reply_to":"9fdfeff1_5a1e69bb","updated":"2019-02-28 10:34:08.000000000","message":"Fair point, can\u0027t hurt to check.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"7141c73275e378e0c1818d570f9d9a80d27c9a65","unresolved":false,"context_lines":[{"line_number":339,"context_line":"            templates, limit, fields\u003dfields, **parameters)"},{"line_number":340,"context_line":""},{"line_number":341,"context_line":"    @METRICS.timer(\u0027DeployTemplatesController.get_one\u0027)"},{"line_number":342,"context_line":"    @expose.expose(DeployTemplate, types.name, types.listtype)"},{"line_number":343,"context_line":"    def get_one(self, template_ident, fields\u003dNone):"},{"line_number":344,"context_line":"        \"\"\"Retrieve information about the given deploy template."},{"line_number":345,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_7d5b2721","line":342,"updated":"2019-02-27 18:03:51.000000000","message":"If the template_ident can be a UUID or name, shouldn\u0027t it be s/types.name/types.uuid_or_name/ ?","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"93b8e073d2c407aa1ee0fb768c6c2307a7ea3c14","unresolved":false,"context_lines":[{"line_number":339,"context_line":"            templates, limit, fields\u003dfields, **parameters)"},{"line_number":340,"context_line":""},{"line_number":341,"context_line":"    @METRICS.timer(\u0027DeployTemplatesController.get_one\u0027)"},{"line_number":342,"context_line":"    @expose.expose(DeployTemplate, types.name, types.listtype)"},{"line_number":343,"context_line":"    def get_one(self, template_ident, fields\u003dNone):"},{"line_number":344,"context_line":"        \"\"\"Retrieve information about the given deploy template."},{"line_number":345,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_c6d604c4","line":342,"in_reply_to":"9fdfeff1_7d5b2721","updated":"2019-02-28 10:34:08.000000000","message":"Probably. I guess a UUID is probably a valid types.name so it works, but I will change.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"7141c73275e378e0c1818d570f9d9a80d27c9a65","unresolved":false,"context_lines":[{"line_number":414,"context_line":""},{"line_number":415,"context_line":"        notify.emit_start_notification(context, rpc_template, \u0027update\u0027)"},{"line_number":416,"context_line":"        with notify.handle_error_notification(context, rpc_template, \u0027update\u0027):"},{"line_number":417,"context_line":"            rpc_template.save()"},{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        api_template \u003d DeployTemplate.convert_with_links(rpc_template)"},{"line_number":420,"context_line":"        notify.emit_end_notification(context, rpc_template, \u0027update\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_3d183fd1","line":417,"updated":"2019-02-27 18:03:51.000000000","message":"Hmm.\n\nIf a node has a trait that corresponds to this one and is being deployed right now, is it OK to change the deploy template? I\u0027ve lost track of what we allow to change in a deploy template -- name \u0026 steps?\n\nHaving said that, I\u0027m not sure what sort of validation a conductor could do.\n\nI\u0027ve already forgotten how rolling upgrades work. For whatever reason, I feel like during a rolling upgrade, the conductor is the one that needs to update/modify an object based on the pinned version but I\u0027m too lazy to look into it. I think this could be a problem if we have a new version of the deploy_template object.\n\nI suppose we can look into this later.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"93b8e073d2c407aa1ee0fb768c6c2307a7ea3c14","unresolved":false,"context_lines":[{"line_number":414,"context_line":""},{"line_number":415,"context_line":"        notify.emit_start_notification(context, rpc_template, \u0027update\u0027)"},{"line_number":416,"context_line":"        with notify.handle_error_notification(context, rpc_template, \u0027update\u0027):"},{"line_number":417,"context_line":"            rpc_template.save()"},{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        api_template \u003d DeployTemplate.convert_with_links(rpc_template)"},{"line_number":420,"context_line":"        notify.emit_end_notification(context, rpc_template, \u0027update\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_d8956fe5","line":417,"in_reply_to":"9fdfeff1_3d183fd1","updated":"2019-02-28 10:34:08.000000000","message":"It\u0027s definitely worth clearing this up. I think if we add any notion of \u0027ownership\u0027 or \u0027attachment\u0027 between a node and templates, things could get quite messy. We\u0027d essentially need to lookup the instance_info.traits for every deployed node, and see if the template\u0027s name matches any of those. We couldn\u0027t hold the lock for every node simultaneously, so it would always be racy.\n\nThe way it works in my head (and currently in the WIP conductor patch) is that the conductor queries the matching templates during deployment to build a snapshot of the list of steps. We use whatever templates are present at the time, and don\u0027t form any attachment to them. A later rebuild would generate the list of steps again, which could be different (including due to driver/config changes for non-template steps).\n\nThe rolling upgrade question is interesting. I guess the case that might be a problem is if another unpinned API saved a new object, a pinned API could lose data by saving? I\u0027ll let you mull that one over, I can add the RPC methods if necessary.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":414,"context_line":""},{"line_number":415,"context_line":"        notify.emit_start_notification(context, rpc_template, \u0027update\u0027)"},{"line_number":416,"context_line":"        with notify.handle_error_notification(context, rpc_template, \u0027update\u0027):"},{"line_number":417,"context_line":"            rpc_template.save()"},{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        api_template \u003d DeployTemplate.convert_with_links(rpc_template)"},{"line_number":420,"context_line":"        notify.emit_end_notification(context, rpc_template, \u0027update\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_eea2d13e","line":417,"in_reply_to":"9fdfeff1_b7ae717e","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"4ed8bb1bdc8870c4db7112c7dfebcdeb6e1608ec","unresolved":false,"context_lines":[{"line_number":414,"context_line":""},{"line_number":415,"context_line":"        notify.emit_start_notification(context, rpc_template, \u0027update\u0027)"},{"line_number":416,"context_line":"        with notify.handle_error_notification(context, rpc_template, \u0027update\u0027):"},{"line_number":417,"context_line":"            rpc_template.save()"},{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        api_template \u003d DeployTemplate.convert_with_links(rpc_template)"},{"line_number":420,"context_line":"        notify.emit_end_notification(context, rpc_template, \u0027update\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_b7ae717e","line":417,"in_reply_to":"9fdfeff1_d8956fe5","updated":"2019-02-28 16:03:06.000000000","message":"We discussed a bit on irc. Looks like we have a bit of an issue with \u0027concurrent\u0027 updates, even with the node. I\u0027m good with adding a NOTE or TODO or FIXME thing here.\n\nwe need to document that a rebuild won\u0027t guarantee the same thing if the deploy template that had been used in initial deploy has been changed or deleted in the meantime.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"7141c73275e378e0c1818d570f9d9a80d27c9a65","unresolved":false,"context_lines":[{"line_number":437,"context_line":"            template_ident)"},{"line_number":438,"context_line":"        notify.emit_start_notification(context, rpc_template, \u0027delete\u0027)"},{"line_number":439,"context_line":"        with notify.handle_error_notification(context, rpc_template, \u0027delete\u0027):"},{"line_number":440,"context_line":"            rpc_template.destroy()"},{"line_number":441,"context_line":"        notify.emit_end_notification(context, rpc_template, \u0027delete\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_8089c46f","line":440,"updated":"2019-02-27 18:03:51.000000000","message":"more hmm. What if a template is destroyed while the conductor is using it for a node?\n\nDo we care if a node has already been deployed using this template, and then the template is deleted? (No history to know how the node was deployed. Presumably a node.rebuild won\u0027t need the same deploy steps that were used in the deploy with this template?","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"4ed8bb1bdc8870c4db7112c7dfebcdeb6e1608ec","unresolved":false,"context_lines":[{"line_number":437,"context_line":"            template_ident)"},{"line_number":438,"context_line":"        notify.emit_start_notification(context, rpc_template, \u0027delete\u0027)"},{"line_number":439,"context_line":"        with notify.handle_error_notification(context, rpc_template, \u0027delete\u0027):"},{"line_number":440,"context_line":"            rpc_template.destroy()"},{"line_number":441,"context_line":"        notify.emit_end_notification(context, rpc_template, \u0027delete\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_170add88","line":440,"in_reply_to":"9fdfeff1_785b2353","updated":"2019-02-28 16:03:06.000000000","message":"ok, lets make sure we document this in the admin (or whatever) guide.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"93b8e073d2c407aa1ee0fb768c6c2307a7ea3c14","unresolved":false,"context_lines":[{"line_number":437,"context_line":"            template_ident)"},{"line_number":438,"context_line":"        notify.emit_start_notification(context, rpc_template, \u0027delete\u0027)"},{"line_number":439,"context_line":"        with notify.handle_error_notification(context, rpc_template, \u0027delete\u0027):"},{"line_number":440,"context_line":"            rpc_template.destroy()"},{"line_number":441,"context_line":"        notify.emit_end_notification(context, rpc_template, \u0027delete\u0027)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_785b2353","line":440,"in_reply_to":"9fdfeff1_8089c46f","updated":"2019-02-28 10:34:08.000000000","message":"I see this as being analogous to nova flavors. There is no reference counting there AFAIK - you can delete a flavor in use by an instance, due to the \u0027embedded flavor\u0027 in the instance state.\n\nHopefully I answered most of this above, but essentially I don\u0027t think we should prevent deletion of an in use template.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":42,"context_line":""},{"line_number":43,"context_line":"_DEFAULT_RETURN_FIELDS \u003d (\u0027uuid\u0027, \u0027name\u0027)"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"_DEPLOY_TEMPLATES_CONTROLLER_RESERVED_WORDS \u003d None"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"_DEPLOY_INTERFACE_TYPE \u003d wtypes.Enum("},{"line_number":48,"context_line":"    wtypes.text, *conductor_utils.DEPLOYING_INTERFACE_PRIORITY)"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_c1a1f7f8","line":45,"updated":"2019-02-28 15:00:12.000000000","message":"Not needed any more?","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":42,"context_line":""},{"line_number":43,"context_line":"_DEFAULT_RETURN_FIELDS \u003d (\u0027uuid\u0027, \u0027name\u0027)"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"_DEPLOY_TEMPLATES_CONTROLLER_RESERVED_WORDS \u003d None"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"_DEPLOY_INTERFACE_TYPE \u003d wtypes.Enum("},{"line_number":48,"context_line":"    wtypes.text, *conductor_utils.DEPLOYING_INTERFACE_PRIORITY)"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_ee25f1bf","line":45,"in_reply_to":"9fdfeff1_c1a1f7f8","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":53,"context_line":"        raise exception.NotFound()"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"class DeployTemplateNameType(wtypes.UserType):"},{"line_number":57,"context_line":"    \"\"\"Type representing the name of a deploy template.\"\"\""},{"line_number":58,"context_line":""},{"line_number":59,"context_line":"    basetype \u003d wtypes.text"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_e1a43b09","line":56,"updated":"2019-02-28 15:00:12.000000000","message":"nit: creating a new type for a simple validation seems a bit overkill (and we don\u0027t do it in other places).","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":53,"context_line":"        raise exception.NotFound()"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"class DeployTemplateNameType(wtypes.UserType):"},{"line_number":57,"context_line":"    \"\"\"Type representing the name of a deploy template.\"\"\""},{"line_number":58,"context_line":""},{"line_number":59,"context_line":"    basetype \u003d wtypes.text"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_99502d0c","line":56,"in_reply_to":"9fdfeff1_e1a43b09","updated":"2019-03-01 12:05:33.000000000","message":"I guess you\u0027re right. I\u0027ll move to template.validate().","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":61,"context_line":""},{"line_number":62,"context_line":"    @staticmethod"},{"line_number":63,"context_line":"    def validate(value):"},{"line_number":64,"context_line":"        # Name must be a valid logical name."},{"line_number":65,"context_line":"        if not utils.is_valid_logical_name(value):"},{"line_number":66,"context_line":"            error_msg \u003d (_(\"Deploy template name is invalid. Value: \u0027%s\u0027\")"},{"line_number":67,"context_line":"                         % str(value))"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_81af6fe1","line":64,"updated":"2019-02-28 15:00:12.000000000","message":"I think the validate_trait check covers this, since it\u0027s more strict.","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":61,"context_line":""},{"line_number":62,"context_line":"    @staticmethod"},{"line_number":63,"context_line":"    def validate(value):"},{"line_number":64,"context_line":"        # Name must be a valid logical name."},{"line_number":65,"context_line":"        if not utils.is_valid_logical_name(value):"},{"line_number":66,"context_line":"            error_msg \u003d (_(\"Deploy template name is invalid. Value: \u0027%s\u0027\")"},{"line_number":67,"context_line":"                         % str(value))"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_d9131558","line":64,"in_reply_to":"9fdfeff1_81af6fe1","updated":"2019-03-01 12:05:33.000000000","message":"It does, but the error message is a bit confusing. Perhaps that\u0027s a problem in itself. This does mean that if you give an invalid logical name, it doesn\u0027t tell you exactly how to fix it. I\u0027ll use validate_trait, but add some context to the exception message.","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":64,"context_line":"        # Name must be a valid logical name."},{"line_number":65,"context_line":"        if not utils.is_valid_logical_name(value):"},{"line_number":66,"context_line":"            error_msg \u003d (_(\"Deploy template name is invalid. Value: \u0027%s\u0027\")"},{"line_number":67,"context_line":"                         % str(value))"},{"line_number":68,"context_line":"            raise wsme.exc.ClientSideError("},{"line_number":69,"context_line":"                error_msg, status_code\u003dhttp_client.BAD_REQUEST)"},{"line_number":70,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_a1aab3ce","line":67,"updated":"2019-02-28 15:00:12.000000000","message":"nit: str() is redundant","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":64,"context_line":"        # Name must be a valid logical name."},{"line_number":65,"context_line":"        if not utils.is_valid_logical_name(value):"},{"line_number":66,"context_line":"            error_msg \u003d (_(\"Deploy template name is invalid. Value: \u0027%s\u0027\")"},{"line_number":67,"context_line":"                         % str(value))"},{"line_number":68,"context_line":"            raise wsme.exc.ClientSideError("},{"line_number":69,"context_line":"                error_msg, status_code\u003dhttp_client.BAD_REQUEST)"},{"line_number":70,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_992b4d80","line":67,"in_reply_to":"9fdfeff1_a1aab3ce","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":150,"context_line":"        # Check for duplicate steps. Each interface/step combination can be"},{"line_number":151,"context_line":"        # specified at most once."},{"line_number":152,"context_line":"        counter \u003d collections.Counter([(step.interface, step.step)"},{"line_number":153,"context_line":"                                       for step in value.steps])"},{"line_number":154,"context_line":"        duplicates \u003d {key for key, count in counter.items() if count \u003e 1}"},{"line_number":155,"context_line":"        if duplicates:"},{"line_number":156,"context_line":"            duplicates \u003d {\"interface: %s, step: %s\" % (interface, step)"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_41b50731","line":153,"updated":"2019-02-28 15:00:12.000000000","message":"nit: brackets are redundant: []","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":150,"context_line":"        # Check for duplicate steps. Each interface/step combination can be"},{"line_number":151,"context_line":"        # specified at most once."},{"line_number":152,"context_line":"        counter \u003d collections.Counter([(step.interface, step.step)"},{"line_number":153,"context_line":"                                       for step in value.steps])"},{"line_number":154,"context_line":"        duplicates \u003d {key for key, count in counter.items() if count \u003e 1}"},{"line_number":155,"context_line":"        if duplicates:"},{"line_number":156,"context_line":"            duplicates \u003d {\"interface: %s, step: %s\" % (interface, step)"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_19d8bd7c","line":153,"in_reply_to":"9fdfeff1_41b50731","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":153,"context_line":"                                       for step in value.steps])"},{"line_number":154,"context_line":"        duplicates \u003d {key for key, count in counter.items() if count \u003e 1}"},{"line_number":155,"context_line":"        if duplicates:"},{"line_number":156,"context_line":"            duplicates \u003d {\"interface: %s, step: %s\" % (interface, step)"},{"line_number":157,"context_line":"                          for interface, step in duplicates}"},{"line_number":158,"context_line":"            err \u003d _(\"Duplicate deploy steps. A deploy template cannot have \""},{"line_number":159,"context_line":"                    \"multiple deploy steps with the same interface and step. \""}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_61b04b41","line":156,"updated":"2019-02-28 15:00:12.000000000","message":"nit: this is not i18n-friendly. I don\u0027t have an easy solution though..","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":153,"context_line":"                                       for step in value.steps])"},{"line_number":154,"context_line":"        duplicates \u003d {key for key, count in counter.items() if count \u003e 1}"},{"line_number":155,"context_line":"        if duplicates:"},{"line_number":156,"context_line":"            duplicates \u003d {\"interface: %s, step: %s\" % (interface, step)"},{"line_number":157,"context_line":"                          for interface, step in duplicates}"},{"line_number":158,"context_line":"            err \u003d _(\"Duplicate deploy steps. A deploy template cannot have \""},{"line_number":159,"context_line":"                    \"multiple deploy steps with the same interface and step. \""}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_790549c1","line":156,"in_reply_to":"9fdfeff1_61b04b41","updated":"2019-03-01 12:05:33.000000000","message":"How about:\n\n_(\"interface: %s, step: %s\") % (interface, step)\n\nUltimately this is the format of the step though - to change it you need to know the English word, so this might hurt rather than help.","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a5eb00bf9a033e287d2fabb8c15953ee402bfaa8","unresolved":false,"context_lines":[{"line_number":120,"context_line":""},{"line_number":121,"context_line":"        # The name must also be a valid trait."},{"line_number":122,"context_line":"        api_utils.validate_trait("},{"line_number":123,"context_line":"            value.name, _(\"Deploy template name must be a valid trait\"))"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"        # There must be at least one step."},{"line_number":126,"context_line":"        if not value.steps:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_b37745d1","line":123,"updated":"2019-03-01 20:39:59.000000000","message":"nit s/_(/error_prefix\u003d_(/","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"001f41a439543ed336c9f3da23a9794a540b9530","unresolved":false,"context_lines":[{"line_number":120,"context_line":""},{"line_number":121,"context_line":"        # The name must also be a valid trait."},{"line_number":122,"context_line":"        api_utils.validate_trait("},{"line_number":123,"context_line":"            value.name, _(\"Deploy template name must be a valid trait\"))"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"        # There must be at least one step."},{"line_number":126,"context_line":"        if not value.steps:"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_bb0625cd","line":123,"in_reply_to":"9fdfeff1_b37745d1","updated":"2019-03-04 13:57:28.000000000","message":"Will fix in a follow up.","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a5eb00bf9a033e287d2fabb8c15953ee402bfaa8","unresolved":false,"context_lines":[{"line_number":186,"context_line":"        \"\"\""},{"line_number":187,"context_line":"        if self.steps !\u003d wtypes.Unset:"},{"line_number":188,"context_line":"            for step in self.steps:"},{"line_number":189,"context_line":"                step.sanitize()"},{"line_number":190,"context_line":""},{"line_number":191,"context_line":"        if fields is not None:"},{"line_number":192,"context_line":"            self.unset_fields_except(fields)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_b38985c7","line":189,"updated":"2019-03-01 20:39:59.000000000","message":"I was trying to refresh my memory on how this sanitize stuff works, because I thought it was based on policy but I don\u0027t see any code related to that here. Looks like we have this \u0027show_policy\u0027 [1] that node uses and the rest of the objects always sanitize.\n\n[1] https://docs.openstack.org/ironic/latest/configuration/policy.html","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"001f41a439543ed336c9f3da23a9794a540b9530","unresolved":false,"context_lines":[{"line_number":186,"context_line":"        \"\"\""},{"line_number":187,"context_line":"        if self.steps !\u003d wtypes.Unset:"},{"line_number":188,"context_line":"            for step in self.steps:"},{"line_number":189,"context_line":"                step.sanitize()"},{"line_number":190,"context_line":""},{"line_number":191,"context_line":"        if fields is not None:"},{"line_number":192,"context_line":"            self.unset_fields_except(fields)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_3b1b151d","line":189,"in_reply_to":"9fdfeff1_b38985c7","updated":"2019-03-04 13:57:28.000000000","message":"I looked at the node sanitise code and it seems to use that policy for legacy reasons, presumably someone had a use case for scraping passwords from driver_info.","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"}],"ironic/api/controllers/v1/notification_utils.py":[{"author":{"_account_id":24828,"name":"Kaifeng Wang","email":"kaifeng.w@gmail.com","username":"wangkf"},"change_message_id":"384b19992ffbbd0e3cf2753761a8ecc05beb511e","unresolved":false,"context_lines":[{"line_number":89,"context_line":"            payload_name \u003d payload_method.__name__"},{"line_number":90,"context_line":"        finally:"},{"line_number":91,"context_line":"            # Prepare our exception message just in case"},{"line_number":92,"context_line":"            uuid \u003d obj.uuid if hasattr(obj, \u0027uuid\u0027) else None"},{"line_number":93,"context_line":"            exception_values \u003d {\"resource\": resource,"},{"line_number":94,"context_line":"                                \"uuid\": uuid,"},{"line_number":95,"context_line":"                                \"action\": action,"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_01a88875","line":92,"updated":"2019-02-27 09:43:27.000000000","message":"deploy template has uuid, I wonder why we need to add a protect here?","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"a95fe7dfbb7531ad043fd954713da82d2c2a5875","unresolved":false,"context_lines":[{"line_number":89,"context_line":"            payload_name \u003d payload_method.__name__"},{"line_number":90,"context_line":"        finally:"},{"line_number":91,"context_line":"            # Prepare our exception message just in case"},{"line_number":92,"context_line":"            uuid \u003d obj.uuid if hasattr(obj, \u0027uuid\u0027) else None"},{"line_number":93,"context_line":"            exception_values \u003d {\"resource\": resource,"},{"line_number":94,"context_line":"                                \"uuid\": uuid,"},{"line_number":95,"context_line":"                                \"action\": action,"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_472460c6","line":92,"in_reply_to":"9fdfeff1_01a88875","updated":"2019-02-27 10:54:44.000000000","message":"I\u0027m sure that at one point I had to add this to get unit tests to pass. It seems to work without it now though so I\u0027ll remove.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"}],"ironic/api/controllers/v1/utils.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"33fddd6c8a9509d12aea6a7799981acb1d036ac6","unresolved":false,"context_lines":[{"line_number":94,"context_line":"    return sort_dir"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"def validate_trait(trait, error_prefix\u003d\u0027Invalid trait\u0027):"},{"line_number":98,"context_line":"    error \u003d wsme.exc.ClientSideError("},{"line_number":99,"context_line":"        _(\u0027%(error_prefix)s. A valid trait must be no longer than 255 \u0027"},{"line_number":100,"context_line":"          \u0027characters. Standard traits are defined in the os_traits library. \u0027"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_ffcb594f","line":97,"range":{"start_line":97,"start_character":39,"end_line":97,"end_character":54},"updated":"2019-03-01 13:17:20.000000000","message":"nit: _()","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"6b427b6ae3e50b5a36a32d89a29d1882d178b982","unresolved":false,"context_lines":[{"line_number":94,"context_line":"    return sort_dir"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"def validate_trait(trait, error_prefix\u003d\u0027Invalid trait\u0027):"},{"line_number":98,"context_line":"    error \u003d wsme.exc.ClientSideError("},{"line_number":99,"context_line":"        _(\u0027%(error_prefix)s. A valid trait must be no longer than 255 \u0027"},{"line_number":100,"context_line":"          \u0027characters. Standard traits are defined in the os_traits library. \u0027"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_fe5fb60c","line":97,"range":{"start_line":97,"start_character":39,"end_line":97,"end_character":54},"in_reply_to":"9fdfeff1_11517162","updated":"2019-03-04 14:21:41.000000000","message":"In a follow up?","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"005ba09b2786824377ca30981c9ecd638f8ef55d","unresolved":false,"context_lines":[{"line_number":94,"context_line":"    return sort_dir"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"def validate_trait(trait, error_prefix\u003d\u0027Invalid trait\u0027):"},{"line_number":98,"context_line":"    error \u003d wsme.exc.ClientSideError("},{"line_number":99,"context_line":"        _(\u0027%(error_prefix)s. A valid trait must be no longer than 255 \u0027"},{"line_number":100,"context_line":"          \u0027characters. Standard traits are defined in the os_traits library. \u0027"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_11517162","line":97,"range":{"start_line":97,"start_character":39,"end_line":97,"end_character":54},"in_reply_to":"9fdfeff1_ffcb594f","updated":"2019-03-01 15:35:42.000000000","message":"Done","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"}],"ironic/common/policy.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":440,"context_line":"        \u0027rule:is_admin or rule:is_observer\u0027,"},{"line_number":441,"context_line":"        \u0027Retrieve Deploy Template records\u0027,"},{"line_number":442,"context_line":"        [{\u0027path\u0027: \u0027/deploy_templates\u0027, \u0027method\u0027: \u0027GET\u0027},"},{"line_number":443,"context_line":"         {\u0027path\u0027: \u0027/deploy_templates/detail\u0027, \u0027method\u0027: \u0027GET\u0027},"},{"line_number":444,"context_line":"         {\u0027path\u0027: \u0027/deploy_templates/{deploy_template_ident}\u0027,"},{"line_number":445,"context_line":"          \u0027method\u0027: \u0027GET\u0027}]),"},{"line_number":446,"context_line":"    policy.DocumentedRuleDefault("}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_0185bf59","line":443,"updated":"2019-02-28 15:00:12.000000000","message":"This no longer exists","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":440,"context_line":"        \u0027rule:is_admin or rule:is_observer\u0027,"},{"line_number":441,"context_line":"        \u0027Retrieve Deploy Template records\u0027,"},{"line_number":442,"context_line":"        [{\u0027path\u0027: \u0027/deploy_templates\u0027, \u0027method\u0027: \u0027GET\u0027},"},{"line_number":443,"context_line":"         {\u0027path\u0027: \u0027/deploy_templates/detail\u0027, \u0027method\u0027: \u0027GET\u0027},"},{"line_number":444,"context_line":"         {\u0027path\u0027: \u0027/deploy_templates/{deploy_template_ident}\u0027,"},{"line_number":445,"context_line":"          \u0027method\u0027: \u0027GET\u0027}]),"},{"line_number":446,"context_line":"    policy.DocumentedRuleDefault("}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_8e31c50d","line":443,"in_reply_to":"9fdfeff1_0185bf59","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"}],"ironic/objects/deploy_template.py":[{"author":{"_account_id":24828,"name":"Kaifeng Wang","email":"kaifeng.w@gmail.com","username":"wangkf"},"change_message_id":"384b19992ffbbd0e3cf2753761a8ecc05beb511e","unresolved":false,"context_lines":[{"line_number":258,"context_line":"class DeployTemplateCRUDPayload(notification.NotificationPayloadBase):"},{"line_number":259,"context_line":"    # Version 1.0: Initial version"},{"line_number":260,"context_line":"    # Version 1.1: Added \u0027extra\u0027 field"},{"line_number":261,"context_line":"    VERSION \u003d \u00271.1\u0027"},{"line_number":262,"context_line":""},{"line_number":263,"context_line":"    SCHEMA \u003d {"},{"line_number":264,"context_line":"        \u0027created_at\u0027: (\u0027deploy_template\u0027, \u0027created_at\u0027),"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_c17840f9","line":261,"range":{"start_line":261,"start_character":14,"end_line":261,"end_character":19},"updated":"2019-02-27 09:43:27.000000000","message":"I guess the version is 1.0 because we just exposed it, not sure, but kind of unimportant.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"a95fe7dfbb7531ad043fd954713da82d2c2a5875","unresolved":false,"context_lines":[{"line_number":258,"context_line":"class DeployTemplateCRUDPayload(notification.NotificationPayloadBase):"},{"line_number":259,"context_line":"    # Version 1.0: Initial version"},{"line_number":260,"context_line":"    # Version 1.1: Added \u0027extra\u0027 field"},{"line_number":261,"context_line":"    VERSION \u003d \u00271.1\u0027"},{"line_number":262,"context_line":""},{"line_number":263,"context_line":"    SCHEMA \u003d {"},{"line_number":264,"context_line":"        \u0027created_at\u0027: (\u0027deploy_template\u0027, \u0027created_at\u0027),"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_c7193088","line":261,"range":{"start_line":261,"start_character":14,"end_line":261,"end_character":19},"in_reply_to":"9fdfeff1_c17840f9","updated":"2019-02-27 10:54:44.000000000","message":"Doh, yeah, 1.0 is fine.","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"}],"ironic/tests/unit/api/controllers/v1/test_deploy_template.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":316,"context_line":"        self._test_sort_key_allowed(detail\u003dTrue)"},{"line_number":317,"context_line":""},{"line_number":318,"context_line":""},{"line_number":319,"context_line":"@mock.patch.object(objects.DeployTemplate, \u0027save\u0027)"},{"line_number":320,"context_line":"class TestPatch(BaseDeployTemplatesAPITest):"},{"line_number":321,"context_line":""},{"line_number":322,"context_line":"    def setUp(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_2188036f","line":319,"updated":"2019-02-28 15:00:12.000000000","message":"nit: autospec\u003dTrue","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":316,"context_line":"        self._test_sort_key_allowed(detail\u003dTrue)"},{"line_number":317,"context_line":""},{"line_number":318,"context_line":""},{"line_number":319,"context_line":"@mock.patch.object(objects.DeployTemplate, \u0027save\u0027)"},{"line_number":320,"context_line":"class TestPatch(BaseDeployTemplatesAPITest):"},{"line_number":321,"context_line":""},{"line_number":322,"context_line":"    def setUp(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_d91235fd","line":319,"in_reply_to":"9fdfeff1_2188036f","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":344,"context_line":"        return response"},{"line_number":345,"context_line":""},{"line_number":346,"context_line":"    @mock.patch.object(notification_utils, \u0027_emit_api_notification\u0027)"},{"line_number":347,"context_line":"    def test_update_byid(self, mock_notify, mock_save):"},{"line_number":348,"context_line":"        name \u003d \u0027CUSTOM_DT2\u0027"},{"line_number":349,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/name\u0027, \u0027value\u0027: name, \u0027op\u0027: \u0027add\u0027}]"},{"line_number":350,"context_line":"        response \u003d self._test_update_ok(mock_save, patch)"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_c17a5775","line":347,"updated":"2019-02-28 15:00:12.000000000","message":"nit: by_id","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":344,"context_line":"        return response"},{"line_number":345,"context_line":""},{"line_number":346,"context_line":"    @mock.patch.object(notification_utils, \u0027_emit_api_notification\u0027)"},{"line_number":347,"context_line":"    def test_update_byid(self, mock_notify, mock_save):"},{"line_number":348,"context_line":"        name \u003d \u0027CUSTOM_DT2\u0027"},{"line_number":349,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/name\u0027, \u0027value\u0027: name, \u0027op\u0027: \u0027add\u0027}]"},{"line_number":350,"context_line":"        response \u003d self._test_update_ok(mock_save, patch)"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_d96eb562","line":347,"in_reply_to":"9fdfeff1_c17a5775","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":357,"context_line":"                                      obj_fields.NotificationLevel.INFO,"},{"line_number":358,"context_line":"                                      obj_fields.NotificationStatus.END)])"},{"line_number":359,"context_line":""},{"line_number":360,"context_line":"    def test_update_byname(self, mock_save):"},{"line_number":361,"context_line":"        steps \u003d [{"},{"line_number":362,"context_line":"            \u0027interface\u0027: \u0027bios\u0027,"},{"line_number":363,"context_line":"            \u0027step\u0027: \u0027apply_configuration\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_e17d1b6d","line":360,"updated":"2019-02-28 15:00:12.000000000","message":"What does byname imply here? I assume you would test PATCH deploy_templates/NAME, but _test_update_ok always uses uuid..","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":357,"context_line":"                                      obj_fields.NotificationLevel.INFO,"},{"line_number":358,"context_line":"                                      obj_fields.NotificationStatus.END)])"},{"line_number":359,"context_line":""},{"line_number":360,"context_line":"    def test_update_byname(self, mock_save):"},{"line_number":361,"context_line":"        steps \u003d [{"},{"line_number":362,"context_line":"            \u0027interface\u0027: \u0027bios\u0027,"},{"line_number":363,"context_line":"            \u0027step\u0027: \u0027apply_configuration\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_d9a3159a","line":360,"in_reply_to":"9fdfeff1_e17d1b6d","updated":"2019-03-01 12:05:33.000000000","message":"Done","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":499,"context_line":"        }"},{"line_number":500,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps/1\u0027, \u0027op\u0027: \u0027replace\u0027, \u0027value\u0027: step}]"},{"line_number":501,"context_line":"        self._test_update_bad_request("},{"line_number":502,"context_line":"            mock_save, patch, \"list assignment index out of range\")"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    def test_replace_empty_step_list_fail(self, mock_save):"},{"line_number":505,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps\u0027, \u0027op\u0027: \u0027replace\u0027, \u0027value\u0027: []}]"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_8198cfbf","line":502,"updated":"2019-02-28 15:00:12.000000000","message":"This doesn\u0027t look a great error message. Maybe catch it and turn into something meaningful?","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"33fddd6c8a9509d12aea6a7799981acb1d036ac6","unresolved":false,"context_lines":[{"line_number":499,"context_line":"        }"},{"line_number":500,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps/1\u0027, \u0027op\u0027: \u0027replace\u0027, \u0027value\u0027: step}]"},{"line_number":501,"context_line":"        self._test_update_bad_request("},{"line_number":502,"context_line":"            mock_save, patch, \"list assignment index out of range\")"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    def test_replace_empty_step_list_fail(self, mock_save):"},{"line_number":505,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps\u0027, \u0027op\u0027: \u0027replace\u0027, \u0027value\u0027: []}]"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_7f068988","line":502,"in_reply_to":"9fdfeff1_59e9657c","updated":"2019-03-01 13:17:20.000000000","message":"Hmm. We can try experimenting with it in a follow-up. But I guess it will be hard to guess what exactly went wrong here (as opposed to most other places).","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"005ba09b2786824377ca30981c9ecd638f8ef55d","unresolved":false,"context_lines":[{"line_number":499,"context_line":"        }"},{"line_number":500,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps/1\u0027, \u0027op\u0027: \u0027replace\u0027, \u0027value\u0027: step}]"},{"line_number":501,"context_line":"        self._test_update_bad_request("},{"line_number":502,"context_line":"            mock_save, patch, \"list assignment index out of range\")"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    def test_replace_empty_step_list_fail(self, mock_save):"},{"line_number":505,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps\u0027, \u0027op\u0027: \u0027replace\u0027, \u0027value\u0027: []}]"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_e4ae6de5","line":502,"in_reply_to":"9fdfeff1_7f068988","updated":"2019-03-01 15:35:42.000000000","message":"I\u0027ll see what I can come up with.","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":499,"context_line":"        }"},{"line_number":500,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps/1\u0027, \u0027op\u0027: \u0027replace\u0027, \u0027value\u0027: step}]"},{"line_number":501,"context_line":"        self._test_update_bad_request("},{"line_number":502,"context_line":"            mock_save, patch, \"list assignment index out of range\")"},{"line_number":503,"context_line":""},{"line_number":504,"context_line":"    def test_replace_empty_step_list_fail(self, mock_save):"},{"line_number":505,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps\u0027, \u0027op\u0027: \u0027replace\u0027, \u0027value\u0027: []}]"}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_59e9657c","line":502,"in_reply_to":"9fdfeff1_8198cfbf","updated":"2019-03-01 12:05:33.000000000","message":"This comes from the innards of jsonpatch:\n\n\u003e\u003e\u003e jsonpatch.apply_patch([], [{\"op\": \"add\", \"value\": 1, \"path\": \"/0\"}])\n[1]\n\u003e\u003e\u003e jsonpatch.apply_patch([], [{\"op\": \"replace\", \"value\": 1, \"path\": \"/0\"}])\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\n  File \"/usr/lib/python2.7/dist-packages/jsonpatch.py\", line 151, in apply_patch\n    return patch.apply(doc, in_place)\n  File \"/usr/lib/python2.7/dist-packages/jsonpatch.py\", line 349, in apply\n    obj \u003d operation.apply(obj)\n  File \"/usr/lib/python2.7/dist-packages/jsonpatch.py\", line 467, in apply\n    subobj[part] \u003d value\nIndexError: list assignment index out of range\n\nWe catch the IndexError, but include the message in the PatchError that gets raised. I\u0027m not sure that reading too much into IndexError is a good idea. What we could do more generally is apply each operation in turn, so that you know which failed, and can include it in the error:\n\n            for patch_op in patch:\n                template \u003d DeployTemplate(\n                   **api_utils.apply_jsonpatch(template_dict, [patch_op]))\n\nWDYT? Is that something we should do more widely?","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f995ff2213d08d760822fefb174ef1acf33c1b5a","unresolved":false,"context_lines":[{"line_number":626,"context_line":"        }"},{"line_number":627,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps/2\u0027, \u0027op\u0027: \u0027add\u0027, \u0027value\u0027: step}]"},{"line_number":628,"context_line":"        self._test_update_bad_request("},{"line_number":629,"context_line":"            mock_save, patch, \"can\u0027t insert outside of list\")"},{"line_number":630,"context_line":""},{"line_number":631,"context_line":"    def test_add_multi(self, mock_save):"},{"line_number":632,"context_line":"        steps \u003d ["}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_a19393a2","line":629,"updated":"2019-02-28 15:00:12.000000000","message":"ditto?\n\nalso this means we cannot append to the list, right? maybe actually detect an attempt to add the Nth element and turn it into append? or is it too hard?","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"33fddd6c8a9509d12aea6a7799981acb1d036ac6","unresolved":false,"context_lines":[{"line_number":626,"context_line":"        }"},{"line_number":627,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps/2\u0027, \u0027op\u0027: \u0027add\u0027, \u0027value\u0027: step}]"},{"line_number":628,"context_line":"        self._test_update_bad_request("},{"line_number":629,"context_line":"            mock_save, patch, \"can\u0027t insert outside of list\")"},{"line_number":630,"context_line":""},{"line_number":631,"context_line":"    def test_add_multi(self, mock_save):"},{"line_number":632,"context_line":"        steps \u003d ["}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_9f09ed95","line":629,"in_reply_to":"9fdfeff1_99982d1b","updated":"2019-03-01 13:17:20.000000000","message":"Got it","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"e433bdddb6157c4dcfc92cd0fb31a854c5164ccd","unresolved":false,"context_lines":[{"line_number":626,"context_line":"        }"},{"line_number":627,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/steps/2\u0027, \u0027op\u0027: \u0027add\u0027, \u0027value\u0027: step}]"},{"line_number":628,"context_line":"        self._test_update_bad_request("},{"line_number":629,"context_line":"            mock_save, patch, \"can\u0027t insert outside of list\")"},{"line_number":630,"context_line":""},{"line_number":631,"context_line":"    def test_add_multi(self, mock_save):"},{"line_number":632,"context_line":"        steps \u003d ["}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_99982d1b","line":629,"in_reply_to":"9fdfeff1_a19393a2","updated":"2019-03-01 12:05:33.000000000","message":"You can append (see test_add_multi), but you can only add to the Nth item, not the N+1th.","commit_id":"45bf5d31d6dc975933c98ae26d9aeb3c21ca195d"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a5eb00bf9a033e287d2fabb8c15953ee402bfaa8","unresolved":false,"context_lines":[{"line_number":177,"context_line":"        obj_utils.create_test_deploy_template(self.context)"},{"line_number":178,"context_line":"        data1 \u003d self.get_json("},{"line_number":179,"context_line":"            \u0027/deploy_templates\u0027,"},{"line_number":180,"context_line":"            headers\u003d{api_base.Version.string: str(api_v1.max_version())})"},{"line_number":181,"context_line":"        data2 \u003d self.get_json("},{"line_number":182,"context_line":"            \u0027/deploy_templates?detail\u003dFalse\u0027,"},{"line_number":183,"context_line":"            headers\u003d{api_base.Version.string: str(api_v1.max_version())})"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_cfcc9d64","line":180,"updated":"2019-03-01 20:39:59.000000000","message":"headers\u003dself.headers?","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"001f41a439543ed336c9f3da23a9794a540b9530","unresolved":false,"context_lines":[{"line_number":177,"context_line":"        obj_utils.create_test_deploy_template(self.context)"},{"line_number":178,"context_line":"        data1 \u003d self.get_json("},{"line_number":179,"context_line":"            \u0027/deploy_templates\u0027,"},{"line_number":180,"context_line":"            headers\u003d{api_base.Version.string: str(api_v1.max_version())})"},{"line_number":181,"context_line":"        data2 \u003d self.get_json("},{"line_number":182,"context_line":"            \u0027/deploy_templates?detail\u003dFalse\u0027,"},{"line_number":183,"context_line":"            headers\u003d{api_base.Version.string: str(api_v1.max_version())})"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_bbbdc5d8","line":180,"in_reply_to":"9fdfeff1_cfcc9d64","updated":"2019-03-04 13:57:28.000000000","message":"Done in a follow up.","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a5eb00bf9a033e287d2fabb8c15953ee402bfaa8","unresolved":false,"context_lines":[{"line_number":180,"context_line":"            headers\u003d{api_base.Version.string: str(api_v1.max_version())})"},{"line_number":181,"context_line":"        data2 \u003d self.get_json("},{"line_number":182,"context_line":"            \u0027/deploy_templates?detail\u003dFalse\u0027,"},{"line_number":183,"context_line":"            headers\u003d{api_base.Version.string: str(api_v1.max_version())})"},{"line_number":184,"context_line":"        self.assertEqual(data1[\u0027deploy_templates\u0027], data2[\u0027deploy_templates\u0027])"},{"line_number":185,"context_line":""},{"line_number":186,"context_line":"    def test_detail_using_query_false_and_fields(self):"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_efc96151","line":183,"updated":"2019-03-01 20:39:59.000000000","message":"ditto\n\nand i see other occurrences of this.","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"001f41a439543ed336c9f3da23a9794a540b9530","unresolved":false,"context_lines":[{"line_number":180,"context_line":"            headers\u003d{api_base.Version.string: str(api_v1.max_version())})"},{"line_number":181,"context_line":"        data2 \u003d self.get_json("},{"line_number":182,"context_line":"            \u0027/deploy_templates?detail\u003dFalse\u0027,"},{"line_number":183,"context_line":"            headers\u003d{api_base.Version.string: str(api_v1.max_version())})"},{"line_number":184,"context_line":"        self.assertEqual(data1[\u0027deploy_templates\u0027], data2[\u0027deploy_templates\u0027])"},{"line_number":185,"context_line":""},{"line_number":186,"context_line":"    def test_detail_using_query_false_and_fields(self):"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_5ba7f9bd","line":183,"in_reply_to":"9fdfeff1_efc96151","updated":"2019-03-04 13:57:28.000000000","message":"Done","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a5eb00bf9a033e287d2fabb8c15953ee402bfaa8","unresolved":false,"context_lines":[{"line_number":431,"context_line":"        self.assertTrue(response.json[\u0027error_message\u0027])"},{"line_number":432,"context_line":"        self.assertFalse(mock_save.called)"},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"    def test_replace_singular(self, mock_save):"},{"line_number":435,"context_line":"        name \u003d \u0027CUSTOM_DT2\u0027"},{"line_number":436,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/name\u0027, \u0027value\u0027: name, \u0027op\u0027: \u0027replace\u0027}]"},{"line_number":437,"context_line":"        response \u003d self._test_update_ok(mock_save, patch)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_4f48ad89","line":434,"updated":"2019-03-01 20:39:59.000000000","message":"This is basically similar to L387; just using a custom name instead of standard trait?","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"001f41a439543ed336c9f3da23a9794a540b9530","unresolved":false,"context_lines":[{"line_number":431,"context_line":"        self.assertTrue(response.json[\u0027error_message\u0027])"},{"line_number":432,"context_line":"        self.assertFalse(mock_save.called)"},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"    def test_replace_singular(self, mock_save):"},{"line_number":435,"context_line":"        name \u003d \u0027CUSTOM_DT2\u0027"},{"line_number":436,"context_line":"        patch \u003d [{\u0027path\u0027: \u0027/name\u0027, \u0027value\u0027: name, \u0027op\u0027: \u0027replace\u0027}]"},{"line_number":437,"context_line":"        response \u003d self._test_update_ok(mock_save, patch)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_7b851d07","line":434,"in_reply_to":"9fdfeff1_4f48ad89","updated":"2019-03-04 13:57:28.000000000","message":"Yes you\u0027re right. I\u0027ve moved it next to that one in the follow up.","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a5eb00bf9a033e287d2fabb8c15953ee402bfaa8","unresolved":false,"context_lines":[{"line_number":572,"context_line":"        patch \u003d []"},{"line_number":573,"context_line":"        for i, step in enumerate(steps):"},{"line_number":574,"context_line":"            patch.append({\u0027path\u0027: \u0027/steps/%s\u0027 % i,"},{"line_number":575,"context_line":"                          \u0027value\u0027: steps[i],"},{"line_number":576,"context_line":"                          \u0027op\u0027: \u0027replace\u0027})"},{"line_number":577,"context_line":"        response \u003d self.patch_json(\u0027/deploy_templates/%s\u0027 % template.uuid,"},{"line_number":578,"context_line":"                                   patch, headers\u003dself.headers)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_32582e30","line":575,"updated":"2019-03-01 20:39:59.000000000","message":"nit s/steps[i]/step/","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"001f41a439543ed336c9f3da23a9794a540b9530","unresolved":false,"context_lines":[{"line_number":572,"context_line":"        patch \u003d []"},{"line_number":573,"context_line":"        for i, step in enumerate(steps):"},{"line_number":574,"context_line":"            patch.append({\u0027path\u0027: \u0027/steps/%s\u0027 % i,"},{"line_number":575,"context_line":"                          \u0027value\u0027: steps[i],"},{"line_number":576,"context_line":"                          \u0027op\u0027: \u0027replace\u0027})"},{"line_number":577,"context_line":"        response \u003d self.patch_json(\u0027/deploy_templates/%s\u0027 % template.uuid,"},{"line_number":578,"context_line":"                                   patch, headers\u003dself.headers)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9fdfeff1_7be8bdb2","line":575,"in_reply_to":"9fdfeff1_32582e30","updated":"2019-03-04 13:57:28.000000000","message":"Done, follow up.","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"}],"ironic/tests/unit/api/utils.py":[{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"7141c73275e378e0c1818d570f9d9a80d27c9a65","unresolved":false,"context_lines":[{"line_number":221,"context_line":""},{"line_number":222,"context_line":""},{"line_number":223,"context_line":"def post_get_test_deploy_template(**kw):"},{"line_number":224,"context_line":"    \"\"\"Return a Portgroup object with appropriate attributes.\"\"\""},{"line_number":225,"context_line":"    return deploy_template_post_data(**kw)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_5b1d1060","line":224,"updated":"2019-02-27 18:03:51.000000000","message":"s/Portgroup/DeployTemplate/","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"93b8e073d2c407aa1ee0fb768c6c2307a7ea3c14","unresolved":false,"context_lines":[{"line_number":221,"context_line":""},{"line_number":222,"context_line":""},{"line_number":223,"context_line":"def post_get_test_deploy_template(**kw):"},{"line_number":224,"context_line":"    \"\"\"Return a Portgroup object with appropriate attributes.\"\"\""},{"line_number":225,"context_line":"    return deploy_template_post_data(**kw)"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_830e9c2f","line":224,"in_reply_to":"9fdfeff1_5b1d1060","updated":"2019-02-28 10:34:08.000000000","message":"Caught!","commit_id":"61c504ed19a16cb696af298a454f59266512e13e"}],"releasenotes/notes/deploy-templates-5df3368df862631c.yaml":[{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a5eb00bf9a033e287d2fabb8c15953ee402bfaa8","unresolved":false,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Adds the `deploy templates"},{"line_number":5,"context_line":"    \u003chttps://specs.openstack.org/openstack/ironic-specs/specs/approved/deploy-templates.html\u003e`__"},{"line_number":6,"context_line":"    API. Deploy templates can be used to customise the node deployment process,"},{"line_number":7,"context_line":"    each specifying a list of deploy steps to execute with configurable"},{"line_number":8,"context_line":"    priority and arguments."}],"source_content_type":"text/x-yaml","patch_set":8,"id":"9fdfeff1_92febaad","line":5,"updated":"2019-03-01 20:39:59.000000000","message":"ugh, i think we said we weren\u0027t going to use specs as documentation. We should remember to update this with the admin? doc that needs to be written to explain this stuff. (Maybe enhance this or add a new page: https://docs.openstack.org/ironic/latest/admin/deploy-steps.html)","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"001f41a439543ed336c9f3da23a9794a540b9530","unresolved":false,"context_lines":[{"line_number":2,"context_line":"features:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Adds the `deploy templates"},{"line_number":5,"context_line":"    \u003chttps://specs.openstack.org/openstack/ironic-specs/specs/approved/deploy-templates.html\u003e`__"},{"line_number":6,"context_line":"    API. Deploy templates can be used to customise the node deployment process,"},{"line_number":7,"context_line":"    each specifying a list of deploy steps to execute with configurable"},{"line_number":8,"context_line":"    priority and arguments."}],"source_content_type":"text/x-yaml","patch_set":8,"id":"9fdfeff1_bb070582","line":5,"in_reply_to":"9fdfeff1_92febaad","updated":"2019-03-04 13:57:28.000000000","message":"Yeah, you\u0027re right. I\u0027ll remove the link and we can update the note when the docs land.","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"33fddd6c8a9509d12aea6a7799981acb1d036ac6","unresolved":false,"context_lines":[{"line_number":7,"context_line":"    each specifying a list of deploy steps to execute with configurable"},{"line_number":8,"context_line":"    priority and arguments."},{"line_number":9,"context_line":""},{"line_number":10,"context_line":"    Introduces the following new API endpoints, available from Bare Metal REST"},{"line_number":11,"context_line":"    API version 1.55:"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"    * ``GET /v1/deploy_templates``"}],"source_content_type":"text/x-yaml","patch_set":8,"id":"9fdfeff1_bfef11af","line":10,"range":{"start_line":10,"start_character":73,"end_line":10,"end_character":78},"updated":"2019-03-01 13:17:20.000000000","message":"nit: s/REST// (unnecessary detail).","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"005ba09b2786824377ca30981c9ecd638f8ef55d","unresolved":false,"context_lines":[{"line_number":7,"context_line":"    each specifying a list of deploy steps to execute with configurable"},{"line_number":8,"context_line":"    priority and arguments."},{"line_number":9,"context_line":""},{"line_number":10,"context_line":"    Introduces the following new API endpoints, available from Bare Metal REST"},{"line_number":11,"context_line":"    API version 1.55:"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"    * ``GET /v1/deploy_templates``"}],"source_content_type":"text/x-yaml","patch_set":8,"id":"9fdfeff1_c45a491c","line":10,"range":{"start_line":10,"start_character":73,"end_line":10,"end_character":78},"in_reply_to":"9fdfeff1_bfef11af","updated":"2019-03-01 15:35:42.000000000","message":"Done","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"6b427b6ae3e50b5a36a32d89a29d1882d178b982","unresolved":false,"context_lines":[{"line_number":7,"context_line":"    each specifying a list of deploy steps to execute with configurable"},{"line_number":8,"context_line":"    priority and arguments."},{"line_number":9,"context_line":""},{"line_number":10,"context_line":"    Introduces the following new API endpoints, available from Bare Metal REST"},{"line_number":11,"context_line":"    API version 1.55:"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"    * ``GET /v1/deploy_templates``"}],"source_content_type":"text/x-yaml","patch_set":8,"id":"9fdfeff1_9e7f8a65","line":10,"range":{"start_line":10,"start_character":73,"end_line":10,"end_character":78},"in_reply_to":"9fdfeff1_c45a491c","updated":"2019-03-04 14:21:41.000000000","message":"In a follow up?","commit_id":"c532cec2f92075451b8d8ea858210b77f5342dfd"}]}
