)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7900,"name":"Tomasz Paszkowski","email":"ss7pro@gmail.com","username":"tpaszkowski"},"change_message_id":"76c48b4cb9f1f93891dd1d0c538003cf490583a5","unresolved":false,"context_lines":[{"line_number":22,"context_line":""},{"line_number":23,"context_line":"New config option `CONF.api.restrict_ipxe` which is similar to"},{"line_number":24,"context_line":"`CONF.api.restrict_lookup` but also allows nodes in ACTIVE state if"},{"line_number":25,"context_line":"node is using \u0027netboot\u0027."},{"line_number":26,"context_line":"Note that currently switching pxe config is not implemented yet"},{"line_number":27,"context_line":"(thus netboot is currently actually not supported)."},{"line_number":28,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":10,"id":"ba5da102_c9cd1d88","line":25,"updated":"2016-11-05 14:02:32.000000000","message":"We should have an option for nodes in ACTIVE state which are attempting to netboot over ipxe to tell them to boot from local drive.","commit_id":"5ca9fcc168155de1333dd4977c20f4752107aa4a"}],"ironic/api/controllers/v1/ramdisk.py":[{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"00983bc7a0b7304e980ab0b38a03afc4b1470cbf","unresolved":false,"context_lines":[{"line_number":177,"context_line":"class IpxeConfigController(rest.RestController):"},{"line_number":178,"context_line":"    \"\"\"Controller handling iPXE config requests from nodes.\"\"\""},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"    @expose.expose(FileResult, types.macaddress, types.uuid)"},{"line_number":181,"context_line":"    def get_all(self, mac\u003dNone, node_uuid\u003dNone):"},{"line_number":182,"context_line":"        \"\"\"Process iPXE boot script request from the node."},{"line_number":183,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"5a8bc5a2_530143ae","line":180,"range":{"start_line":180,"start_character":49,"end_line":180,"end_character":59},"updated":"2016-09-26 14:39:32.000000000","message":"or name","commit_id":"ce0a3e6af892090dea8a30fa5d5aa5496bbc1dd5"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"1d0292495fef159d761eba4d52ea91a8b147d225","unresolved":false,"context_lines":[{"line_number":177,"context_line":"class IpxeConfigController(rest.RestController):"},{"line_number":178,"context_line":"    \"\"\"Controller handling iPXE config requests from nodes.\"\"\""},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"    @expose.expose(FileResult, types.macaddress, types.uuid)"},{"line_number":181,"context_line":"    def get_all(self, mac\u003dNone, node_uuid\u003dNone):"},{"line_number":182,"context_line":"        \"\"\"Process iPXE boot script request from the node."},{"line_number":183,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"5a8bc5a2_b9ab3d74","line":180,"range":{"start_line":180,"start_character":49,"end_line":180,"end_character":59},"in_reply_to":"5a8bc5a2_530143ae","updated":"2016-09-26 17:04:37.000000000","message":"name is not really relevant here. when using this form, Ironic conductor controls what get put into the pxe opts for dhcp. since name is not exactly unique (or it is in Ironic? not sure), we can safely use only uuid here.","commit_id":"ce0a3e6af892090dea8a30fa5d5aa5496bbc1dd5"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"00983bc7a0b7304e980ab0b38a03afc4b1470cbf","unresolved":false,"context_lines":[{"line_number":186,"context_line":"                    iPXE boot script, used when node ID is not known yet"},{"line_number":187,"context_line":"        \"\"\""},{"line_number":188,"context_line":"        if not (CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_server_enabled):"},{"line_number":189,"context_line":"            raise exception.NotFound()"},{"line_number":190,"context_line":"        cdict \u003d pecan.request.context.to_dict()"},{"line_number":191,"context_line":"        policy.authorize(\u0027baremetal:ipxe\u0027, cdict, cdict)"},{"line_number":192,"context_line":"        if not mac and not node_uuid:"}],"source_content_type":"text/x-python","patch_set":4,"id":"5a8bc5a2_b37fe7de","line":189,"range":{"start_line":189,"start_character":28,"end_line":189,"end_character":36},"updated":"2016-09-26 14:39:32.000000000","message":"Hm, looking at the status codes descriptions, I\u0027d prefer it to be forbidden, with a description what\u0027s wrong, it is not some private info, is it?","commit_id":"ce0a3e6af892090dea8a30fa5d5aa5496bbc1dd5"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"1d0292495fef159d761eba4d52ea91a8b147d225","unresolved":false,"context_lines":[{"line_number":186,"context_line":"                    iPXE boot script, used when node ID is not known yet"},{"line_number":187,"context_line":"        \"\"\""},{"line_number":188,"context_line":"        if not (CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_server_enabled):"},{"line_number":189,"context_line":"            raise exception.NotFound()"},{"line_number":190,"context_line":"        cdict \u003d pecan.request.context.to_dict()"},{"line_number":191,"context_line":"        policy.authorize(\u0027baremetal:ipxe\u0027, cdict, cdict)"},{"line_number":192,"context_line":"        if not mac and not node_uuid:"}],"source_content_type":"text/x-python","patch_set":4,"id":"5a8bc5a2_b94c1dc9","line":189,"range":{"start_line":189,"start_character":28,"end_line":189,"end_character":36},"in_reply_to":"5a8bc5a2_b37fe7de","updated":"2016-09-26 17:04:37.000000000","message":"We basically \"expose\" this API endpoint by config option set (instead of API microversion). AFAIK if one generally tries to access a non-existing API endpoint, one should receive NotFound.","commit_id":"ce0a3e6af892090dea8a30fa5d5aa5496bbc1dd5"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"00983bc7a0b7304e980ab0b38a03afc4b1470cbf","unresolved":false,"context_lines":[{"line_number":205,"context_line":"            # at all and nodes in a wrong state by different error messages."},{"line_number":206,"context_line":"            raise exception.NotFound()"},{"line_number":207,"context_line":""},{"line_number":208,"context_line":"        if (CONF.api.restrict_lookup and"},{"line_number":209,"context_line":"                node.provision_state not in _LOOKUP_ALLOWED_STATES):"},{"line_number":210,"context_line":"            raise exception.NotFound()"},{"line_number":211,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"5a8bc5a2_7f67deb6","line":208,"range":{"start_line":208,"start_character":21,"end_line":208,"end_character":36},"updated":"2016-09-26 14:39:32.000000000","message":"Why do we have to rely on this option?","commit_id":"ce0a3e6af892090dea8a30fa5d5aa5496bbc1dd5"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"1d0292495fef159d761eba4d52ea91a8b147d225","unresolved":false,"context_lines":[{"line_number":205,"context_line":"            # at all and nodes in a wrong state by different error messages."},{"line_number":206,"context_line":"            raise exception.NotFound()"},{"line_number":207,"context_line":""},{"line_number":208,"context_line":"        if (CONF.api.restrict_lookup and"},{"line_number":209,"context_line":"                node.provision_state not in _LOOKUP_ALLOWED_STATES):"},{"line_number":210,"context_line":"            raise exception.NotFound()"},{"line_number":211,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"5a8bc5a2_5412000a","line":208,"range":{"start_line":208,"start_character":21,"end_line":208,"end_character":36},"in_reply_to":"5a8bc5a2_7f67deb6","updated":"2016-09-26 17:04:37.000000000","message":"This is a topic we need to discuss, namely security of such endpoint.\n\nAs with lookup, this is unrestricted public endpoint (more over, even w/o microversioning). If not covered by firewall etc anybody with access to public Ironic API endpoint can acces it when enebled.\n\nThe real question is what \"secret\" data an attacker can generally get from iPXE boot script and boot config? One thing for sure is the tempurls of deployment ramdisk and kernel when booting from tempurls is enabled. This would allow an attacker to download the actual deploy image. In upstream currently this does not have any secrets, but who knows what operators might keep there (e.g. a hard-coded password for a BIOS needed by some custom HardwareManager in IPA?..).\n\nSo in order to minimize possible attack surface, we\u0027d better to allow accessing this information only for certain node states. Re-using \u0027restrict_lookup\u0027 was an immediate idea, but per your comment below, we might need another option, with different set of allowed states","commit_id":"ce0a3e6af892090dea8a30fa5d5aa5496bbc1dd5"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"00983bc7a0b7304e980ab0b38a03afc4b1470cbf","unresolved":false,"context_lines":[{"line_number":206,"context_line":"            raise exception.NotFound()"},{"line_number":207,"context_line":""},{"line_number":208,"context_line":"        if (CONF.api.restrict_lookup and"},{"line_number":209,"context_line":"                node.provision_state not in _LOOKUP_ALLOWED_STATES):"},{"line_number":210,"context_line":"            raise exception.NotFound()"},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"        LOG.debug(\u0027Building iPXE boot script for node %s\u0027 % node.uuid)"}],"source_content_type":"text/x-python","patch_set":4,"id":"5a8bc5a2_c4666750","line":209,"range":{"start_line":209,"start_character":44,"end_line":209,"end_character":66},"updated":"2016-09-26 14:39:32.000000000","message":"Don\u0027t we want to allow ACTIVE for netboot case?","commit_id":"ce0a3e6af892090dea8a30fa5d5aa5496bbc1dd5"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"1d0292495fef159d761eba4d52ea91a8b147d225","unresolved":false,"context_lines":[{"line_number":206,"context_line":"            raise exception.NotFound()"},{"line_number":207,"context_line":""},{"line_number":208,"context_line":"        if (CONF.api.restrict_lookup and"},{"line_number":209,"context_line":"                node.provision_state not in _LOOKUP_ALLOWED_STATES):"},{"line_number":210,"context_line":"            raise exception.NotFound()"},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"        LOG.debug(\u0027Building iPXE boot script for node %s\u0027 % node.uuid)"}],"source_content_type":"text/x-python","patch_set":4,"id":"5a8bc5a2_59d4f9bb","line":209,"range":{"start_line":209,"start_character":44,"end_line":209,"end_character":66},"in_reply_to":"5a8bc5a2_c4666750","updated":"2016-09-26 17:04:37.000000000","message":"goog point. This will warrant another option similar to restrict_lookup but with different set of fields.","commit_id":"ce0a3e6af892090dea8a30fa5d5aa5496bbc1dd5"},{"author":{"_account_id":7900,"name":"Tomasz Paszkowski","email":"ss7pro@gmail.com","username":"tpaszkowski"},"change_message_id":"5fc60fc6167313dadf6377743aaa0ac920d412ff","unresolved":false,"context_lines":[{"line_number":65,"context_line":"        allowed \u003d _IPXE_ALLOWED_STATES_NETBOOT"},{"line_number":66,"context_line":"    else:"},{"line_number":67,"context_line":"        allowed \u003d _IPXE_ALLOWED_STATES"},{"line_number":68,"context_line":"    return (CONF.api.restrict_ipxe and node.provision_state not in allowed)"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"def config():"}],"source_content_type":"text/x-python","patch_set":10,"id":"ba5da102_29c5b95a","line":68,"updated":"2016-11-05 14:05:17.000000000","message":"I think that default should be to tell the node to boot from local storage.","commit_id":"5ca9fcc168155de1333dd4977c20f4752107aa4a"},{"author":{"_account_id":7900,"name":"Tomasz Paszkowski","email":"ss7pro@gmail.com","username":"tpaszkowski"},"change_message_id":"b81d0bdc35d1b1c851f7b7dc31fa374fd2401478","unresolved":false,"context_lines":[{"line_number":65,"context_line":"        allowed \u003d _IPXE_ALLOWED_STATES_NETBOOT"},{"line_number":66,"context_line":"    else:"},{"line_number":67,"context_line":"        allowed \u003d _IPXE_ALLOWED_STATES"},{"line_number":68,"context_line":"    return (CONF.api.restrict_ipxe and node.provision_state not in allowed)"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"def config():"}],"source_content_type":"text/x-python","patch_set":10,"id":"ba5da102_c9943d46","line":68,"in_reply_to":"ba5da102_29c5b95a","updated":"2016-11-05 14:06:17.000000000","message":"Best would be to have a config option to enable that behavior :)","commit_id":"5ca9fcc168155de1333dd4977c20f4752107aa4a"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"bd5a83854c030dce12b58001b86c71b3fabb1692","unresolved":false,"context_lines":[{"line_number":65,"context_line":"        allowed \u003d _IPXE_ALLOWED_STATES_NETBOOT"},{"line_number":66,"context_line":"    else:"},{"line_number":67,"context_line":"        allowed \u003d _IPXE_ALLOWED_STATES"},{"line_number":68,"context_line":"    return (CONF.api.restrict_ipxe and node.provision_state not in allowed)"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"def config():"}],"source_content_type":"text/x-python","patch_set":10,"id":"9a629dbe_563705e3","line":68,"in_reply_to":"ba5da102_c9943d46","updated":"2016-11-07 12:15:21.000000000","message":"Not sure I understand why we need this. ACTIVE nodes booting from (i)PXE will only be set when the node is configured/requires to netboot to user image (see the PXEBoot.prepare_instance). Nodes that actually can do localboot will be set to boot from disk right away.","commit_id":"5ca9fcc168155de1333dd4977c20f4752107aa4a"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"8fc8612c2c62355ed9b6406c30a1702a8b5213d7","unresolved":false,"context_lines":[{"line_number":270,"context_line":"                # content \u003d ipxe.DENIED_BOOT_CONFIG"},{"line_number":271,"context_line":""},{"line_number":272,"context_line":"            LOG.debug(\u0027Requesting iPXE boot config params \u0027"},{"line_number":273,"context_line":"                      \u0027for node %s\u0027 % node.uuid)"},{"line_number":274,"context_line":"            rpc_node \u003d api_utils.get_rpc_node(node.uuid)"},{"line_number":275,"context_line":"            try:"},{"line_number":276,"context_line":"                topic \u003d pecan.request.rpcapi.get_topic_for(rpc_node)"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a77a97e_e5c0ee7e","line":273,"range":{"start_line":273,"start_character":36,"end_line":273,"end_character":37},"updated":"2016-11-16 20:26:52.000000000","message":"pep8 not happy","commit_id":"1d6b8ed67ec7c2c76f229a9f135eac69f020b436"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"8fc8612c2c62355ed9b6406c30a1702a8b5213d7","unresolved":false,"context_lines":[{"line_number":280,"context_line":""},{"line_number":281,"context_line":"            content \u003d pecan.request.rpcapi.get_ipxe_config("},{"line_number":282,"context_line":"                pecan.request.context, rpc_node.uuid, topic\u003dtopic)"},{"line_number":283,"context_line":"            LOG.debug(\u0027Serving iPXE boot config to node %s\u0027 % node.uuid)"},{"line_number":284,"context_line":""},{"line_number":285,"context_line":"        return FileResult(content)"}],"source_content_type":"text/x-python","patch_set":15,"id":"7a77a97e_4538c2a0","line":283,"range":{"start_line":283,"start_character":60,"end_line":283,"end_character":61},"updated":"2016-11-16 20:26:52.000000000","message":"ditto","commit_id":"1d6b8ed67ec7c2c76f229a9f135eac69f020b436"},{"author":{"_account_id":11878,"name":"Rushil Chugh","email":"rushil.chugh@gmail.com","username":"rushil"},"change_message_id":"3992e3617781c3f2d4465473932b2fb05d96d7db","unresolved":false,"context_lines":[{"line_number":51,"context_line":"                          states.CLEANING, states.CLEANWAIT,"},{"line_number":52,"context_line":"                          states.INSPECTING}"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"_BOOT_CONFIG_ALLOWED_STATES \u003d {states.DEPLOYING,"},{"line_number":55,"context_line":"                               states.DEPLOYWAIT,"},{"line_number":56,"context_line":"                               states.CLEANING,"},{"line_number":57,"context_line":"                               states.CLEANWAIT,"}],"source_content_type":"text/x-python","patch_set":31,"id":"1a430d35_a1bb01e4","line":54,"range":{"start_line":54,"start_character":31,"end_line":54,"end_character":37},"updated":"2017-02-07 23:27:36.000000000","message":"Either move states.DEPLOYING to the next line or move the closing brace after states.CLEANWAIT right after the comma.","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"f7391efcb129459f5c6b5947fd30ca750956aad5","unresolved":false,"context_lines":[{"line_number":51,"context_line":"                          states.CLEANING, states.CLEANWAIT,"},{"line_number":52,"context_line":"                          states.INSPECTING}"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"_BOOT_CONFIG_ALLOWED_STATES \u003d {states.DEPLOYING,"},{"line_number":55,"context_line":"                               states.DEPLOYWAIT,"},{"line_number":56,"context_line":"                               states.CLEANING,"},{"line_number":57,"context_line":"                               states.CLEANWAIT,"}],"source_content_type":"text/x-python","patch_set":31,"id":"fa31d9ce_771f2c6c","line":54,"range":{"start_line":54,"start_character":31,"end_line":54,"end_character":37},"in_reply_to":"1a430d35_a1bb01e4","updated":"2017-02-14 11:25:07.000000000","message":"Done","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":19593,"name":"Anup Navare","email":"anup.d.navare@intel.com","username":"anup"},"change_message_id":"e854b8513575606bd6b632a5956df83e5b7cbaa3","unresolved":false,"context_lines":[{"line_number":233,"context_line":""},{"line_number":234,"context_line":"    @METRICS.timer(\u0027BootConfigController.get_all\u0027)"},{"line_number":235,"context_line":"    @expose.expose(FileResult)"},{"line_number":236,"context_line":"    def get_all(self):"},{"line_number":237,"context_line":"        \"\"\"Process boot script request from the node."},{"line_number":238,"context_line":""},{"line_number":239,"context_line":"        Returns iPXE boot script for the node attached to the response."}],"source_content_type":"text/x-python","patch_set":34,"id":"9a30ddce_75c6984a","line":236,"range":{"start_line":236,"start_character":8,"end_line":236,"end_character":15},"updated":"2017-03-08 01:21:25.000000000","message":"I think so name can be changed as get_all does not describe processing boot script.","commit_id":"80f71ea5a78eb54c1bc52e522bf0cfe08384b9fa"},{"author":{"_account_id":19593,"name":"Anup Navare","email":"anup.d.navare@intel.com","username":"anup"},"change_message_id":"e854b8513575606bd6b632a5956df83e5b7cbaa3","unresolved":false,"context_lines":[{"line_number":272,"context_line":"        # NOTE(pas-ha) mac is already converted from dashed to colon form"},{"line_number":273,"context_line":"        # due to general_macaddress wtype"},{"line_number":274,"context_line":"        try:"},{"line_number":275,"context_line":"            node \u003d objects.Node.get_by_port_addresses("},{"line_number":276,"context_line":"                pecan.request.context, [mac])"},{"line_number":277,"context_line":"        except exception.NotFound:"},{"line_number":278,"context_line":"            # NOTE(dtantsur): we are reraising the same exception to"}],"source_content_type":"text/x-python","patch_set":34,"id":"9a30ddce_b59bb071","line":275,"range":{"start_line":275,"start_character":32,"end_line":275,"end_character":53},"updated":"2017-03-08 01:21:25.000000000","message":"Will this still happen if called from lower api?","commit_id":"80f71ea5a78eb54c1bc52e522bf0cfe08384b9fa"},{"author":{"_account_id":19593,"name":"Anup Navare","email":"anup.d.navare@intel.com","username":"anup"},"change_message_id":"e854b8513575606bd6b632a5956df83e5b7cbaa3","unresolved":false,"context_lines":[{"line_number":283,"context_line":""},{"line_number":284,"context_line":"        if _deny_boot_config_for_node(node):"},{"line_number":285,"context_line":"            raise exception.NotFound()"},{"line_number":286,"context_line":"            # content \u003d ipxe.DENIED_BOOT_CONFIG"},{"line_number":287,"context_line":""},{"line_number":288,"context_line":"        LOG.debug(\u0027Requesting boot config for node %s\u0027, node.uuid)"},{"line_number":289,"context_line":"        rpc_node \u003d api_utils.get_rpc_node(node.uuid)"}],"source_content_type":"text/x-python","patch_set":34,"id":"9a30ddce_95c94c7b","line":286,"range":{"start_line":286,"start_character":14,"end_line":286,"end_character":47},"updated":"2017-03-08 01:21:25.000000000","message":"Do you think should this be passed to NotFound() to tell clear reason?","commit_id":"80f71ea5a78eb54c1bc52e522bf0cfe08384b9fa"},{"author":{"_account_id":13636,"name":"aarefiev","display_name":"Anton","email":"arefyevanton@gmail.com","username":"aarefiev"},"change_message_id":"083f306ac5f047dc166a062ca3ef8085a81b43a8","unresolved":false,"context_lines":[{"line_number":239,"context_line":""},{"line_number":240,"context_line":"        \"\"\""},{"line_number":241,"context_line":"        if not (CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_server_enabled):"},{"line_number":242,"context_line":"            raise exception.NotFound()"},{"line_number":243,"context_line":"        cdict \u003d pecan.request.context.to_policy_values()"},{"line_number":244,"context_line":"        policy.authorize(\u0027baremetal:boot_config\u0027, cdict, cdict)"},{"line_number":245,"context_line":"        LOG.debug(\u0027Building boot script\u0027)"}],"source_content_type":"text/x-python","patch_set":45,"id":"ff0f0b1f_527f4ddf","line":242,"range":{"start_line":242,"start_character":12,"end_line":242,"end_character":38},"updated":"2017-05-23 14:24:42.000000000","message":"I\u0027m wondering if `Gone` should be here to indicate that feature is disabled, but general NotFound works anyway.","commit_id":"526781104c40b73c4d70de2eebec4ff21817890d"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"964f2eef90e9a3eeece2468961a9d223372e5ae0","unresolved":false,"context_lines":[{"line_number":239,"context_line":""},{"line_number":240,"context_line":"        \"\"\""},{"line_number":241,"context_line":"        if not (CONF.pxe.ipxe_enabled and CONF.pxe.ipxe_server_enabled):"},{"line_number":242,"context_line":"            raise exception.NotFound()"},{"line_number":243,"context_line":"        cdict \u003d pecan.request.context.to_policy_values()"},{"line_number":244,"context_line":"        policy.authorize(\u0027baremetal:boot_config\u0027, cdict, cdict)"},{"line_number":245,"context_line":"        LOG.debug(\u0027Building boot script\u0027)"}],"source_content_type":"text/x-python","patch_set":45,"id":"ff0f0b1f_1d1a056e","line":242,"range":{"start_line":242,"start_character":12,"end_line":242,"end_character":38},"in_reply_to":"ff0f0b1f_527f4ddf","updated":"2017-05-23 15:33:34.000000000","message":"I\u0027m following the same security approach as in get_one, that is not to leak the internal settings out on API requests.","commit_id":"526781104c40b73c4d70de2eebec4ff21817890d"},{"author":{"_account_id":26340,"name":"Ilya Etingof","email":"etingof@gmail.com","username":"etingof"},"change_message_id":"0452ce21464b89d1328f4d3742c92e6869810363","unresolved":false,"context_lines":[{"line_number":218,"context_line":""},{"line_number":219,"context_line":"    def __init__(self, content):"},{"line_number":220,"context_line":"        if isinstance(content, six.text_type):"},{"line_number":221,"context_line":"            # If unicode, convert to bytes"},{"line_number":222,"context_line":"            content \u003d content.encode(\u0027utf-8\u0027)"},{"line_number":223,"context_line":"        file_ \u003d wtypes.File(content\u003dcontent)"},{"line_number":224,"context_line":"        pecan.response.app_iter \u003d static.FileIter(file_.file)"}],"source_content_type":"text/x-python","patch_set":55,"id":"7f287b81_c102c909","line":221,"range":{"start_line":221,"start_character":37,"end_line":221,"end_character":42},"updated":"2017-08-24 13:51:46.000000000","message":"nit: with Py2 it will be `str`, not bytes`","commit_id":"a5ea721f4c8c24f75d2da5e27ec8a6e095bf05c0"}],"ironic/common/policy.py":[{"author":{"_account_id":13636,"name":"aarefiev","display_name":"Anton","email":"arefyevanton@gmail.com","username":"aarefiev"},"change_message_id":"083f306ac5f047dc166a062ca3ef8085a81b43a8","unresolved":false,"context_lines":[{"line_number":202,"context_line":"    policy.RuleDefault(\u0027baremetal:driver:ipa_lookup\u0027,"},{"line_number":203,"context_line":"                       \u0027rule:public_api\u0027,"},{"line_number":204,"context_line":"                       description\u003d\u0027Access IPA ramdisk functions\u0027),"},{"line_number":205,"context_line":"    policy.RuleDefault(\u0027baremetal:boot_config\u0027,"},{"line_number":206,"context_line":"                       \u0027rule:public_api\u0027,"},{"line_number":207,"context_line":"                       description\u003d\u0027Fetch boot configuration files\u0027),"},{"line_number":208,"context_line":"]"},{"line_number":209,"context_line":""},{"line_number":210,"context_line":""}],"source_content_type":"text/x-python","patch_set":45,"id":"ff0f0b1f_77292388","line":207,"range":{"start_line":205,"start_character":0,"end_line":207,"end_character":69},"updated":"2017-05-23 14:24:42.000000000","message":"nit: it would be nice to update sample policy\nhttps://github.com/openstack/ironic/blob/master/etc/ironic/policy.json.sample","commit_id":"526781104c40b73c4d70de2eebec4ff21817890d"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"964f2eef90e9a3eeece2468961a9d223372e5ae0","unresolved":false,"context_lines":[{"line_number":202,"context_line":"    policy.RuleDefault(\u0027baremetal:driver:ipa_lookup\u0027,"},{"line_number":203,"context_line":"                       \u0027rule:public_api\u0027,"},{"line_number":204,"context_line":"                       description\u003d\u0027Access IPA ramdisk functions\u0027),"},{"line_number":205,"context_line":"    policy.RuleDefault(\u0027baremetal:boot_config\u0027,"},{"line_number":206,"context_line":"                       \u0027rule:public_api\u0027,"},{"line_number":207,"context_line":"                       description\u003d\u0027Fetch boot configuration files\u0027),"},{"line_number":208,"context_line":"]"},{"line_number":209,"context_line":""},{"line_number":210,"context_line":""}],"source_content_type":"text/x-python","patch_set":45,"id":"ff0f0b1f_9d1f355a","line":207,"range":{"start_line":205,"start_character":0,"end_line":207,"end_character":69},"in_reply_to":"ff0f0b1f_77292388","updated":"2017-05-23 15:33:34.000000000","message":"will do","commit_id":"526781104c40b73c4d70de2eebec4ff21817890d"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"2104fe8832f2804e8374e3493ccf03ad77f9ac78","unresolved":false,"context_lines":[{"line_number":202,"context_line":"    policy.RuleDefault(\u0027baremetal:driver:ipa_lookup\u0027,"},{"line_number":203,"context_line":"                       \u0027rule:public_api\u0027,"},{"line_number":204,"context_line":"                       description\u003d\u0027Access IPA ramdisk functions\u0027),"},{"line_number":205,"context_line":"    policy.RuleDefault(\u0027baremetal:boot_config\u0027,"},{"line_number":206,"context_line":"                       \u0027rule:public_api\u0027,"},{"line_number":207,"context_line":"                       description\u003d\u0027Fetch boot configuration files\u0027),"},{"line_number":208,"context_line":"]"},{"line_number":209,"context_line":""},{"line_number":210,"context_line":""}],"source_content_type":"text/x-python","patch_set":45,"id":"ff0f0b1f_207a20b9","line":207,"range":{"start_line":205,"start_character":0,"end_line":207,"end_character":69},"in_reply_to":"ff0f0b1f_9d1f355a","updated":"2017-05-24 10:30:44.000000000","message":"I\u0027d probably delay that to the documentation patch when the actual details have been finalized.","commit_id":"526781104c40b73c4d70de2eebec4ff21817890d"}],"ironic/conf/api.py":[{"author":{"_account_id":13636,"name":"aarefiev","display_name":"Anton","email":"arefyevanton@gmail.com","username":"aarefiev"},"change_message_id":"083f306ac5f047dc166a062ca3ef8085a81b43a8","unresolved":false,"context_lines":[{"line_number":60,"context_line":"    cfg.BoolOpt(\u0027restrict_boot_config\u0027,"},{"line_number":61,"context_line":"                default\u003dTrue,"},{"line_number":62,"context_line":"                help\u003d_(\u0027Whether to restrict the boot config API \u0027"},{"line_number":63,"context_line":"                       \u0027to only nodes in certain states.\u0027)),"},{"line_number":64,"context_line":"]"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"opt_group \u003d cfg.OptGroup(name\u003d\u0027api\u0027,"}],"source_content_type":"text/x-python","patch_set":45,"id":"ff0f0b1f_d7c34f88","line":63,"range":{"start_line":63,"start_character":41,"end_line":63,"end_character":48},"updated":"2017-05-23 14:24:42.000000000","message":"would be useful to list this states","commit_id":"526781104c40b73c4d70de2eebec4ff21817890d"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"964f2eef90e9a3eeece2468961a9d223372e5ae0","unresolved":false,"context_lines":[{"line_number":60,"context_line":"    cfg.BoolOpt(\u0027restrict_boot_config\u0027,"},{"line_number":61,"context_line":"                default\u003dTrue,"},{"line_number":62,"context_line":"                help\u003d_(\u0027Whether to restrict the boot config API \u0027"},{"line_number":63,"context_line":"                       \u0027to only nodes in certain states.\u0027)),"},{"line_number":64,"context_line":"]"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"opt_group \u003d cfg.OptGroup(name\u003d\u0027api\u0027,"}],"source_content_type":"text/x-python","patch_set":45,"id":"ff0f0b1f_dd4ecd6d","line":63,"range":{"start_line":63,"start_character":41,"end_line":63,"end_character":48},"in_reply_to":"ff0f0b1f_d7c34f88","updated":"2017-05-23 15:33:34.000000000","message":"I could add that, but note that restrict_lookup above is also not listing those explicitly.","commit_id":"526781104c40b73c4d70de2eebec4ff21817890d"}],"ironic/drivers/modules/ipxe.py":[{"author":{"_account_id":7900,"name":"Tomasz Paszkowski","email":"ss7pro@gmail.com","username":"tpaszkowski"},"change_message_id":"fb1eb59e59f6852b153f7b36456818b9f2b395e7","unresolved":false,"context_lines":[{"line_number":18,"context_line":"import six"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"DENIED_BOOT_CONFIG \u003d \"\"\"#!ipxe"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"echo PXE boot failed! This Ironic Node is in wrong provision state"},{"line_number":24,"context_line":"echo Press any key to reboot"}],"source_content_type":"text/x-python","patch_set":10,"id":"ba5da102_8998856c","line":21,"updated":"2016-11-05 14:17:17.000000000","message":"I would prefer to have those ipxe templates as a j2 files, where each file path is configured in ironic.conf so operators can customize those templates to their specific needs.","commit_id":"5ca9fcc168155de1333dd4977c20f4752107aa4a"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"bd5a83854c030dce12b58001b86c71b3fabb1692","unresolved":false,"context_lines":[{"line_number":18,"context_line":"import six"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"DENIED_BOOT_CONFIG \u003d \"\"\"#!ipxe"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"echo PXE boot failed! This Ironic Node is in wrong provision state"},{"line_number":24,"context_line":"echo Press any key to reboot"}],"source_content_type":"text/x-python","patch_set":10,"id":"9a629dbe_b69a21c4","line":21,"in_reply_to":"ba5da102_8998856c","updated":"2016-11-07 12:15:21.000000000","message":"I am actually ditching that for now (let\u0027s discuss in the spec if it is needed/has to be implemented).\n\nFor now, for the same security considerations as lookup/heartbeat, nodes in inappropriate states would receive NotFound error to not leak the actual difference between node missing or node in a wrong state (see next patch-sets in this series).","commit_id":"5ca9fcc168155de1333dd4977c20f4752107aa4a"}],"ironic/tests/unit/api/v1/test_ramdisk.py":[{"author":{"_account_id":11878,"name":"Rushil Chugh","email":"rushil.chugh@gmail.com","username":"rushil"},"change_message_id":"3992e3617781c3f2d4465473932b2fb05d96d7db","unresolved":false,"context_lines":[{"line_number":206,"context_line":"                    ipxe_server_enabled\u003dTrue,"},{"line_number":207,"context_line":"                    ipxe_boot_script\u003d\u0027fake_ipxe_script_path\u0027)"},{"line_number":208,"context_line":"        self.config(group\u003d\u0027conductor\u0027, api_url\u003d\u0027http://1.2.3.4:5678\u0027)"},{"line_number":209,"context_line":"        fake_script \u003d \u0027fake_ipxe_script\u0027"},{"line_number":210,"context_line":"        render_mock.return_value \u003d fake_script"},{"line_number":211,"context_line":"        if isinstance(fake_script, six.text_type):"},{"line_number":212,"context_line":"            expected_body \u003d fake_script.encode(\u0027utf-8\u0027)"}],"source_content_type":"text/x-python","patch_set":31,"id":"1a430d35_814445b7","line":209,"range":{"start_line":209,"start_character":21,"end_line":209,"end_character":22},"updated":"2017-02-07 23:27:36.000000000","message":"Can fake_script be moved to the top of the file so that it can be reused in all the tests?","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"f7391efcb129459f5c6b5947fd30ca750956aad5","unresolved":false,"context_lines":[{"line_number":206,"context_line":"                    ipxe_server_enabled\u003dTrue,"},{"line_number":207,"context_line":"                    ipxe_boot_script\u003d\u0027fake_ipxe_script_path\u0027)"},{"line_number":208,"context_line":"        self.config(group\u003d\u0027conductor\u0027, api_url\u003d\u0027http://1.2.3.4:5678\u0027)"},{"line_number":209,"context_line":"        fake_script \u003d \u0027fake_ipxe_script\u0027"},{"line_number":210,"context_line":"        render_mock.return_value \u003d fake_script"},{"line_number":211,"context_line":"        if isinstance(fake_script, six.text_type):"},{"line_number":212,"context_line":"            expected_body \u003d fake_script.encode(\u0027utf-8\u0027)"}],"source_content_type":"text/x-python","patch_set":31,"id":"fa31d9ce_3d47554c","line":209,"range":{"start_line":209,"start_character":21,"end_line":209,"end_character":22},"in_reply_to":"1a430d35_814445b7","updated":"2017-02-14 11:25:07.000000000","message":"Done","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":11878,"name":"Rushil Chugh","email":"rushil.chugh@gmail.com","username":"rushil"},"change_message_id":"3992e3617781c3f2d4465473932b2fb05d96d7db","unresolved":false,"context_lines":[{"line_number":229,"context_line":"        self.config(group\u003d\u0027pxe\u0027,"},{"line_number":230,"context_line":"                    ipxe_enabled\u003dTrue,"},{"line_number":231,"context_line":"                    ipxe_server_enabled\u003dTrue)"},{"line_number":232,"context_line":"        node_address \u003d \u002711:22:33:44:55:66\u0027"},{"line_number":233,"context_line":"        node \u003d obj_utils.create_test_node(self.context,"},{"line_number":234,"context_line":"                                          provision_state\u003d\u0027deploying\u0027)"},{"line_number":235,"context_line":"        obj_utils.create_test_port(self.context,"}],"source_content_type":"text/x-python","patch_set":31,"id":"1a430d35_611e79bc","line":232,"updated":"2017-02-07 23:27:36.000000000","message":"Can fake_node_address be moved to the top of the file so that it can be reused in all the tests?","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"f7391efcb129459f5c6b5947fd30ca750956aad5","unresolved":false,"context_lines":[{"line_number":229,"context_line":"        self.config(group\u003d\u0027pxe\u0027,"},{"line_number":230,"context_line":"                    ipxe_enabled\u003dTrue,"},{"line_number":231,"context_line":"                    ipxe_server_enabled\u003dTrue)"},{"line_number":232,"context_line":"        node_address \u003d \u002711:22:33:44:55:66\u0027"},{"line_number":233,"context_line":"        node \u003d obj_utils.create_test_node(self.context,"},{"line_number":234,"context_line":"                                          provision_state\u003d\u0027deploying\u0027)"},{"line_number":235,"context_line":"        obj_utils.create_test_port(self.context,"}],"source_content_type":"text/x-python","patch_set":31,"id":"fa31d9ce_9d6cc1d1","line":232,"in_reply_to":"1a430d35_611e79bc","updated":"2017-02-14 11:25:07.000000000","message":"Done","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":11878,"name":"Rushil Chugh","email":"rushil.chugh@gmail.com","username":"rushil"},"change_message_id":"3992e3617781c3f2d4465473932b2fb05d96d7db","unresolved":false,"context_lines":[{"line_number":235,"context_line":"        obj_utils.create_test_port(self.context,"},{"line_number":236,"context_line":"                                   node_id\u003dnode.id,"},{"line_number":237,"context_line":"                                   address\u003dnode_address)"},{"line_number":238,"context_line":"        fake_boot_config \u003d \u0027fake_boot_config\u0027"},{"line_number":239,"context_line":"        mock_boot_config.return_value \u003d fake_boot_config"},{"line_number":240,"context_line":"        if isinstance(fake_boot_config, six.text_type):"},{"line_number":241,"context_line":"            expected_body \u003d fake_boot_config.encode(\u0027utf-8\u0027)"}],"source_content_type":"text/x-python","patch_set":31,"id":"1a430d35_e1098985","line":238,"range":{"start_line":238,"start_character":8,"end_line":238,"end_character":24},"updated":"2017-02-07 23:27:36.000000000","message":"Can fake_boot_config be moved to the top of the file so that it can be reused in all the tests?","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"f7391efcb129459f5c6b5947fd30ca750956aad5","unresolved":false,"context_lines":[{"line_number":235,"context_line":"        obj_utils.create_test_port(self.context,"},{"line_number":236,"context_line":"                                   node_id\u003dnode.id,"},{"line_number":237,"context_line":"                                   address\u003dnode_address)"},{"line_number":238,"context_line":"        fake_boot_config \u003d \u0027fake_boot_config\u0027"},{"line_number":239,"context_line":"        mock_boot_config.return_value \u003d fake_boot_config"},{"line_number":240,"context_line":"        if isinstance(fake_boot_config, six.text_type):"},{"line_number":241,"context_line":"            expected_body \u003d fake_boot_config.encode(\u0027utf-8\u0027)"}],"source_content_type":"text/x-python","patch_set":31,"id":"fa31d9ce_bd7185aa","line":238,"range":{"start_line":238,"start_character":8,"end_line":238,"end_character":24},"in_reply_to":"1a430d35_e1098985","updated":"2017-02-14 11:25:07.000000000","message":"Done","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":11878,"name":"Rushil Chugh","email":"rushil.chugh@gmail.com","username":"rushil"},"change_message_id":"3992e3617781c3f2d4465473932b2fb05d96d7db","unresolved":false,"context_lines":[{"line_number":258,"context_line":"        self.config(group\u003d\u0027pxe\u0027,"},{"line_number":259,"context_line":"                    ipxe_enabled\u003dTrue,"},{"line_number":260,"context_line":"                    ipxe_server_enabled\u003dTrue)"},{"line_number":261,"context_line":"        node_address \u003d \u002711:22:33:44:55:66\u0027"},{"line_number":262,"context_line":"        node \u003d obj_utils.create_test_node(self.context,"},{"line_number":263,"context_line":"                                          provision_state\u003d\u0027active\u0027)"},{"line_number":264,"context_line":"        obj_utils.create_test_port(self.context,"}],"source_content_type":"text/x-python","patch_set":31,"id":"1a430d35_a17a21ef","line":261,"updated":"2017-02-07 23:27:36.000000000","message":"Can fake_node_address be moved to the top of the file so that it can be reused in all the tests?","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"f7391efcb129459f5c6b5947fd30ca750956aad5","unresolved":false,"context_lines":[{"line_number":258,"context_line":"        self.config(group\u003d\u0027pxe\u0027,"},{"line_number":259,"context_line":"                    ipxe_enabled\u003dTrue,"},{"line_number":260,"context_line":"                    ipxe_server_enabled\u003dTrue)"},{"line_number":261,"context_line":"        node_address \u003d \u002711:22:33:44:55:66\u0027"},{"line_number":262,"context_line":"        node \u003d obj_utils.create_test_node(self.context,"},{"line_number":263,"context_line":"                                          provision_state\u003d\u0027active\u0027)"},{"line_number":264,"context_line":"        obj_utils.create_test_port(self.context,"}],"source_content_type":"text/x-python","patch_set":31,"id":"fa31d9ce_dd6ab9b2","line":261,"in_reply_to":"1a430d35_a17a21ef","updated":"2017-02-14 11:25:07.000000000","message":"Done","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":11878,"name":"Rushil Chugh","email":"rushil.chugh@gmail.com","username":"rushil"},"change_message_id":"3992e3617781c3f2d4465473932b2fb05d96d7db","unresolved":false,"context_lines":[{"line_number":280,"context_line":"        self.config(group\u003d\u0027pxe\u0027,"},{"line_number":281,"context_line":"                    ipxe_enabled\u003dTrue,"},{"line_number":282,"context_line":"                    ipxe_server_enabled\u003dTrue)"},{"line_number":283,"context_line":"        fake_boot_config \u003d \u0027fake_boot_config\u0027"},{"line_number":284,"context_line":"        mock_boot_config.return_value \u003d fake_boot_config"},{"line_number":285,"context_line":"        if isinstance(fake_boot_config, six.text_type):"},{"line_number":286,"context_line":"            expected_body \u003d fake_boot_config.encode(\u0027utf-8\u0027)"}],"source_content_type":"text/x-python","patch_set":31,"id":"1a430d35_216f112c","line":283,"updated":"2017-02-07 23:27:36.000000000","message":"Same comment as above.","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"f7391efcb129459f5c6b5947fd30ca750956aad5","unresolved":false,"context_lines":[{"line_number":280,"context_line":"        self.config(group\u003d\u0027pxe\u0027,"},{"line_number":281,"context_line":"                    ipxe_enabled\u003dTrue,"},{"line_number":282,"context_line":"                    ipxe_server_enabled\u003dTrue)"},{"line_number":283,"context_line":"        fake_boot_config \u003d \u0027fake_boot_config\u0027"},{"line_number":284,"context_line":"        mock_boot_config.return_value \u003d fake_boot_config"},{"line_number":285,"context_line":"        if isinstance(fake_boot_config, six.text_type):"},{"line_number":286,"context_line":"            expected_body \u003d fake_boot_config.encode(\u0027utf-8\u0027)"}],"source_content_type":"text/x-python","patch_set":31,"id":"fa31d9ce_fd677de6","line":283,"in_reply_to":"1a430d35_216f112c","updated":"2017-02-14 11:25:07.000000000","message":"Done","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":11878,"name":"Rushil Chugh","email":"rushil.chugh@gmail.com","username":"rushil"},"change_message_id":"3992e3617781c3f2d4465473932b2fb05d96d7db","unresolved":false,"context_lines":[{"line_number":286,"context_line":"            expected_body \u003d fake_boot_config.encode(\u0027utf-8\u0027)"},{"line_number":287,"context_line":"        else:"},{"line_number":288,"context_line":"            expected_body \u003d fake_boot_config"},{"line_number":289,"context_line":"        node_address \u003d \u002711:22:33:44:55:66\u0027"},{"line_number":290,"context_line":"        node \u003d obj_utils.create_test_node(self.context,"},{"line_number":291,"context_line":"                                          provision_state\u003d\u0027active\u0027)"},{"line_number":292,"context_line":"        obj_utils.create_test_port(self.context,"}],"source_content_type":"text/x-python","patch_set":31,"id":"1a430d35_e180a9c1","line":289,"updated":"2017-02-07 23:27:36.000000000","message":"Same comment as above","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"},{"author":{"_account_id":9542,"name":"Pavlo Shchelokovskyy","email":"pshchelokovskyy@mirantis.com","username":"pshchelo"},"change_message_id":"f7391efcb129459f5c6b5947fd30ca750956aad5","unresolved":false,"context_lines":[{"line_number":286,"context_line":"            expected_body \u003d fake_boot_config.encode(\u0027utf-8\u0027)"},{"line_number":287,"context_line":"        else:"},{"line_number":288,"context_line":"            expected_body \u003d fake_boot_config"},{"line_number":289,"context_line":"        node_address \u003d \u002711:22:33:44:55:66\u0027"},{"line_number":290,"context_line":"        node \u003d obj_utils.create_test_node(self.context,"},{"line_number":291,"context_line":"                                          provision_state\u003d\u0027active\u0027)"},{"line_number":292,"context_line":"        obj_utils.create_test_port(self.context,"}],"source_content_type":"text/x-python","patch_set":31,"id":"fa31d9ce_1d61b1d3","line":289,"in_reply_to":"1a430d35_e180a9c1","updated":"2017-02-14 11:25:07.000000000","message":"Done","commit_id":"627d6ec77b5251a091ccae481ed3ef2d8e978533"}]}
