)]}'
{"ironic/conductor/manager.py":[{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"979ce75f2b05fe663838df35c0ef6f6ba3028c42","unresolved":false,"context_lines":[{"line_number":211,"context_line":"            # Prevent setting traits in instance_info that are not present on"},{"line_number":212,"context_line":"            # the node."},{"line_number":213,"context_line":"            if \u0027instance_info\u0027 in delta:"},{"line_number":214,"context_line":"                instance_traits \u003d node_obj.instance_info.get(\u0027traits\u0027, [])"},{"line_number":215,"context_line":"                # TODO(mgoddard): Remove the obj_attr_is_set() call in Rocky"},{"line_number":216,"context_line":"                # when all node objects will have a traits field."},{"line_number":217,"context_line":"                node_traits \u003d (task.node.traits.get_trait_names()"}],"source_content_type":"text/x-python","patch_set":1,"id":"3fa0c359_8449e3b7","line":214,"updated":"2018-02-12 21:01:41.000000000","message":"if this is [], no need to do anything more. Is it worth checking? Maybe not.","commit_id":"2b8a58583beb4adce39d57ebf9d83fe91e342a33"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"6dfb738da069b49f9da50244d3a3b18aae79f5c0","unresolved":false,"context_lines":[{"line_number":211,"context_line":"            # Prevent setting traits in instance_info that are not present on"},{"line_number":212,"context_line":"            # the node."},{"line_number":213,"context_line":"            if \u0027instance_info\u0027 in delta:"},{"line_number":214,"context_line":"                instance_traits \u003d node_obj.instance_info.get(\u0027traits\u0027, [])"},{"line_number":215,"context_line":"                # TODO(mgoddard): Remove the obj_attr_is_set() call in Rocky"},{"line_number":216,"context_line":"                # when all node objects will have a traits field."},{"line_number":217,"context_line":"                node_traits \u003d (task.node.traits.get_trait_names()"}],"source_content_type":"text/x-python","patch_set":1,"id":"3fa0c359_bd64174b","line":214,"in_reply_to":"3fa0c359_8449e3b7","updated":"2018-02-13 18:44:01.000000000","message":"Done","commit_id":"2b8a58583beb4adce39d57ebf9d83fe91e342a33"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"979ce75f2b05fe663838df35c0ef6f6ba3028c42","unresolved":false,"context_lines":[{"line_number":3132,"context_line":"        with task_manager.acquire(context, node_id,"},{"line_number":3133,"context_line":"                                  purpose\u003d\u0027remove node traits\u0027) as task:"},{"line_number":3134,"context_line":"            # Prevent removing traits from the node that are present in"},{"line_number":3135,"context_line":"            # instance_info."},{"line_number":3136,"context_line":"            instance_traits \u003d task.node.instance_info.get(\u0027traits\u0027, [])"},{"line_number":3137,"context_line":"            removed_traits \u003d (task.node.traits.get_trait_names()"},{"line_number":3138,"context_line":"                              if traits is None else traits)"}],"source_content_type":"text/x-python","patch_set":1,"id":"3fa0c359_4420bbac","line":3135,"updated":"2018-02-12 21:01:41.000000000","message":"what we\u0027re saying, sort of, is that we aren\u0027t going to allow deletion of traits while a node is deployed/active, but we\u0027re going to allow addition of traits. Which is a bit icky. Will people get confused by this?\n\nMakes me wonder if we should just bite the bullet and don\u0027t allow changes to node traits when a node is in certain states, but then we\u0027d have to figure out which states: \u0027available\u0027, \u0027deploying\u0027, \u0027active\u0027, \u0027rescue*\u0027, ...","commit_id":"2b8a58583beb4adce39d57ebf9d83fe91e342a33"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"6dfb738da069b49f9da50244d3a3b18aae79f5c0","unresolved":false,"context_lines":[{"line_number":3132,"context_line":"        with task_manager.acquire(context, node_id,"},{"line_number":3133,"context_line":"                                  purpose\u003d\u0027remove node traits\u0027) as task:"},{"line_number":3134,"context_line":"            # Prevent removing traits from the node that are present in"},{"line_number":3135,"context_line":"            # instance_info."},{"line_number":3136,"context_line":"            instance_traits \u003d task.node.instance_info.get(\u0027traits\u0027, [])"},{"line_number":3137,"context_line":"            removed_traits \u003d (task.node.traits.get_trait_names()"},{"line_number":3138,"context_line":"                              if traits is None else traits)"}],"source_content_type":"text/x-python","patch_set":1,"id":"3fa0c359_0fe952e4","line":3135,"in_reply_to":"3fa0c359_4420bbac","updated":"2018-02-13 18:44:01.000000000","message":"I\u0027m just thinking we should prevent the removal of traits that are in use, and I\u0027ve defined \u0027in use\u0027 to mean in instance_info, regardless of whether or not the node is deployed. That way we can enforce that instance traits are always a subset of node traits.\n\nWe probably ought to go with the existing patterns in ironic here, which is to be open to updates to instance_info, then validate during the deploy. Doing that makes the check here in remove_node_traits less important, and possibly something that could be implemented separately.","commit_id":"2b8a58583beb4adce39d57ebf9d83fe91e342a33"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"979ce75f2b05fe663838df35c0ef6f6ba3028c42","unresolved":false,"context_lines":[{"line_number":3139,"context_line":"            in_use \u003d set(instance_traits) \u0026 set(removed_traits)"},{"line_number":3140,"context_line":"            if in_use:"},{"line_number":3141,"context_line":"                err \u003d (_(\"Cannot remove traits from node %(node)s that are in \""},{"line_number":3142,"context_line":"                         \"instance_info. Traits in use: %(traits)s\") %"},{"line_number":3143,"context_line":"                       {\u0027node\u0027: task.node.uuid,"},{"line_number":3144,"context_line":"                        \u0027traits\u0027: \u0027, \u0027.join(in_use)})"},{"line_number":3145,"context_line":"                raise exception.InvalidParameterValue(err\u003derr)"}],"source_content_type":"text/x-python","patch_set":1,"id":"3fa0c359_3f02580b","line":3142,"updated":"2018-02-12 21:01:41.000000000","message":"traits are only in use if the node is being deployed/active/etc. instance_info is set before that though.","commit_id":"2b8a58583beb4adce39d57ebf9d83fe91e342a33"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"6dfb738da069b49f9da50244d3a3b18aae79f5c0","unresolved":false,"context_lines":[{"line_number":3139,"context_line":"            in_use \u003d set(instance_traits) \u0026 set(removed_traits)"},{"line_number":3140,"context_line":"            if in_use:"},{"line_number":3141,"context_line":"                err \u003d (_(\"Cannot remove traits from node %(node)s that are in \""},{"line_number":3142,"context_line":"                         \"instance_info. Traits in use: %(traits)s\") %"},{"line_number":3143,"context_line":"                       {\u0027node\u0027: task.node.uuid,"},{"line_number":3144,"context_line":"                        \u0027traits\u0027: \u0027, \u0027.join(in_use)})"},{"line_number":3145,"context_line":"                raise exception.InvalidParameterValue(err\u003derr)"}],"source_content_type":"text/x-python","patch_set":1,"id":"3fa0c359_2fe44e0c","line":3142,"in_reply_to":"3fa0c359_3f02580b","updated":"2018-02-13 18:44:01.000000000","message":"See above :)","commit_id":"2b8a58583beb4adce39d57ebf9d83fe91e342a33"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"57c08fb6033468d3e67b91188c3d192ed082d0e7","unresolved":false,"context_lines":[{"line_number":1843,"context_line":"                            \u0027%(iface)s driver interface for driver \u0027"},{"line_number":1844,"context_line":"                            \u0027%(driver)s: %(err)s on node %(node)s.\u0027,"},{"line_number":1845,"context_line":"                            {\u0027iface\u0027: iface_name, \u0027driver\u0027: task.node.driver,"},{"line_number":1846,"context_line":"                             \u0027err\u0027: e, \u0027node\u0027: task.node.uuid})"},{"line_number":1847,"context_line":"                else:"},{"line_number":1848,"context_line":"                    reason \u003d _(\u0027not supported\u0027)"},{"line_number":1849,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"df7087c5_8afd9cb2","line":1846,"updated":"2018-03-13 18:50:08.000000000","message":"I hate to suggest this but... really, this validation should be part of deploy.validate(). We\u0027re hacking it in. I think that if GET /v1/nodes/\u003cnode\u003e/validate [1] is called, we also need to do the validation and return it as part of the deploy.validate().\n\nthe nova-virt-ironic driver makes this call [2].\n\n[1] https://developer.openstack.org/api-ref/baremetal/#validate-node\n[2] https://github.com/openstack/nova/blob/e177ca8a10220756109f60c0695aaa4449f6be58/nova/virt/ironic/driver.py#L1034","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"3cc391c14376db300464c679978b6f79988690a5","unresolved":false,"context_lines":[{"line_number":1843,"context_line":"                            \u0027%(iface)s driver interface for driver \u0027"},{"line_number":1844,"context_line":"                            \u0027%(driver)s: %(err)s on node %(node)s.\u0027,"},{"line_number":1845,"context_line":"                            {\u0027iface\u0027: iface_name, \u0027driver\u0027: task.node.driver,"},{"line_number":1846,"context_line":"                             \u0027err\u0027: e, \u0027node\u0027: task.node.uuid})"},{"line_number":1847,"context_line":"                else:"},{"line_number":1848,"context_line":"                    reason \u003d _(\u0027not supported\u0027)"},{"line_number":1849,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"df7087c5_b9d30d60","line":1846,"in_reply_to":"df7087c5_8afd9cb2","updated":"2018-03-14 11:50:38.000000000","message":"Wasn\u0027t the argument against adding it to deploy.validate that it should apply to all deploy drivers, and each would need to implement it individually? It would be possible to add the call to validate_driver_interfaces.\n\nWould it seem less hacky if it was wrapped in a more generic validate_node() method, which could potentially perform other validation that is not driver-specific in future?","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"9b1f7a5b23954c2a2ef8d5be35bca96a07578cb5","unresolved":false,"context_lines":[{"line_number":1843,"context_line":"                            \u0027%(iface)s driver interface for driver \u0027"},{"line_number":1844,"context_line":"                            \u0027%(driver)s: %(err)s on node %(node)s.\u0027,"},{"line_number":1845,"context_line":"                            {\u0027iface\u0027: iface_name, \u0027driver\u0027: task.node.driver,"},{"line_number":1846,"context_line":"                             \u0027err\u0027: e, \u0027node\u0027: task.node.uuid})"},{"line_number":1847,"context_line":"                else:"},{"line_number":1848,"context_line":"                    reason \u003d _(\u0027not supported\u0027)"},{"line_number":1849,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"df7087c5_41e42be0","line":1846,"in_reply_to":"df7087c5_b9d30d60","updated":"2018-03-14 20:12:05.000000000","message":"The problem with adding it to every deploy.validate() is that we can\u0027t add it to out-of-tree drivers. I guess what we didn\u0027t think of, was to add hooks to each of the driver interfaces, to automatically call a general \u003cinterface\u003e-validate() and glom the results. That\u0027d be your generic validate_node() method, but per interface (vs per driver \u0026 interface).\n\nFrom the API perspective, the GET /v1/nodes/\u003cnode\u003e/validate should return the info needed so that the user knows whether there is anything missing/incorrect.","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"af30e7726af3fc7f128fee4f4dd8bf6e0c34329e","unresolved":false,"context_lines":[{"line_number":1856,"context_line":"            except exception.InvalidParameterValue as e:"},{"line_number":1857,"context_line":"                ret_dict.setdefault(\u0027deploy\u0027, {})"},{"line_number":1858,"context_line":"                ret_dict[\u0027deploy\u0027][\u0027result\u0027] \u003d False"},{"line_number":1859,"context_line":"                ret_dict[\u0027deploy\u0027][\u0027reason\u0027] \u003d str(e)"},{"line_number":1860,"context_line":"        return ret_dict"},{"line_number":1861,"context_line":""},{"line_number":1862,"context_line":"    @METRICS.timer(\u0027ConductorManager.destroy_node\u0027)"}],"source_content_type":"text/x-python","patch_set":13,"id":"df7087c5_fb826b52","line":1859,"updated":"2018-03-19 15:22:34.000000000","message":"I think we should combine any existing errors from deploy, with this one. Concatenating the strings should be good enough.","commit_id":"7d15cc2d1631dec0a6affb99cf3a734aeb959a23"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"56a6cab86a2c3169321df8563f2b8b6b58b56693","unresolved":false,"context_lines":[{"line_number":1856,"context_line":"            except exception.InvalidParameterValue as e:"},{"line_number":1857,"context_line":"                ret_dict.setdefault(\u0027deploy\u0027, {})"},{"line_number":1858,"context_line":"                ret_dict[\u0027deploy\u0027][\u0027result\u0027] \u003d False"},{"line_number":1859,"context_line":"                ret_dict[\u0027deploy\u0027][\u0027reason\u0027] \u003d str(e)"},{"line_number":1860,"context_line":"        return ret_dict"},{"line_number":1861,"context_line":""},{"line_number":1862,"context_line":"    @METRICS.timer(\u0027ConductorManager.destroy_node\u0027)"}],"source_content_type":"text/x-python","patch_set":13,"id":"bf659307_d59cbd5e","line":1859,"in_reply_to":"df7087c5_3df2dc07","updated":"2018-03-28 14:27:05.000000000","message":"Ugh, I thought we returned all errors at one time. That seems like a better user experience vs re-issuing the request to see if there are other issues. Maybe that slipped through the cracks, dunno. Then we\u0027re good with what you had here, or with the change you made.","commit_id":"7d15cc2d1631dec0a6affb99cf3a734aeb959a23"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"d1c0b7ddcec30a18c1ee12850d839a68d5161ad8","unresolved":false,"context_lines":[{"line_number":1856,"context_line":"            except exception.InvalidParameterValue as e:"},{"line_number":1857,"context_line":"                ret_dict.setdefault(\u0027deploy\u0027, {})"},{"line_number":1858,"context_line":"                ret_dict[\u0027deploy\u0027][\u0027result\u0027] \u003d False"},{"line_number":1859,"context_line":"                ret_dict[\u0027deploy\u0027][\u0027reason\u0027] \u003d str(e)"},{"line_number":1860,"context_line":"        return ret_dict"},{"line_number":1861,"context_line":""},{"line_number":1862,"context_line":"    @METRICS.timer(\u0027ConductorManager.destroy_node\u0027)"}],"source_content_type":"text/x-python","patch_set":13,"id":"df7087c5_3df2dc07","line":1859,"in_reply_to":"df7087c5_8cdc1c19","updated":"2018-03-21 12:02:00.000000000","message":"I had a look at the agent deploy driver validate method. While there is some concatenation of messages when checking a specific thing [1], most validation is a series of \u0027if validation of X fails then raise\u0027 statements - in general you\u0027ll only see the first problem.\n\nStill open to concatenation, but thought I\u0027d raise this.\n\n[1] https://github.com/openstack/ironic/blob/master/ironic/drivers/modules/agent.py#L109","commit_id":"7d15cc2d1631dec0a6affb99cf3a734aeb959a23"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"9aea19d51c6dd670814e7b9c67881ac95e245802","unresolved":false,"context_lines":[{"line_number":1856,"context_line":"            except exception.InvalidParameterValue as e:"},{"line_number":1857,"context_line":"                ret_dict.setdefault(\u0027deploy\u0027, {})"},{"line_number":1858,"context_line":"                ret_dict[\u0027deploy\u0027][\u0027result\u0027] \u003d False"},{"line_number":1859,"context_line":"                ret_dict[\u0027deploy\u0027][\u0027reason\u0027] \u003d str(e)"},{"line_number":1860,"context_line":"        return ret_dict"},{"line_number":1861,"context_line":""},{"line_number":1862,"context_line":"    @METRICS.timer(\u0027ConductorManager.destroy_node\u0027)"}],"source_content_type":"text/x-python","patch_set":13,"id":"df7087c5_8cdc1c19","line":1859,"in_reply_to":"df7087c5_fb826b52","updated":"2018-03-21 10:18:55.000000000","message":"Good plan.","commit_id":"7d15cc2d1631dec0a6affb99cf3a734aeb959a23"}],"ironic/conductor/utils.py":[{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4ab8b3cf893177171652b88d0ea1261ffef6dd55","unresolved":false,"context_lines":[{"line_number":737,"context_line":"    if not node.instance_info.get(\u0027traits\u0027):"},{"line_number":738,"context_line":"        return"},{"line_number":739,"context_line":"    instance_traits \u003d node.instance_info[\u0027traits\u0027]"},{"line_number":740,"context_line":"    if not instance_traits:"},{"line_number":741,"context_line":"        return"},{"line_number":742,"context_line":""},{"line_number":743,"context_line":"    if not isinstance(instance_traits, list):"}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_e034cffd","line":740,"updated":"2018-03-09 15:57:06.000000000","message":"I think condition on L737 covers empty lists too","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"8ed3003e25e8c24d003a7e0b150d1e5b60d15b2d","unresolved":false,"context_lines":[{"line_number":737,"context_line":"    if not node.instance_info.get(\u0027traits\u0027):"},{"line_number":738,"context_line":"        return"},{"line_number":739,"context_line":"    instance_traits \u003d node.instance_info[\u0027traits\u0027]"},{"line_number":740,"context_line":"    if not instance_traits:"},{"line_number":741,"context_line":"        return"},{"line_number":742,"context_line":""},{"line_number":743,"context_line":"    if not isinstance(instance_traits, list):"}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_be458f45","line":740,"updated":"2018-03-10 08:02:08.000000000","message":"yep","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"3cc391c14376db300464c679978b6f79988690a5","unresolved":false,"context_lines":[{"line_number":737,"context_line":"    if not node.instance_info.get(\u0027traits\u0027):"},{"line_number":738,"context_line":"        return"},{"line_number":739,"context_line":"    instance_traits \u003d node.instance_info[\u0027traits\u0027]"},{"line_number":740,"context_line":"    if not instance_traits:"},{"line_number":741,"context_line":"        return"},{"line_number":742,"context_line":""},{"line_number":743,"context_line":"    if not isinstance(instance_traits, list):"}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_55ed1b23","line":740,"in_reply_to":"df7087c5_be458f45","updated":"2018-03-14 11:50:38.000000000","message":"Ah, good catch. This is a hangover from the old \u0027parse JSON or list\u0027 days.","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"8ed3003e25e8c24d003a7e0b150d1e5b60d15b2d","unresolved":false,"context_lines":[{"line_number":742,"context_line":""},{"line_number":743,"context_line":"    if not isinstance(instance_traits, list):"},{"line_number":744,"context_line":"        err \u003d (_(\"Error parsing traits from Node %(node)s instance_info \""},{"line_number":745,"context_line":"                 \"field. A list of strings is expected.\")"},{"line_number":746,"context_line":"               % {\"node\": node.uuid})"},{"line_number":747,"context_line":"        raise exception.InvalidParameterValue(err)"},{"line_number":748,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_5e76b3a6","line":745,"updated":"2018-03-10 08:02:08.000000000","message":"nit: you don\u0027t actually check that it\u0027s a list of *strings*","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"3cc391c14376db300464c679978b6f79988690a5","unresolved":false,"context_lines":[{"line_number":742,"context_line":""},{"line_number":743,"context_line":"    if not isinstance(instance_traits, list):"},{"line_number":744,"context_line":"        err \u003d (_(\"Error parsing traits from Node %(node)s instance_info \""},{"line_number":745,"context_line":"                 \"field. A list of strings is expected.\")"},{"line_number":746,"context_line":"               % {\"node\": node.uuid})"},{"line_number":747,"context_line":"        raise exception.InvalidParameterValue(err)"},{"line_number":748,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_155ec3e5","line":745,"in_reply_to":"df7087c5_5e76b3a6","updated":"2018-03-14 11:50:38.000000000","message":"Done","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"8ed3003e25e8c24d003a7e0b150d1e5b60d15b2d","unresolved":false,"context_lines":[{"line_number":747,"context_line":"        raise exception.InvalidParameterValue(err)"},{"line_number":748,"context_line":""},{"line_number":749,"context_line":"    # TODO(mgoddard): Remove the obj_attr_is_set() call in Rocky"},{"line_number":750,"context_line":"    # when all node objects will have a traits field."},{"line_number":751,"context_line":"    node_traits \u003d (node.traits.get_trait_names()"},{"line_number":752,"context_line":"                   if node.obj_attr_is_set(\u0027traits\u0027) else [])"},{"line_number":753,"context_line":"    missing \u003d set(instance_traits) - set(node_traits)"}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_7e793791","line":750,"updated":"2018-03-10 08:02:08.000000000","message":"I assume you keep it here because you plan on backporting this patch to Queens","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"3cc391c14376db300464c679978b6f79988690a5","unresolved":false,"context_lines":[{"line_number":747,"context_line":"        raise exception.InvalidParameterValue(err)"},{"line_number":748,"context_line":""},{"line_number":749,"context_line":"    # TODO(mgoddard): Remove the obj_attr_is_set() call in Rocky"},{"line_number":750,"context_line":"    # when all node objects will have a traits field."},{"line_number":751,"context_line":"    node_traits \u003d (node.traits.get_trait_names()"},{"line_number":752,"context_line":"                   if node.obj_attr_is_set(\u0027traits\u0027) else [])"},{"line_number":753,"context_line":"    missing \u003d set(instance_traits) - set(node_traits)"}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_356187aa","line":750,"in_reply_to":"df7087c5_7e793791","updated":"2018-03-14 11:50:38.000000000","message":"Correct","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"57c08fb6033468d3e67b91188c3d192ed082d0e7","unresolved":false,"context_lines":[{"line_number":750,"context_line":"    if not all(isinstance(t, six.string_types) for t in instance_traits):"},{"line_number":751,"context_line":"        invalid()"},{"line_number":752,"context_line":""},{"line_number":753,"context_line":"    # TODO(mgoddard): Remove the obj_attr_is_set() call in Rocky"},{"line_number":754,"context_line":"    # when all node objects will have a traits field."},{"line_number":755,"context_line":"    node_traits \u003d (node.traits.get_trait_names()"},{"line_number":756,"context_line":"                   if node.obj_attr_is_set(\u0027traits\u0027) else [])"}],"source_content_type":"text/x-python","patch_set":12,"id":"df7087c5_8a459c45","line":753,"updated":"2018-03-13 18:50:08.000000000","message":"can it be removed now?","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"0f914bc28d8ac6a9cdaabbb9be8586dd67da7694","unresolved":false,"context_lines":[{"line_number":750,"context_line":"    if not all(isinstance(t, six.string_types) for t in instance_traits):"},{"line_number":751,"context_line":"        invalid()"},{"line_number":752,"context_line":""},{"line_number":753,"context_line":"    # TODO(mgoddard): Remove the obj_attr_is_set() call in Rocky"},{"line_number":754,"context_line":"    # when all node objects will have a traits field."},{"line_number":755,"context_line":"    node_traits \u003d (node.traits.get_trait_names()"},{"line_number":756,"context_line":"                   if node.obj_attr_is_set(\u0027traits\u0027) else [])"}],"source_content_type":"text/x-python","patch_set":12,"id":"df7087c5_68612fa9","line":753,"in_reply_to":"df7087c5_8a459c45","updated":"2018-03-13 20:49:58.000000000","message":"ok, i see that you have a follow on patch to do this.","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"57c08fb6033468d3e67b91188c3d192ed082d0e7","unresolved":false,"context_lines":[{"line_number":757,"context_line":"    missing \u003d set(instance_traits) - set(node_traits)"},{"line_number":758,"context_line":"    if missing:"},{"line_number":759,"context_line":"        err \u003d (_(\"Cannot specify instance traits that are not also set on the \""},{"line_number":760,"context_line":"                 \"node. Node %(node)s missing traits %(traits)s\") %"},{"line_number":761,"context_line":"               {\"node\": node.uuid, \"traits\": \", \".join(missing)})"},{"line_number":762,"context_line":"        raise exception.InvalidParameterValue(err)"}],"source_content_type":"text/x-python","patch_set":12,"id":"df7087c5_0a818c4a","line":760,"updated":"2018-03-13 18:50:08.000000000","message":"nit s/missing/is missing/","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"099f0f8b6af117b8e25060eefcfba22fcda8a566","unresolved":false,"context_lines":[{"line_number":757,"context_line":"    missing \u003d set(instance_traits) - set(node_traits)"},{"line_number":758,"context_line":"    if missing:"},{"line_number":759,"context_line":"        err \u003d (_(\"Cannot specify instance traits that are not also set on the \""},{"line_number":760,"context_line":"                 \"node. Node %(node)s missing traits %(traits)s\") %"},{"line_number":761,"context_line":"               {\"node\": node.uuid, \"traits\": \", \".join(missing)})"},{"line_number":762,"context_line":"        raise exception.InvalidParameterValue(err)"}],"source_content_type":"text/x-python","patch_set":12,"id":"df7087c5_a16acb16","line":760,"in_reply_to":"df7087c5_0a818c4a","updated":"2018-03-15 15:54:59.000000000","message":"Done","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"}],"ironic/tests/unit/conductor/test_utils.py":[{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"2cb732876d8eba9659353938ced8b06a9e72b86d","unresolved":false,"context_lines":[{"line_number":1757,"context_line":"                                            traits\u003d[\u0027trait1\u0027, \u0027trait2\u0027])"},{"line_number":1758,"context_line":""},{"line_number":1759,"context_line":"    def test_validate_instance_info_traits_no_instance_traits(self):"},{"line_number":1760,"context_line":"        self.node.instance_info[\u0027traits\u0027] \u003d []"},{"line_number":1761,"context_line":"        conductor_utils.validate_instance_info_traits(self.node)"},{"line_number":1762,"context_line":""},{"line_number":1763,"context_line":"    def test_parse_instance_info_traits_invalid_type(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_0d81fc8f","line":1760,"updated":"2018-03-09 15:11:37.000000000","message":"nit: We should have a test without any trait field in instance_info.","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"3cc391c14376db300464c679978b6f79988690a5","unresolved":false,"context_lines":[{"line_number":1757,"context_line":"                                            traits\u003d[\u0027trait1\u0027, \u0027trait2\u0027])"},{"line_number":1758,"context_line":""},{"line_number":1759,"context_line":"    def test_validate_instance_info_traits_no_instance_traits(self):"},{"line_number":1760,"context_line":"        self.node.instance_info[\u0027traits\u0027] \u003d []"},{"line_number":1761,"context_line":"        conductor_utils.validate_instance_info_traits(self.node)"},{"line_number":1762,"context_line":""},{"line_number":1763,"context_line":"    def test_parse_instance_info_traits_invalid_type(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_f5b22fe6","line":1760,"in_reply_to":"df7087c5_0d81fc8f","updated":"2018-03-14 11:50:38.000000000","message":"Done","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4ab8b3cf893177171652b88d0ea1261ffef6dd55","unresolved":false,"context_lines":[{"line_number":1762,"context_line":""},{"line_number":1763,"context_line":"    def test_parse_instance_info_traits_invalid_type(self):"},{"line_number":1764,"context_line":"        self.node.instance_info[\u0027traits\u0027] \u003d \u0027not-a-list\u0027"},{"line_number":1765,"context_line":"        self.assertRaises(exception.InvalidParameterValue,"},{"line_number":1766,"context_line":"                          conductor_utils.validate_instance_info_traits,"},{"line_number":1767,"context_line":"                          self.node)"},{"line_number":1768,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_233171ed","line":1765,"updated":"2018-03-09 15:57:06.000000000","message":"we might also use assertraisesregex but that\u0027s not a big deal","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"3cc391c14376db300464c679978b6f79988690a5","unresolved":false,"context_lines":[{"line_number":1762,"context_line":""},{"line_number":1763,"context_line":"    def test_parse_instance_info_traits_invalid_type(self):"},{"line_number":1764,"context_line":"        self.node.instance_info[\u0027traits\u0027] \u003d \u0027not-a-list\u0027"},{"line_number":1765,"context_line":"        self.assertRaises(exception.InvalidParameterValue,"},{"line_number":1766,"context_line":"                          conductor_utils.validate_instance_info_traits,"},{"line_number":1767,"context_line":"                          self.node)"},{"line_number":1768,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"df7087c5_d5c7eb44","line":1765,"in_reply_to":"df7087c5_233171ed","updated":"2018-03-14 11:50:38.000000000","message":"Done","commit_id":"d9657df5513a3a1e44c3b6b62fa84e4ac9519578"}],"releasenotes/notes/validate-instance-traits-525dd3150aa6afa2.yaml":[{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"57c08fb6033468d3e67b91188c3d192ed082d0e7","unresolved":false,"context_lines":[{"line_number":2,"context_line":"fixes:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Fixes an issue where a node\u0027s ``instance_info.traits`` field could be"},{"line_number":5,"context_line":"    incorrectly formatted, or contain traits that are not traits of the node."},{"line_number":6,"context_line":"    See `bug bug/1755146 \u003chttps://bugs.launchpad.net/ironic/+bug/1755146\u003e`_ for"},{"line_number":7,"context_line":"    details."}],"source_content_type":"text/x-yaml","patch_set":12,"id":"df7087c5_aa96604b","line":5,"updated":"2018-03-13 18:50:08.000000000","message":"i wonder if we want to be a bit more specific. something like \u0027For deployment, validates that a node\u0027s traits include all the traits in its instance_info.traits field. (Just a suggestion though.)","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"099f0f8b6af117b8e25060eefcfba22fcda8a566","unresolved":false,"context_lines":[{"line_number":2,"context_line":"fixes:"},{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Fixes an issue where a node\u0027s ``instance_info.traits`` field could be"},{"line_number":5,"context_line":"    incorrectly formatted, or contain traits that are not traits of the node."},{"line_number":6,"context_line":"    See `bug bug/1755146 \u003chttps://bugs.launchpad.net/ironic/+bug/1755146\u003e`_ for"},{"line_number":7,"context_line":"    details."}],"source_content_type":"text/x-yaml","patch_set":12,"id":"df7087c5_41fc0f3d","line":5,"in_reply_to":"df7087c5_aa96604b","updated":"2018-03-15 15:54:59.000000000","message":"Added words.","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"57c08fb6033468d3e67b91188c3d192ed082d0e7","unresolved":false,"context_lines":[{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Fixes an issue where a node\u0027s ``instance_info.traits`` field could be"},{"line_number":5,"context_line":"    incorrectly formatted, or contain traits that are not traits of the node."},{"line_number":6,"context_line":"    See `bug bug/1755146 \u003chttps://bugs.launchpad.net/ironic/+bug/1755146\u003e`_ for"},{"line_number":7,"context_line":"    details."}],"source_content_type":"text/x-yaml","patch_set":12,"id":"df7087c5_0ae0acf9","line":6,"updated":"2018-03-13 18:50:08.000000000","message":"maybe remove \u0027bug/\u0027","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"},{"author":{"_account_id":14826,"name":"Mark Goddard","email":"markgoddard86@gmail.com","username":"mgoddard"},"change_message_id":"099f0f8b6af117b8e25060eefcfba22fcda8a566","unresolved":false,"context_lines":[{"line_number":3,"context_line":"  - |"},{"line_number":4,"context_line":"    Fixes an issue where a node\u0027s ``instance_info.traits`` field could be"},{"line_number":5,"context_line":"    incorrectly formatted, or contain traits that are not traits of the node."},{"line_number":6,"context_line":"    See `bug bug/1755146 \u003chttps://bugs.launchpad.net/ironic/+bug/1755146\u003e`_ for"},{"line_number":7,"context_line":"    details."}],"source_content_type":"text/x-yaml","patch_set":12,"id":"df7087c5_a1016b3a","line":6,"in_reply_to":"df7087c5_0ae0acf9","updated":"2018-03-15 15:54:59.000000000","message":"Done","commit_id":"df89ad5d085f587d86051d36333958ff479ad73e"}]}
