)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"f78b4ae9b3e82ef1fb695a2f631e484936e40816","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"15755e7b_9d505b6b","updated":"2025-11-11 19:15:05.000000000","message":"+1 for now, nothing is really standing out as problematic or needing revision on this change. I expect the prior change to have a revision first which will force this one to need to be rebased at some point, at which point I can just +2 it.","commit_id":"96de4ae57993c62ffd763f7ea339161c8e2acf25"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"2d7bc15a1e472947d9632ac59da1720915bf14a8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"7f5c6da5_bbb94526","updated":"2025-11-14 20:31:27.000000000","message":"Comments addressed.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"00d73fb1ab86aecddb73a069ede9fbd26470186e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"f153f0fd_bf3d5735","updated":"2025-11-21 16:51:26.000000000","message":"First pass, nothing really blocking except for the exception handling.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"6ed99bb2fd58b2cf1a5ca4451c5607322b698540","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"18d62683_35e784fd","updated":"2025-11-22 00:14:12.000000000","message":"There\u0027s some error paths on writing files that needs to be handled. Also don\u0027t manually code writing out the file format and then use ConfigParser to read the file format. Use the same module for in and out.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"029b5f9f_b5d38361","in_reply_to":"18d62683_35e784fd","updated":"2025-11-27 16:41:44.000000000","message":"Done","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"6fab05a2_a286d668","updated":"2025-12-02 13:12:36.000000000","message":"A bunch of relatively minor comments inline, enough to warrant a respin, I think.","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"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":"2277d2365f7da0ed95a0ffb3825983c70659cedc","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":3,"id":"68325196_8f4c281f","updated":"2025-12-01 23:16:13.000000000","message":"Some feedback about using abc for your baseclass, but it\u0027s not blocking.","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"24ab94fa_d67853e6","updated":"2025-11-27 16:41:44.000000000","message":"comments addressed, PTAL","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"0f7534ee6e3316addea18dd4e8d9659e9c5519bb","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"7fd8a843_6d3339e7","updated":"2025-12-01 12:28:54.000000000","message":"recheck","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"88421712_05196549","in_reply_to":"68325196_8f4c281f","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6d0f05cf3c6704fe6d2dec7c09dfec854110f5f6","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"aeac704e_797d72ee","updated":"2025-12-03 13:45:12.000000000","message":"A couple more nits left, but these do not warrant a new revision, just address them at some point please.","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"},{"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":"54cabe190fc8c6afff1e0a77b2098ff2bf520ff8","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":4,"id":"0fc6de0f_fd26c7ae","updated":"2025-12-03 15:17:11.000000000","message":"Approved under the assumption you\u0027ll follow-up the issues indicated. Thank you!","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"5060abaf_b879f86e","updated":"2025-12-03 13:08:29.000000000","message":"comments addressed, PTAL","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"93a20426e33b08881f8e6cc08bf4250256825e50","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"fe53068f_4dd71fd4","in_reply_to":"aeac704e_797d72ee","updated":"2025-12-03 14:45:18.000000000","message":"Ok, will add another commit to the top of the chain to collect these nits.","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"}],"ironic/networking/driver_adapter.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"00d73fb1ab86aecddb73a069ede9fbd26470186e","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":2,"id":"833ad346_24145933","updated":"2025-11-21 16:51:26.000000000","message":"nit: you have several files prefixed with `driver_` here, so I wonder if it\u0027s time for `ironic.networking.drivers.*`. Or maybe `ironic.networking.switch_drivers.*` to be more specific.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"fc04a8d9_77b89c38","in_reply_to":"833ad346_24145933","updated":"2025-11-27 16:41:44.000000000","message":"Done","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"00d73fb1ab86aecddb73a069ede9fbd26470186e","unresolved":true,"context_lines":[{"line_number":40,"context_line":"    def __init__(self):"},{"line_number":41,"context_line":"        \"\"\"Initialize the driver adapter.\"\"\""},{"line_number":42,"context_line":"        self.driver_translators \u003d {}"},{"line_number":43,"context_line":"        self._register_translators()"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    def _register_translators(self):"},{"line_number":46,"context_line":"        \"\"\"Register available driver translators.\"\"\""}],"source_content_type":"text/x-python","patch_set":2,"id":"3e72e357_77c07692","line":43,"updated":"2025-11-21 16:51:26.000000000","message":"This call does nothing except for logging empty drivers","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[{"line_number":40,"context_line":"    def __init__(self):"},{"line_number":41,"context_line":"        \"\"\"Initialize the driver adapter.\"\"\""},{"line_number":42,"context_line":"        self.driver_translators \u003d {}"},{"line_number":43,"context_line":"        self._register_translators()"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    def _register_translators(self):"},{"line_number":46,"context_line":"        \"\"\"Register available driver translators.\"\"\""}],"source_content_type":"text/x-python","patch_set":2,"id":"21a58474_6b3fe1cb","line":43,"in_reply_to":"3e72e357_77c07692","updated":"2025-11-27 16:41:44.000000000","message":"Yes, it became a bit tricky to split the patches so left this empty here and added an implementation in a subsequent patch in this series.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"6ed99bb2fd58b2cf1a5ca4451c5607322b698540","unresolved":true,"context_lines":[{"line_number":172,"context_line":"                    \"configurations\\n\""},{"line_number":173,"context_line":"                )"},{"line_number":174,"context_line":"                f.write("},{"line_number":175,"context_line":"                    \"# Generated from user defined switch \" \"configuration\\n\\n\""},{"line_number":176,"context_line":"                )"},{"line_number":177,"context_line":""},{"line_number":178,"context_line":"                for section_name, section_config in switch_configs.items():"}],"source_content_type":"text/x-python","patch_set":2,"id":"b19b00b3_c57b46de","line":175,"updated":"2025-11-22 00:14:12.000000000","message":"```suggestion\n                    \"# Generated from user defined switch configuration\\n\\n\"\n```","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                    \"configurations\\n\""},{"line_number":173,"context_line":"                )"},{"line_number":174,"context_line":"                f.write("},{"line_number":175,"context_line":"                    \"# Generated from user defined switch \" \"configuration\\n\\n\""},{"line_number":176,"context_line":"                )"},{"line_number":177,"context_line":""},{"line_number":178,"context_line":"                for section_name, section_config in switch_configs.items():"}],"source_content_type":"text/x-python","patch_set":2,"id":"b862c23e_b0b9c8f2","line":175,"in_reply_to":"b19b00b3_c57b46de","updated":"2025-11-27 16:41:44.000000000","message":"Done","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"6ed99bb2fd58b2cf1a5ca4451c5607322b698540","unresolved":true,"context_lines":[{"line_number":179,"context_line":"                    f.write(f\"[{section_name}]\\n\")"},{"line_number":180,"context_line":"                    for key, value in section_config.items():"},{"line_number":181,"context_line":"                        f.write(f\"{key} \u003d {value}\\n\")"},{"line_number":182,"context_line":"                    f.write(\"\\n\")"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"            LOG.info(\"Generated driver config file: %s\", output_file)"},{"line_number":185,"context_line":"            return output_file"}],"source_content_type":"text/x-python","patch_set":2,"id":"53a53d58_4889a6c2","line":182,"updated":"2025-11-22 00:14:12.000000000","message":"If we\u0027re using ini format I\u0027m a big -1 on manually implementing this. Use ConfigParser.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[{"line_number":179,"context_line":"                    f.write(f\"[{section_name}]\\n\")"},{"line_number":180,"context_line":"                    for key, value in section_config.items():"},{"line_number":181,"context_line":"                        f.write(f\"{key} \u003d {value}\\n\")"},{"line_number":182,"context_line":"                    f.write(\"\\n\")"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"            LOG.info(\"Generated driver config file: %s\", output_file)"},{"line_number":185,"context_line":"            return output_file"}],"source_content_type":"text/x-python","patch_set":2,"id":"3a565213_f927defe","line":182,"in_reply_to":"53a53d58_4889a6c2","updated":"2025-11-27 16:41:44.000000000","message":"Done","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"6ed99bb2fd58b2cf1a5ca4451c5607322b698540","unresolved":true,"context_lines":[{"line_number":185,"context_line":"            return output_file"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"        except Exception as e:"},{"line_number":188,"context_line":"            LOG.error(\"Failed to generate config file: %s\", e)"},{"line_number":189,"context_line":"            return None"},{"line_number":190,"context_line":""},{"line_number":191,"context_line":"    def reload_configuration(self, output_file):"}],"source_content_type":"text/x-python","patch_set":2,"id":"44ad3002_941d5623","line":188,"updated":"2025-11-22 00:14:12.000000000","message":"What do we do with a half written file on exception? There\u0027s no cleanup. Write the file to a temp file and then move it over.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[{"line_number":185,"context_line":"            return output_file"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"        except Exception as e:"},{"line_number":188,"context_line":"            LOG.error(\"Failed to generate config file: %s\", e)"},{"line_number":189,"context_line":"            return None"},{"line_number":190,"context_line":""},{"line_number":191,"context_line":"    def reload_configuration(self, output_file):"}],"source_content_type":"text/x-python","patch_set":2,"id":"b69a576e_751ccbb5","line":188,"in_reply_to":"44ad3002_941d5623","updated":"2025-11-27 16:41:44.000000000","message":"Done","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"}],"ironic/networking/switch_config.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":52,"context_line":"        return True"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    # Empty list means no VLANs are allowed"},{"line_number":55,"context_line":"    if isinstance(allowed_spec, list) and len(allowed_spec) \u003d\u003d 0:"},{"line_number":56,"context_line":"        raise exception.InvalidParameterValue("},{"line_number":57,"context_line":"            _(\u0027VLAN %(vlan)s is not allowed: no VLANs are permitted by \u0027"},{"line_number":58,"context_line":"              \u0027configuration\u0027) % {\u0027vlan\u0027: vlan_id})"}],"source_content_type":"text/x-python","patch_set":3,"id":"81ab70b1_82d7882a","line":55,"updated":"2025-12-02 13:12:36.000000000","message":"nit: `not allowed_spec` is slightly preferred to checking `len`","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":52,"context_line":"        return True"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    # Empty list means no VLANs are allowed"},{"line_number":55,"context_line":"    if isinstance(allowed_spec, list) and len(allowed_spec) \u003d\u003d 0:"},{"line_number":56,"context_line":"        raise exception.InvalidParameterValue("},{"line_number":57,"context_line":"            _(\u0027VLAN %(vlan)s is not allowed: no VLANs are permitted by \u0027"},{"line_number":58,"context_line":"              \u0027configuration\u0027) % {\u0027vlan\u0027: vlan_id})"}],"source_content_type":"text/x-python","patch_set":3,"id":"ade92472_30589e67","line":55,"in_reply_to":"81ab70b1_82d7882a","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":66,"context_line":"                {\u0027vlan\u0027: vlan_id})"},{"line_number":67,"context_line":"    except exception.InvalidParameterValue:"},{"line_number":68,"context_line":"        # Re-raise validation errors from parse_vlan_ranges"},{"line_number":69,"context_line":"        raise"},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    return True"},{"line_number":72,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"a5a4d33b_074b3753","line":69,"updated":"2025-12-02 13:12:36.000000000","message":"This try..except block does nothing and can be removed","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":66,"context_line":"                {\u0027vlan\u0027: vlan_id})"},{"line_number":67,"context_line":"    except exception.InvalidParameterValue:"},{"line_number":68,"context_line":"        # Re-raise validation errors from parse_vlan_ranges"},{"line_number":69,"context_line":"        raise"},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    return True"},{"line_number":72,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"82d61d97_daaeade6","line":69,"in_reply_to":"a5a4d33b_074b3753","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":90,"context_line":"    switch_info \u003d switch_driver.get_switch_info(switch_id)"},{"line_number":91,"context_line":"    if switch_info:"},{"line_number":92,"context_line":"        # Process switch-specific allowed_vlans"},{"line_number":93,"context_line":"        if \"allowed_vlans\" in switch_info:"},{"line_number":94,"context_line":"            switch_allowed \u003d switch_info[\"allowed_vlans\"]"},{"line_number":95,"context_line":"            config[\"allowed_vlans\"] \u003d ("},{"line_number":96,"context_line":"                utils.parse_vlan_ranges(switch_allowed))"}],"source_content_type":"text/x-python","patch_set":3,"id":"cff2663b_f4f0019f","line":93,"updated":"2025-12-02 13:12:36.000000000","message":"nit: join two \"if\" statements","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":90,"context_line":"    switch_info \u003d switch_driver.get_switch_info(switch_id)"},{"line_number":91,"context_line":"    if switch_info:"},{"line_number":92,"context_line":"        # Process switch-specific allowed_vlans"},{"line_number":93,"context_line":"        if \"allowed_vlans\" in switch_info:"},{"line_number":94,"context_line":"            switch_allowed \u003d switch_info[\"allowed_vlans\"]"},{"line_number":95,"context_line":"            config[\"allowed_vlans\"] \u003d ("},{"line_number":96,"context_line":"                utils.parse_vlan_ranges(switch_allowed))"}],"source_content_type":"text/x-python","patch_set":3,"id":"7e4dc006_a3401443","line":93,"in_reply_to":"cff2663b_f4f0019f","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"}],"ironic/networking/switch_drivers/driver_adapter.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":138,"context_line":"                    driver_type,"},{"line_number":139,"context_line":"                )"},{"line_number":140,"context_line":"                translation \u003d self.driver_translators["},{"line_number":141,"context_line":"                    driver_type"},{"line_number":142,"context_line":"                ].translate_config(switch_name, config)"},{"line_number":143,"context_line":"                if translation:"},{"line_number":144,"context_line":"                    translations.update(translation)"}],"source_content_type":"text/x-python","patch_set":3,"id":"35276852_6a5b2ebf","line":141,"updated":"2025-12-02 13:12:36.000000000","message":"translations are empty by default, so you\u0027ll get a KeyError here which you need to handle (better than on line 151). Maybe default to no translation (translation\u003d\u003dconfig)?","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                    driver_type,"},{"line_number":139,"context_line":"                )"},{"line_number":140,"context_line":"                translation \u003d self.driver_translators["},{"line_number":141,"context_line":"                    driver_type"},{"line_number":142,"context_line":"                ].translate_config(switch_name, config)"},{"line_number":143,"context_line":"                if translation:"},{"line_number":144,"context_line":"                    translations.update(translation)"}],"source_content_type":"text/x-python","patch_set":3,"id":"80fd1dbc_ea817c1d","line":141,"in_reply_to":"35276852_6a5b2ebf","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":149,"context_line":""},{"line_number":150,"context_line":"            return len(translations)"},{"line_number":151,"context_line":"        except Exception as e:"},{"line_number":152,"context_line":"            LOG.error(\"Failed to preprocess switch configuration: %s\", e)"},{"line_number":153,"context_line":"            raise exception.NetworkError("},{"line_number":154,"context_line":"                _(\"Configuration preprocessing failed: %s\") % e"},{"line_number":155,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":3,"id":"47434ef1_301a315b","line":152,"updated":"2025-12-02 13:12:36.000000000","message":"Some Python errors (like KeyError or AttributeError) have very non-descriptive messages. At the very least, let\u0027s add exc_info\u003dTrue to output a traceback with the logs.","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":149,"context_line":""},{"line_number":150,"context_line":"            return len(translations)"},{"line_number":151,"context_line":"        except Exception as e:"},{"line_number":152,"context_line":"            LOG.error(\"Failed to preprocess switch configuration: %s\", e)"},{"line_number":153,"context_line":"            raise exception.NetworkError("},{"line_number":154,"context_line":"                _(\"Configuration preprocessing failed: %s\") % e"},{"line_number":155,"context_line":"            )"}],"source_content_type":"text/x-python","patch_set":3,"id":"132bab68_8b042730","line":152,"in_reply_to":"47434ef1_301a315b","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":171,"context_line":""},{"line_number":172,"context_line":"        :returns: Dictionary of section_name -\u003e config_dict"},{"line_number":173,"context_line":"        \"\"\""},{"line_number":174,"context_line":"        import re"},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"        switch_sections \u003d {}"},{"line_number":177,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"ac3c37e5_fef8692c","line":174,"updated":"2025-12-02 13:12:36.000000000","message":"Imports on top level please","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":171,"context_line":""},{"line_number":172,"context_line":"        :returns: Dictionary of section_name -\u003e config_dict"},{"line_number":173,"context_line":"        \"\"\""},{"line_number":174,"context_line":"        import re"},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"        switch_sections \u003d {}"},{"line_number":177,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"221604d9_21c5fb30","line":174,"in_reply_to":"ac3c37e5_fef8692c","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":187,"context_line":"            return {}"},{"line_number":188,"context_line":""},{"line_number":189,"context_line":"        for section_name, section_config in sections.items():"},{"line_number":190,"context_line":"            match \u003d section_pattern.match(section_name)"},{"line_number":191,"context_line":"            if match:"},{"line_number":192,"context_line":"                switch_name \u003d match.group(1)"},{"line_number":193,"context_line":"                # Get all key/value pairs in this section"}],"source_content_type":"text/x-python","patch_set":3,"id":"628ca27a_9ca9f8d1","line":190,"updated":"2025-12-02 13:12:36.000000000","message":"`section_name.startswith(\"switch:\")`","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":187,"context_line":"            return {}"},{"line_number":188,"context_line":""},{"line_number":189,"context_line":"        for section_name, section_config in sections.items():"},{"line_number":190,"context_line":"            match \u003d section_pattern.match(section_name)"},{"line_number":191,"context_line":"            if match:"},{"line_number":192,"context_line":"                switch_name \u003d match.group(1)"},{"line_number":193,"context_line":"                # Get all key/value pairs in this section"}],"source_content_type":"text/x-python","patch_set":3,"id":"cfb839c9_b90db8df","line":190,"in_reply_to":"628ca27a_9ca9f8d1","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":189,"context_line":"        for section_name, section_config in sections.items():"},{"line_number":190,"context_line":"            match \u003d section_pattern.match(section_name)"},{"line_number":191,"context_line":"            if match:"},{"line_number":192,"context_line":"                switch_name \u003d match.group(1)"},{"line_number":193,"context_line":"                # Get all key/value pairs in this section"},{"line_number":194,"context_line":"                switch_sections[switch_name] \u003d {"},{"line_number":195,"context_line":"                    k: v[0] for k, v in section_config.items()"}],"source_content_type":"text/x-python","patch_set":3,"id":"d749a719_396538d9","line":192,"updated":"2025-12-02 13:12:36.000000000","message":"`section_name[7:]`","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":189,"context_line":"        for section_name, section_config in sections.items():"},{"line_number":190,"context_line":"            match \u003d section_pattern.match(section_name)"},{"line_number":191,"context_line":"            if match:"},{"line_number":192,"context_line":"                switch_name \u003d match.group(1)"},{"line_number":193,"context_line":"                # Get all key/value pairs in this section"},{"line_number":194,"context_line":"                switch_sections[switch_name] \u003d {"},{"line_number":195,"context_line":"                    k: v[0] for k, v in section_config.items()"}],"source_content_type":"text/x-python","patch_set":3,"id":"5903868d_23bf4efe","line":192,"in_reply_to":"d749a719_396538d9","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":203,"context_line":""},{"line_number":204,"context_line":"        :param output_file: Path to the output file"},{"line_number":205,"context_line":"        :param switch_configs: Dictionary of switch_name -\u003e config_dict"},{"line_number":206,"context_line":"        :returns: Path to generated config file or None if failed"},{"line_number":207,"context_line":"        \"\"\""},{"line_number":208,"context_line":"        # Create temp file in same directory as output file for atomic rename"},{"line_number":209,"context_line":"        output_dir \u003d os.path.dirname(output_file)"}],"source_content_type":"text/x-python","patch_set":3,"id":"9dadb1fc_cab9578a","line":206,"updated":"2025-12-02 13:12:36.000000000","message":"nit: the return value seems unused","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":203,"context_line":""},{"line_number":204,"context_line":"        :param output_file: Path to the output file"},{"line_number":205,"context_line":"        :param switch_configs: Dictionary of switch_name -\u003e config_dict"},{"line_number":206,"context_line":"        :returns: Path to generated config file or None if failed"},{"line_number":207,"context_line":"        \"\"\""},{"line_number":208,"context_line":"        # Create temp file in same directory as output file for atomic rename"},{"line_number":209,"context_line":"        output_dir \u003d os.path.dirname(output_file)"}],"source_content_type":"text/x-python","patch_set":3,"id":"f8c67be2_2c8fd172","line":206,"in_reply_to":"9dadb1fc_cab9578a","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":256,"context_line":"                except OSError as cleanup_error:"},{"line_number":257,"context_line":"                    LOG.debug(\"Failed to remove temp file %s: %s\","},{"line_number":258,"context_line":"                              temp_path, cleanup_error)"},{"line_number":259,"context_line":"            return None"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"    def reload_configuration(self, output_file):"},{"line_number":262,"context_line":"        \"\"\"Reload and regenerate switch configuration files."}],"source_content_type":"text/x-python","patch_set":3,"id":"2b08c6de_fb2d318a","line":259,"updated":"2025-12-02 13:12:36.000000000","message":"I think this should re-raise, otherwise ironic-networking will be running with invalid configuration","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":256,"context_line":"                except OSError as cleanup_error:"},{"line_number":257,"context_line":"                    LOG.debug(\"Failed to remove temp file %s: %s\","},{"line_number":258,"context_line":"                              temp_path, cleanup_error)"},{"line_number":259,"context_line":"            return None"},{"line_number":260,"context_line":""},{"line_number":261,"context_line":"    def reload_configuration(self, output_file):"},{"line_number":262,"context_line":"        \"\"\"Reload and regenerate switch configuration files."}],"source_content_type":"text/x-python","patch_set":3,"id":"41b9e8a6_62787c83","line":259,"in_reply_to":"2b08c6de_fb2d318a","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6d0f05cf3c6704fe6d2dec7c09dfec854110f5f6","unresolved":true,"context_lines":[{"line_number":257,"context_line":"                    LOG.debug(\"Failed to remove temp file %s: %s\","},{"line_number":258,"context_line":"                              temp_path, cleanup_error)"},{"line_number":259,"context_line":"            # Re-raise the original exception"},{"line_number":260,"context_line":"            raise e"},{"line_number":261,"context_line":""},{"line_number":262,"context_line":"    def reload_configuration(self, output_file):"},{"line_number":263,"context_line":"        \"\"\"Reload and regenerate switch configuration files."}],"source_content_type":"text/x-python","patch_set":4,"id":"3abae05f_37daf0ff","line":260,"updated":"2025-12-03 13:45:12.000000000","message":"nit: this approach loses traceback, better use the pattern:\n\n```\nwith excutils.save_and_reraise_exception():\n   # everything else\n```","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"},{"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":"54cabe190fc8c6afff1e0a77b2098ff2bf520ff8","unresolved":true,"context_lines":[{"line_number":257,"context_line":"                    LOG.debug(\"Failed to remove temp file %s: %s\","},{"line_number":258,"context_line":"                              temp_path, cleanup_error)"},{"line_number":259,"context_line":"            # Re-raise the original exception"},{"line_number":260,"context_line":"            raise e"},{"line_number":261,"context_line":""},{"line_number":262,"context_line":"    def reload_configuration(self, output_file):"},{"line_number":263,"context_line":"        \"\"\"Reload and regenerate switch configuration files."}],"source_content_type":"text/x-python","patch_set":4,"id":"1e6e3f01_4115a8e7","line":260,"in_reply_to":"3abae05f_37daf0ff","updated":"2025-12-03 15:17:11.000000000","message":"Please make sure you follow up with this fix.","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"}],"ironic/networking/switch_drivers/driver_factory.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":59,"context_line":"        )"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"        # Check for duplicated driver entries and warn about them"},{"line_number":62,"context_line":"        import collections"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"        counter \u003d collections.Counter(enabled_drivers).items()"},{"line_number":65,"context_line":"        duplicated_drivers \u003d []"}],"source_content_type":"text/x-python","patch_set":3,"id":"e6182ce8_ea442817","line":62,"updated":"2025-12-02 13:12:36.000000000","message":"Imports at the top please","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":59,"context_line":"        )"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"        # Check for duplicated driver entries and warn about them"},{"line_number":62,"context_line":"        import collections"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"        counter \u003d collections.Counter(enabled_drivers).items()"},{"line_number":65,"context_line":"        duplicated_drivers \u003d []"}],"source_content_type":"text/x-python","patch_set":3,"id":"7bebdbea_e2cd6d61","line":62,"in_reply_to":"e6182ce8_ea442817","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":67,"context_line":""},{"line_number":68,"context_line":"        for item, cnt in counter:"},{"line_number":69,"context_line":"            if not item:"},{"line_number":70,"context_line":"                LOG.warning("},{"line_number":71,"context_line":"                    \u0027An empty switch driver was specified in the \"%s\" \u0027"},{"line_number":72,"context_line":"                    \"configuration option and will be ignored. Please \""},{"line_number":73,"context_line":"                    \"fix your ironic.conf file to avoid this warning.\","}],"source_content_type":"text/x-python","patch_set":3,"id":"898ca383_cf1e6a63","line":70,"updated":"2025-12-02 13:12:36.000000000","message":"Shouldn\u0027t this be fatal? We don\u0027t tend to allow invalid configurations.","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":67,"context_line":""},{"line_number":68,"context_line":"        for item, cnt in counter:"},{"line_number":69,"context_line":"            if not item:"},{"line_number":70,"context_line":"                LOG.warning("},{"line_number":71,"context_line":"                    \u0027An empty switch driver was specified in the \"%s\" \u0027"},{"line_number":72,"context_line":"                    \"configuration option and will be ignored. Please \""},{"line_number":73,"context_line":"                    \"fix your ironic.conf file to avoid this warning.\","}],"source_content_type":"text/x-python","patch_set":3,"id":"80176bfc_ce00cb91","line":70,"in_reply_to":"898ca383_cf1e6a63","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":79,"context_line":"            cls._enabled_driver_list.append(item)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if duplicated_drivers:"},{"line_number":82,"context_line":"            LOG.warning("},{"line_number":83,"context_line":"                \u0027The switch driver(s) \"%s\" is/are duplicated in the \u0027"},{"line_number":84,"context_line":"                \"list of enabled drivers. Please check your \""},{"line_number":85,"context_line":"                \"configuration file.\","}],"source_content_type":"text/x-python","patch_set":3,"id":"2db81531_8bb6b54a","line":82,"updated":"2025-12-02 13:12:36.000000000","message":"Same","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":79,"context_line":"            cls._enabled_driver_list.append(item)"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"        if duplicated_drivers:"},{"line_number":82,"context_line":"            LOG.warning("},{"line_number":83,"context_line":"                \u0027The switch driver(s) \"%s\" is/are duplicated in the \u0027"},{"line_number":84,"context_line":"                \"list of enabled drivers. Please check your \""},{"line_number":85,"context_line":"                \"configuration file.\","}],"source_content_type":"text/x-python","patch_set":3,"id":"6d16281b_c9e859bb","line":82,"in_reply_to":"2db81531_8bb6b54a","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6d0f05cf3c6704fe6d2dec7c09dfec854110f5f6","unresolved":true,"context_lines":[{"line_number":70,"context_line":"            if not item:"},{"line_number":71,"context_line":"                raise exception.ConfigInvalid("},{"line_number":72,"context_line":"                    error_msg\u003d("},{"line_number":73,"context_line":"                        \u0027An empty switch driver was specified in the \"%s\" \u0027"},{"line_number":74,"context_line":"                        \"configuration option. Please fix your ironic.conf \""},{"line_number":75,"context_line":"                        \"file.\" % cls._enabled_driver_list_config_option"},{"line_number":76,"context_line":"                    )"}],"source_content_type":"text/x-python","patch_set":4,"id":"bdf546dd_597d0ccb","line":73,"updated":"2025-12-03 13:45:12.000000000","message":"nit: missing _() around user-visible string for translation","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"},{"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":"54cabe190fc8c6afff1e0a77b2098ff2bf520ff8","unresolved":true,"context_lines":[{"line_number":70,"context_line":"            if not item:"},{"line_number":71,"context_line":"                raise exception.ConfigInvalid("},{"line_number":72,"context_line":"                    error_msg\u003d("},{"line_number":73,"context_line":"                        \u0027An empty switch driver was specified in the \"%s\" \u0027"},{"line_number":74,"context_line":"                        \"configuration option. Please fix your ironic.conf \""},{"line_number":75,"context_line":"                        \"file.\" % cls._enabled_driver_list_config_option"},{"line_number":76,"context_line":"                    )"}],"source_content_type":"text/x-python","patch_set":4,"id":"0efb9194_ce9a7af1","line":73,"in_reply_to":"bdf546dd_597d0ccb","updated":"2025-12-03 15:17:11.000000000","message":"Please fix this in a follow-up.","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6d0f05cf3c6704fe6d2dec7c09dfec854110f5f6","unresolved":true,"context_lines":[{"line_number":82,"context_line":"        if duplicated_drivers:"},{"line_number":83,"context_line":"            raise exception.ConfigInvalid("},{"line_number":84,"context_line":"                error_msg\u003d("},{"line_number":85,"context_line":"                    \u0027The switch driver(s) \"%s\" is/are duplicated in the \u0027"},{"line_number":86,"context_line":"                    \"list of enabled drivers. Please check your \""},{"line_number":87,"context_line":"                    \"configuration file.\" % \", \".join(duplicated_drivers)"},{"line_number":88,"context_line":"                )"}],"source_content_type":"text/x-python","patch_set":4,"id":"f92ee696_b42c3762","line":85,"updated":"2025-12-03 13:45:12.000000000","message":"ditto","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"},{"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":"54cabe190fc8c6afff1e0a77b2098ff2bf520ff8","unresolved":true,"context_lines":[{"line_number":82,"context_line":"        if duplicated_drivers:"},{"line_number":83,"context_line":"            raise exception.ConfigInvalid("},{"line_number":84,"context_line":"                error_msg\u003d("},{"line_number":85,"context_line":"                    \u0027The switch driver(s) \"%s\" is/are duplicated in the \u0027"},{"line_number":86,"context_line":"                    \"list of enabled drivers. Please check your \""},{"line_number":87,"context_line":"                    \"configuration file.\" % \", \".join(duplicated_drivers)"},{"line_number":88,"context_line":"                )"}],"source_content_type":"text/x-python","patch_set":4,"id":"6e77670f_10a9a86a","line":85,"in_reply_to":"f92ee696_b42c3762","updated":"2025-12-03 15:17:11.000000000","message":"Please fix this in a follow-up.","commit_id":"05b9dc22c7681cf8b9e30dd5eb0c0505a10ed7c5"}],"ironic/networking/switch_drivers/driver_translators.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":"2277d2365f7da0ed95a0ffb3825983c70659cedc","unresolved":true,"context_lines":[{"line_number":67,"context_line":"        :param switch_name: Name of the switch"},{"line_number":68,"context_line":"        :returns: Section name string"},{"line_number":69,"context_line":"        \"\"\""},{"line_number":70,"context_line":"        raise NotImplementedError("},{"line_number":71,"context_line":"            \"Subclasses must implement _get_section_name\""},{"line_number":72,"context_line":"        )"},{"line_number":73,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"1f21fd62_0cc315b8","line":70,"updated":"2025-12-01 23:16:13.000000000","message":"If you use https://docs.python.org/3/library/abc.html you can mark this as a metaclass, and it will enforce that some of these are implemented for you.","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[{"line_number":67,"context_line":"        :param switch_name: Name of the switch"},{"line_number":68,"context_line":"        :returns: Section name string"},{"line_number":69,"context_line":"        \"\"\""},{"line_number":70,"context_line":"        raise NotImplementedError("},{"line_number":71,"context_line":"            \"Subclasses must implement _get_section_name\""},{"line_number":72,"context_line":"        )"},{"line_number":73,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"67fdbb82_8c1a5507","line":70,"in_reply_to":"1f21fd62_0cc315b8","updated":"2025-12-02 13:12:36.000000000","message":"+1","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[{"line_number":67,"context_line":"        :param switch_name: Name of the switch"},{"line_number":68,"context_line":"        :returns: Section name string"},{"line_number":69,"context_line":"        \"\"\""},{"line_number":70,"context_line":"        raise NotImplementedError("},{"line_number":71,"context_line":"            \"Subclasses must implement _get_section_name\""},{"line_number":72,"context_line":"        )"},{"line_number":73,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"8a715f68_2b28a1c1","line":70,"in_reply_to":"67fdbb82_8c1a5507","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"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":"54cabe190fc8c6afff1e0a77b2098ff2bf520ff8","unresolved":true,"context_lines":[{"line_number":67,"context_line":"        :param switch_name: Name of the switch"},{"line_number":68,"context_line":"        :returns: Section name string"},{"line_number":69,"context_line":"        \"\"\""},{"line_number":70,"context_line":"        raise NotImplementedError("},{"line_number":71,"context_line":"            \"Subclasses must implement _get_section_name\""},{"line_number":72,"context_line":"        )"},{"line_number":73,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"d96a8ed8_1651887f","line":70,"in_reply_to":"8a715f68_2b28a1c1","updated":"2025-12-03 15:17:11.000000000","message":"You get the error for free when an @abstractmethod is not implemented by the subclass. It\u0027s not a big deal though.","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"}],"ironic/networking/utils.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"00d73fb1ab86aecddb73a069ede9fbd26470186e","unresolved":true,"context_lines":[{"line_number":103,"context_line":"    return vlans"},{"line_number":104,"context_line":""},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"def get_switch_vlan_config(switch_driver, switch_id):"},{"line_number":107,"context_line":"    \"\"\"Get VLAN configuration for a switch."},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"    Retrieves switch-specific VLAN configuration from the driver, with"}],"source_content_type":"text/x-python","patch_set":2,"id":"9d699757_640d3f66","line":106,"updated":"2025-11-21 16:51:26.000000000","message":"In ironic, we\u0027ve been historically overdoing it with files named utils.py. I don\u0027t disagree that parsing vlan ranges could be in such a file, but I wonder if the rest here belongs somewhere better named. I think all functions you\u0027re adding a related to switch configuration, so maybe add a module literally called `switch_config`?\n\nAs an example of confusion, I started commenting on parse_vlan_ranges under assumption it\u0027s coming from oslo.config only, where commas are not possible","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[{"line_number":103,"context_line":"    return vlans"},{"line_number":104,"context_line":""},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"def get_switch_vlan_config(switch_driver, switch_id):"},{"line_number":107,"context_line":"    \"\"\"Get VLAN configuration for a switch."},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"    Retrieves switch-specific VLAN configuration from the driver, with"}],"source_content_type":"text/x-python","patch_set":2,"id":"12e69595_e5b2634d","line":106,"in_reply_to":"9d699757_640d3f66","updated":"2025-11-27 16:41:44.000000000","message":"Done","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"00d73fb1ab86aecddb73a069ede9fbd26470186e","unresolved":true,"context_lines":[{"line_number":127,"context_line":"            # Process switch-specific allowed_vlans"},{"line_number":128,"context_line":"            if \"allowed_vlans\" in switch_info:"},{"line_number":129,"context_line":"                switch_allowed \u003d switch_info[\"allowed_vlans\"]"},{"line_number":130,"context_line":"                if isinstance(switch_allowed, list):"},{"line_number":131,"context_line":"                    config[\"allowed_vlans\"] \u003d parse_vlan_ranges(switch_allowed)"},{"line_number":132,"context_line":"                elif isinstance(switch_allowed, str):"},{"line_number":133,"context_line":"                    config[\"allowed_vlans\"] \u003d parse_vlan_ranges("}],"source_content_type":"text/x-python","patch_set":2,"id":"1588b8b3_41310e93","line":130,"updated":"2025-11-21 16:51:26.000000000","message":"very nit: you could make parse_vlan_ranges accept both lists and strings","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[{"line_number":127,"context_line":"            # Process switch-specific allowed_vlans"},{"line_number":128,"context_line":"            if \"allowed_vlans\" in switch_info:"},{"line_number":129,"context_line":"                switch_allowed \u003d switch_info[\"allowed_vlans\"]"},{"line_number":130,"context_line":"                if isinstance(switch_allowed, list):"},{"line_number":131,"context_line":"                    config[\"allowed_vlans\"] \u003d parse_vlan_ranges(switch_allowed)"},{"line_number":132,"context_line":"                elif isinstance(switch_allowed, str):"},{"line_number":133,"context_line":"                    config[\"allowed_vlans\"] \u003d parse_vlan_ranges("}],"source_content_type":"text/x-python","patch_set":2,"id":"7fc35f76_1f607819","line":130,"in_reply_to":"1588b8b3_41310e93","updated":"2025-11-27 16:41:44.000000000","message":"Done","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"00d73fb1ab86aecddb73a069ede9fbd26470186e","unresolved":true,"context_lines":[{"line_number":148,"context_line":"                    switch_info[\"allow_port_channels\"]"},{"line_number":149,"context_line":"                )"},{"line_number":150,"context_line":"    except Exception:"},{"line_number":151,"context_line":"        # If driver doesn\u0027t support get_switch_info or it fails,"},{"line_number":152,"context_line":"        # we\u0027ll use global config"},{"line_number":153,"context_line":"        LOG.debug("},{"line_number":154,"context_line":"            \"Failed to get switch info for switch %s, \" \"using global config\","}],"source_content_type":"text/x-python","patch_set":2,"id":"f4a0f0e7_e3dbf27d","line":151,"updated":"2025-11-21 16:51:26.000000000","message":"I think these cases should be handled separately. So, not having get_switch_info is allowed? Does it make a lot of sense? If yes, let\u0027s handle it separately, but probably let\u0027s not allow start-up with otherwise invalid configuration. This may become a security problem even.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"495407b8d361812da35b27e76fd1c4c8e2bfe310","unresolved":false,"context_lines":[{"line_number":148,"context_line":"                    switch_info[\"allow_port_channels\"]"},{"line_number":149,"context_line":"                )"},{"line_number":150,"context_line":"    except Exception:"},{"line_number":151,"context_line":"        # If driver doesn\u0027t support get_switch_info or it fails,"},{"line_number":152,"context_line":"        # we\u0027ll use global config"},{"line_number":153,"context_line":"        LOG.debug("},{"line_number":154,"context_line":"            \"Failed to get switch info for switch %s, \" \"using global config\","}],"source_content_type":"text/x-python","patch_set":2,"id":"0c0ac1ed_7fadb955","line":151,"in_reply_to":"f4a0f0e7_e3dbf27d","updated":"2025-11-27 16:41:44.000000000","message":"Ya, that should be mandatory so i\u0027ll treat this as an error.  Thanks.","commit_id":"49cdaeddea4b4f8fcdbc8878ce40f6474a751790"}],"ironic/tests/unit/networking/test_switch_config.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3ce43d8f6119e1b9cf91e0d2f88dc070428389ba","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":3,"id":"37cdfabd_e9203cbf","line":181,"updated":"2025-12-02 13:12:36.000000000","message":"I\u0027d prefer to see unit tests for the other 2 functions in the module","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"},{"author":{"_account_id":25437,"name":"Allain Legacy","email":"alegacy@redhat.com","username":"alegacy"},"change_message_id":"a27027692aeff63eac3ec40df4263e3a98ec9343","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"12c26058_190afcf1","line":181,"in_reply_to":"37cdfabd_e9203cbf","updated":"2025-12-03 13:08:29.000000000","message":"Done","commit_id":"5bf8fa60216379a801c73b7bfbdcae7227a49475"}]}
