)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"45f70d7b4454d334f942162631265683db472ea2","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":1,"id":"03b1ab11_3e36eaf3","updated":"2025-09-30 16:01:16.000000000","message":"Will this be retrievable via API in some way? How can I validate how the rules will be applied to a given machine is what I\u0027m after.","commit_id":"b0f5fbfaf7f492a78d1934cf0ad7d0a67637bc5a"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"9591a52d3454f6e5b41221bbd64e26623f7b383a","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":1,"id":"909baf17_60c625a3","in_reply_to":"03b1ab11_3e36eaf3","updated":"2025-10-02 20:57:27.000000000","message":"This wasn\u0027t included in milestone 1 or 2 as specified. It seems like a natural next step once we get the existing spec done.","commit_id":"b0f5fbfaf7f492a78d1934cf0ad7d0a67637bc5a"},{"author":{"_account_id":14228,"name":"Clif Houck","email":"me@clifhouck.com","username":"clif_h"},"change_message_id":"6d7459ac6974eca0bbf9864d34a5c31b621c9d2a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"36da8725_484793cb","in_reply_to":"909baf17_60c625a3","updated":"2025-10-17 18:56:01.000000000","message":"Acknowledged","commit_id":"b0f5fbfaf7f492a78d1934cf0ad7d0a67637bc5a"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"9591a52d3454f6e5b41221bbd64e26623f7b383a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"b05fe33d_a44c41fb","updated":"2025-10-02 20:57:27.000000000","message":"Good start","commit_id":"bf045cf71c9036a040ed745c613d3c246cab37d0"},{"author":{"_account_id":14228,"name":"Clif Houck","email":"me@clifhouck.com","username":"clif_h"},"change_message_id":"6e88c404609f1120ec335ced657218f483d55752","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"2d06a56d_be067731","updated":"2025-10-29 00:40:31.000000000","message":"recheck","commit_id":"04f003179512ad079611e616532db6b95a92a1e7"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"e7911088caf5426433ad6543e018fdcf24ddd1e6","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"074c22d5_8c2371b6","updated":"2025-11-11 20:00:48.000000000","message":"-1 for a revision which seems to be commented out calls which I don\u0027t think should be commented out. Some further discussion and consensus seems needed, but I\u0027m sort of good with it as-is.","commit_id":"3d809afd4373dc5eb665434a5c450a62ec1a3b36"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"0244d2a4951f56e9d6d90f54e583348e4de613b9","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":10,"id":"2e34e089_d4a7f6a5","updated":"2025-11-19 06:18:25.000000000","message":"I won’t vote against but open coded validation instead of using tools is a code smell. pydantic would be the way to go here.","commit_id":"136f6a1074ac86dd3b15ca0f50a4649f461963d9"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"f1456441b3bd791eef2d270ddf2ef76dc6399c83","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":10,"id":"2149508b_809ec1ed","in_reply_to":"192ff00a_04198761","updated":"2025-11-24 22:36:55.000000000","message":"Either one. pydantic is probably easier but I don\u0027t think its in global-requirements.txt so jsonschema is probably the way to go.","commit_id":"136f6a1074ac86dd3b15ca0f50a4649f461963d9"},{"author":{"_account_id":14228,"name":"Clif Houck","email":"me@clifhouck.com","username":"clif_h"},"change_message_id":"f0303378cc77a41e5215d00ecd485bf44eabc9c4","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":10,"id":"192ff00a_04198761","in_reply_to":"2e34e089_d4a7f6a5","updated":"2025-11-24 19:20:36.000000000","message":"So you also mentioned jsonschema as a way to validate. Which do you think is better? Pydantic or jsonschema? \n\ncc @jay@jvf.cc","commit_id":"136f6a1074ac86dd3b15ca0f50a4649f461963d9"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"dcb4932cf93b6b6f045596e6a7054598b7fdef5d","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":11,"id":"256698c9_8394a3ca","updated":"2025-11-24 16:07:06.000000000","message":"Please update validation to use jsonschema in a follow up.","commit_id":"c8abaad9fa44bb60c317a70be4049ceed55a922e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"b0fa556916c5a4fa18b166130c9637e73a418df1","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"3bc836f3_bada4c08","updated":"2025-11-24 22:37:03.000000000","message":"recheck dep has merged","commit_id":"c8abaad9fa44bb60c317a70be4049ceed55a922e"},{"author":{"_account_id":14228,"name":"Clif Houck","email":"me@clifhouck.com","username":"clif_h"},"change_message_id":"f0303378cc77a41e5215d00ecd485bf44eabc9c4","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"6c01439d_b52f45f3","in_reply_to":"256698c9_8394a3ca","updated":"2025-11-24 19:20:36.000000000","message":"Acknowledged","commit_id":"c8abaad9fa44bb60c317a70be4049ceed55a922e"}],"etc/ironic/trait_based_networks.yaml":[{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"9591a52d3454f6e5b41221bbd64e26623f7b383a","unresolved":true,"context_lines":[{"line_number":1,"context_line":"CUSTOM_TRAIT_NAME:"},{"line_number":2,"context_line":"  - action: bond_ports"},{"line_number":3,"context_line":"    filter: port.vendor \u003d\u003d \u0027vendor_string\u0027"},{"line_number":4,"context_line":"    min_count: 2"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"469ed43e_5f3b242b","line":1,"updated":"2025-10-02 20:57:27.000000000","message":"maybe .yaml.sample similar to how we do ironic.conf.sample?","commit_id":"bf045cf71c9036a040ed745c613d3c246cab37d0"},{"author":{"_account_id":14228,"name":"Clif Houck","email":"me@clifhouck.com","username":"clif_h"},"change_message_id":"6d7459ac6974eca0bbf9864d34a5c31b621c9d2a","unresolved":false,"context_lines":[{"line_number":1,"context_line":"CUSTOM_TRAIT_NAME:"},{"line_number":2,"context_line":"  - action: bond_ports"},{"line_number":3,"context_line":"    filter: port.vendor \u003d\u003d \u0027vendor_string\u0027"},{"line_number":4,"context_line":"    min_count: 2"}],"source_content_type":"text/x-yaml","patch_set":2,"id":"1728063d_e37057eb","line":1,"in_reply_to":"469ed43e_5f3b242b","updated":"2025-10-17 18:56:01.000000000","message":"Done","commit_id":"bf045cf71c9036a040ed745c613d3c246cab37d0"}],"ironic/common/trait_based_networking/config_file.py":[{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"978ab2e3d24f51c02eea771423f2149b61830a0a","unresolved":true,"context_lines":[{"line_number":22,"context_line":"    def __init__(self, filename):"},{"line_number":23,"context_line":"        self._filename \u003d filename"},{"line_number":24,"context_line":"        # TODO(clif): Do this here, or defer to clients of class calling these?"},{"line_number":25,"context_line":"        self.read()"},{"line_number":26,"context_line":"        # self.validate()"},{"line_number":27,"context_line":"        # self.parse()"},{"line_number":28,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"2cb815e0_f25673e3","line":25,"updated":"2025-11-10 17:45:04.000000000","message":"Another useful question for this: do we re-read it if it\u0027s updated or do we need to restart/hup conductors? Generally config variable changes take effect on the fly (if mutable\u003dTrue).","commit_id":"3d809afd4373dc5eb665434a5c450a62ec1a3b36"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"e7911088caf5426433ad6543e018fdcf24ddd1e6","unresolved":true,"context_lines":[{"line_number":22,"context_line":"    def __init__(self, filename):"},{"line_number":23,"context_line":"        self._filename \u003d filename"},{"line_number":24,"context_line":"        # TODO(clif): Do this here, or defer to clients of class calling these?"},{"line_number":25,"context_line":"        self.read()"},{"line_number":26,"context_line":"        # self.validate()"},{"line_number":27,"context_line":"        # self.parse()"},{"line_number":28,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"6536351a_4164ce98","line":25,"in_reply_to":"2cb815e0_f25673e3","updated":"2025-11-11 20:00:48.000000000","message":"So, on the fly via a HUP signal is mutable, however HUP changes meaning with the removal of eventlet and ends up triggering internal drain/restarts of the process. Not the worst thing in the world, but I think the question ends up being:\n\nDo we cache and force hup behavior for regular changes, assuming there are regular changes... or do we open the file to read each time and revalidate.\n\nAlso, then if we find invalid content on a hup, do we just detonate the process (hint, that is harder). Dunno.\n\nBroadly speaking, I\u0027m kind of okay with just reading as needed and storing on the class when it is invoked. Sure, slows it down a little bit, but its an \"under the hood\" action.","commit_id":"3d809afd4373dc5eb665434a5c450a62ec1a3b36"},{"author":{"_account_id":14228,"name":"Clif Houck","email":"me@clifhouck.com","username":"clif_h"},"change_message_id":"af1d602051910a3f810bb7679078b16c4ab6626f","unresolved":true,"context_lines":[{"line_number":22,"context_line":"    def __init__(self, filename):"},{"line_number":23,"context_line":"        self._filename \u003d filename"},{"line_number":24,"context_line":"        # TODO(clif): Do this here, or defer to clients of class calling these?"},{"line_number":25,"context_line":"        self.read()"},{"line_number":26,"context_line":"        # self.validate()"},{"line_number":27,"context_line":"        # self.parse()"},{"line_number":28,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"e01c9fe0_ceb5d2d6","line":25,"in_reply_to":"6536351a_4164ce98","updated":"2025-11-12 23:08:26.000000000","message":"If this is hooked up in a sane way, I think re-reading the file after a change *shouldn\u0027t* necessarily be a problem. It doesn\u0027t seem like a terribly expensive thing to do computationally. Just getting the logic right, ie what to do if the changed configuration file fails to parse. Ensuring new nodes being provisioned are planning the network using the newly loaded configuration, etc. \n\nThough I may be forgetting the overall structure of Ironic which may make that more complicated.","commit_id":"3d809afd4373dc5eb665434a5c450a62ec1a3b36"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"e7911088caf5426433ad6543e018fdcf24ddd1e6","unresolved":true,"context_lines":[{"line_number":23,"context_line":"        self._filename \u003d filename"},{"line_number":24,"context_line":"        # TODO(clif): Do this here, or defer to clients of class calling these?"},{"line_number":25,"context_line":"        self.read()"},{"line_number":26,"context_line":"        # self.validate()"},{"line_number":27,"context_line":"        # self.parse()"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"    def read(self):"},{"line_number":30,"context_line":"        with open(self._filename, \u0027r\u0027) as file:"}],"source_content_type":"text/x-python","patch_set":4,"id":"cca5e381_e6d0d2fc","line":27,"range":{"start_line":26,"start_character":8,"end_line":27,"end_character":22},"updated":"2025-11-11 20:00:48.000000000","message":"Don\u0027t forget about these :)","commit_id":"3d809afd4373dc5eb665434a5c450a62ec1a3b36"},{"author":{"_account_id":14228,"name":"Clif Houck","email":"me@clifhouck.com","username":"clif_h"},"change_message_id":"af1d602051910a3f810bb7679078b16c4ab6626f","unresolved":false,"context_lines":[{"line_number":23,"context_line":"        self._filename \u003d filename"},{"line_number":24,"context_line":"        # TODO(clif): Do this here, or defer to clients of class calling these?"},{"line_number":25,"context_line":"        self.read()"},{"line_number":26,"context_line":"        # self.validate()"},{"line_number":27,"context_line":"        # self.parse()"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"    def read(self):"},{"line_number":30,"context_line":"        with open(self._filename, \u0027r\u0027) as file:"}],"source_content_type":"text/x-python","patch_set":4,"id":"bbd576b1_1d94d7a9","line":27,"range":{"start_line":26,"start_character":8,"end_line":27,"end_character":22},"in_reply_to":"cca5e381_e6d0d2fc","updated":"2025-11-12 23:08:26.000000000","message":"Done","commit_id":"3d809afd4373dc5eb665434a5c450a62ec1a3b36"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"14b2854d62c2bd7aa72ef6d46f8a03d2f21dc20a","unresolved":true,"context_lines":[{"line_number":33,"context_line":"        for key, value_list in self._contents.items():"},{"line_number":34,"context_line":"            if not isinstance(value_list, list):"},{"line_number":35,"context_line":"                reasons.append("},{"line_number":36,"context_line":"                    f\"\u0027{key}\u0027 trait does not consist of a list of actions\")"},{"line_number":37,"context_line":"                valid \u003d False"},{"line_number":38,"context_line":"                continue"},{"line_number":39,"context_line":"            for v in value_list:"}],"source_content_type":"text/x-python","patch_set":7,"id":"aeebc6bd_61b282f8","line":36,"updated":"2025-11-12 23:20:18.000000000","message":"Please i18n-ize all these strings (with _(\"string\"))","commit_id":"31c3652f1d44737241d4e3bd87dd2915e3e8437c"},{"author":{"_account_id":14228,"name":"Clif Houck","email":"me@clifhouck.com","username":"clif_h"},"change_message_id":"391c1415c4c82ca61877487532aa140a827780b7","unresolved":false,"context_lines":[{"line_number":33,"context_line":"        for key, value_list in self._contents.items():"},{"line_number":34,"context_line":"            if not isinstance(value_list, list):"},{"line_number":35,"context_line":"                reasons.append("},{"line_number":36,"context_line":"                    f\"\u0027{key}\u0027 trait does not consist of a list of actions\")"},{"line_number":37,"context_line":"                valid \u003d False"},{"line_number":38,"context_line":"                continue"},{"line_number":39,"context_line":"            for v in value_list:"}],"source_content_type":"text/x-python","patch_set":7,"id":"3300ee0d_2e14295b","line":36,"in_reply_to":"aeebc6bd_61b282f8","updated":"2025-11-13 17:57:31.000000000","message":"Done","commit_id":"31c3652f1d44737241d4e3bd87dd2915e3e8437c"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"0244d2a4951f56e9d6d90f54e583348e4de613b9","unresolved":true,"context_lines":[{"line_number":27,"context_line":"        with open(self._filename, \u0027r\u0027) as file:"},{"line_number":28,"context_line":"            self._contents \u003d yaml.safe_load(file)"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"    def validate(self):"},{"line_number":31,"context_line":"        \"\"\"Check that contents conform to TBN expectations.\"\"\""},{"line_number":32,"context_line":"        reasons \u003d []"},{"line_number":33,"context_line":"        valid \u003d True"}],"source_content_type":"text/x-python","patch_set":10,"id":"ea36f47b_e9596957","line":30,"updated":"2025-11-19 06:18:25.000000000","message":"most of this function could be expressed today with a jsonschema check instead of open coded checks.","commit_id":"136f6a1074ac86dd3b15ca0f50a4649f461963d9"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"a138cfd9198448a3ccad36d9b4ed593492e94051","unresolved":true,"context_lines":[{"line_number":27,"context_line":"        with open(self._filename, \u0027r\u0027) as file:"},{"line_number":28,"context_line":"            self._contents \u003d yaml.safe_load(file)"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"    def validate(self):"},{"line_number":31,"context_line":"        \"\"\"Check that contents conform to TBN expectations.\"\"\""},{"line_number":32,"context_line":"        reasons \u003d []"},{"line_number":33,"context_line":"        valid \u003d True"}],"source_content_type":"text/x-python","patch_set":10,"id":"47148558_52fe8a8b","line":30,"in_reply_to":"08aa09bb_010dd638","updated":"2025-11-21 23:02:56.000000000","message":"Yep.","commit_id":"136f6a1074ac86dd3b15ca0f50a4649f461963d9"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"9df0cef5e41e51c0e698b7147daed9427ed19713","unresolved":true,"context_lines":[{"line_number":27,"context_line":"        with open(self._filename, \u0027r\u0027) as file:"},{"line_number":28,"context_line":"            self._contents \u003d yaml.safe_load(file)"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"    def validate(self):"},{"line_number":31,"context_line":"        \"\"\"Check that contents conform to TBN expectations.\"\"\""},{"line_number":32,"context_line":"        reasons \u003d []"},{"line_number":33,"context_line":"        valid \u003d True"}],"source_content_type":"text/x-python","patch_set":10,"id":"08aa09bb_010dd638","line":30,"in_reply_to":"ea36f47b_e9596957","updated":"2025-11-19 15:18:59.000000000","message":"Does jsonschema work with yaml?","commit_id":"136f6a1074ac86dd3b15ca0f50a4649f461963d9"}]}
