)]}'
{"/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":"5f7111cac172dec85f8cb64f8f5de6404befd644","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"095e3f1c_45a6d4a0","updated":"2026-04-17 00:58:57.000000000","message":"recheck ironic devstack plugin fixed","commit_id":"e359e4652cc45f8e7d3c8ee7ab640d991679e252"},{"author":{"_account_id":4571,"name":"Steve Baker","email":"sbaker@redhat.com","username":"steve-stevebaker"},"change_message_id":"bac2a372c107ab3cd2533ba2ca6b3a84ef8882c3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":16,"id":"079e6d45_75e5ce3b","updated":"2026-10-27 23:08:31.000000000","message":"I\u0027m +1ing this just because I was involved in earlier revisions of this change, otherwise I would +2","commit_id":"19e3fb3612df2f2e0e48d127d3fbbddcc50c5a02"},{"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":"e40488392b5d6778240851bd0d18e5250fec12aa","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":16,"id":"efcb10cc_bcec70ce","updated":"2026-10-19 21:29:22.000000000","message":"This change is nearly 3000 lines long. It\u0027s extremely difficult to review effectively as a result.","commit_id":"19e3fb3612df2f2e0e48d127d3fbbddcc50c5a02"}],"doc/source/admin.rst":[{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":572,"context_line":"* ``username`` - NDFC authentication username"},{"line_number":573,"context_line":"* ``password`` - NDFC authentication password"},{"line_number":574,"context_line":"* ``ip`` - Switch IP address (used to identify switch in NDFC inventory)"},{"line_number":575,"context_line":"* ``ndfc_fabric_name`` - NDFC fabric name"},{"line_number":576,"context_line":""},{"line_number":577,"context_line":"Optional:"},{"line_number":578,"context_line":""}],"source_content_type":"text/x-rst","patch_set":9,"id":"e7be65dc_efa8ce25","line":575,"range":{"start_line":575,"start_character":4,"end_line":575,"end_character":20},"updated":"2026-06-12 13:09:30.000000000","message":"nit: could add (default: `default`)","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"}],"doc/source/admin/vxlan/cisco-ndfc.rst":[{"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":"c0dbd4c845f69437564e16f62971ebeed139ccb7","unresolved":true,"context_lines":[{"line_number":47,"context_line":""},{"line_number":48,"context_line":"The config section name (e.g. ``leaf01`` for ``[genericswitch:leaf01]``) must"},{"line_number":49,"context_line":"match the switch hostname in NDFC. This aligns with the Ironic ``switch_info``"},{"line_number":50,"context_line":"used to route ports to this section."},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"Optional:"},{"line_number":53,"context_line":""}],"source_content_type":"text/x-rst","patch_set":16,"id":"919d6bfd_73985086","line":50,"updated":"2026-10-19 21:35:37.000000000","message":"Just trying to make sure I have the shape of this right:\n\nThere\u0027s an NDFC that manages \"N\" switches. We have a single config to manage a single one of them.\n\nIs this going to create connection sharing issues or pain? What happens if I have 10 switches controlled by the same NDFC hooked up to NGS?","commit_id":"19e3fb3612df2f2e0e48d127d3fbbddcc50c5a02"}],"doc/source/configuration.rst":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"daca04b4a4b50da6594378e14df07d1b96a72067","unresolved":true,"context_lines":[{"line_number":507,"context_line":"  (see :ref:`restconf-nxos-quirks`)."},{"line_number":508,"context_line":"* ``ngs_restconf_base_path`` — Base path for RESTCONF data resources"},{"line_number":509,"context_line":"  (default: ``/restconf/data``)."},{"line_number":510,"context_line":"* ``ngs_verify_tls`` — Whether to verify the server\u0027s TLS"},{"line_number":511,"context_line":"  certificate (default: ``True``)."},{"line_number":512,"context_line":"* ``ngs_openconfig_network_instance`` — OpenConfig network-instance"},{"line_number":513,"context_line":"  for VLAN management (default: ``default``)."}],"source_content_type":"text/x-rst","patch_set":16,"id":"b4d6e18d_224cd283","line":510,"updated":"2026-09-28 13:09:29.000000000","message":"Are you changing the restconf implementation too? It doesn\u0027t seem to me from reading the patch.","commit_id":"19e3fb3612df2f2e0e48d127d3fbbddcc50c5a02"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":507,"context_line":"  (see :ref:`restconf-nxos-quirks`)."},{"line_number":508,"context_line":"* ``ngs_restconf_base_path`` — Base path for RESTCONF data resources"},{"line_number":509,"context_line":"  (default: ``/restconf/data``)."},{"line_number":510,"context_line":"* ``ngs_verify_tls`` — Whether to verify the server\u0027s TLS"},{"line_number":511,"context_line":"  certificate (default: ``True``)."},{"line_number":512,"context_line":"* ``ngs_openconfig_network_instance`` — OpenConfig network-instance"},{"line_number":513,"context_line":"  for VLAN management (default: ``default``)."}],"source_content_type":"text/x-rst","patch_set":16,"id":"14edb2f2_bb75c766","line":510,"in_reply_to":"b4d6e18d_224cd283","updated":"2026-10-16 20:03:56.000000000","message":"Acknowledged","commit_id":"19e3fb3612df2f2e0e48d127d3fbbddcc50c5a02"}],"networking_generic_switch/devices/__init__.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":65,"context_line":"    {\u0027name\u0027: \u0027ngs_security_groups_enabled\u0027, \u0027default\u0027: False},"},{"line_number":66,"context_line":"    # If False, skip TLS certificate verification for REST-API based"},{"line_number":67,"context_line":"    # drivers that talk HTTPS to a controller (e.g. NDFC)."},{"line_number":68,"context_line":"    {\u0027name\u0027: \u0027ngs_verify_ssl\u0027, \u0027default\u0027: True},"},{"line_number":69,"context_line":"    # Force NETCONF datastore target (\u0027candidate\u0027 or \u0027running\u0027)."},{"line_number":70,"context_line":"    # Unset (default) auto-detects from server capabilities."},{"line_number":71,"context_line":"    {\u0027name\u0027: \u0027ngs_netconf_target\u0027},"}],"source_content_type":"text/x-python","patch_set":15,"id":"2a6dfb26_2cb11ef3","line":68,"updated":"2026-09-17 10:46:25.000000000","message":"nit: s/ssl/tls/","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"817891e32844accf30fb3d86f8fa71fad46f45ed","unresolved":true,"context_lines":[{"line_number":65,"context_line":"    {\u0027name\u0027: \u0027ngs_security_groups_enabled\u0027, \u0027default\u0027: False},"},{"line_number":66,"context_line":"    # If False, skip TLS certificate verification for REST-API based"},{"line_number":67,"context_line":"    # drivers that talk HTTPS to a controller (e.g. NDFC)."},{"line_number":68,"context_line":"    {\u0027name\u0027: \u0027ngs_verify_ssl\u0027, \u0027default\u0027: True},"},{"line_number":69,"context_line":"    # Force NETCONF datastore target (\u0027candidate\u0027 or \u0027running\u0027)."},{"line_number":70,"context_line":"    # Unset (default) auto-detects from server capabilities."},{"line_number":71,"context_line":"    {\u0027name\u0027: \u0027ngs_netconf_target\u0027},"}],"source_content_type":"text/x-python","patch_set":15,"id":"3860f256_498134ea","line":68,"in_reply_to":"2a6dfb26_2cb11ef3","updated":"2026-09-18 20:53:30.000000000","message":"ugh, yeah, thats wrong. :(","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"}],"networking_generic_switch/devices/ndfc_devices/__init__.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":10,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"\"\"\"NDFC-based device drivers for Cisco switches.\"\"\""}],"source_content_type":"text/x-python","patch_set":15,"id":"78eb4742_f8db5f73","line":13,"updated":"2026-09-17 10:46:25.000000000","message":"nit: I think our linter used to object to files that only have a license..","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"817891e32844accf30fb3d86f8fa71fad46f45ed","unresolved":true,"context_lines":[{"line_number":10,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":11,"context_line":"#    under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"\"\"\"NDFC-based device drivers for Cisco switches.\"\"\""}],"source_content_type":"text/x-python","patch_set":15,"id":"6afe0c67_5a5355ea","line":13,"in_reply_to":"78eb4742_f8db5f73","updated":"2026-09-18 20:53:30.000000000","message":"Yeah, we should just go \"nope, make the empty file.\"","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"}],"networking_generic_switch/devices/ndfc_devices/cisco.py":[{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":14,"context_line":""},{"line_number":15,"context_line":"EXPERIMENTAL: This driver is experimental and based on publicly available"},{"line_number":16,"context_line":"NDFC API documentation. It manages Cisco NX-OS switches through the NDFC"},{"line_number":17,"context_line":"REST API instead of direct SSH access. NDFC provides centralized fabric"},{"line_number":18,"context_line":"management with audit trails, templating, and policy-based configuration."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"API Documentation:"}],"source_content_type":"text/x-python","patch_set":9,"id":"45e2eab9_9535a3ee","line":17,"range":{"start_line":17,"start_character":9,"end_line":17,"end_character":37},"updated":"2026-06-12 13:09:30.000000000","message":"nit: the \"instead of ...\" part can be dropped.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":false,"context_lines":[{"line_number":14,"context_line":""},{"line_number":15,"context_line":"EXPERIMENTAL: This driver is experimental and based on publicly available"},{"line_number":16,"context_line":"NDFC API documentation. It manages Cisco NX-OS switches through the NDFC"},{"line_number":17,"context_line":"REST API instead of direct SSH access. NDFC provides centralized fabric"},{"line_number":18,"context_line":"management with audit trails, templating, and policy-based configuration."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"API Documentation:"}],"source_content_type":"text/x-python","patch_set":9,"id":"626c2dae_d1d993db","line":17,"range":{"start_line":17,"start_character":9,"end_line":17,"end_character":37},"in_reply_to":"45e2eab9_9535a3ee","updated":"2026-09-02 14:19:33.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":102,"context_line":"    \"\"\"Cisco NDFC REST API-based switch driver."},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    Manages Cisco NX-OS switches through Nexus Dashboard Fabric"},{"line_number":105,"context_line":"    Controller (NDFC) REST API instead of SSH. Supports VLAN"},{"line_number":106,"context_line":"    provisioning, port configuration, trunk management, and"},{"line_number":107,"context_line":"    VXLAN L2VNI configuration via NDFC fabric controller."},{"line_number":108,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"90e3abe9_ff031a0e","line":105,"range":{"start_line":105,"start_character":31,"end_line":105,"end_character":46},"updated":"2026-06-12 13:09:30.000000000","message":"nit: the instead of SSH part can be dropped.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":false,"context_lines":[{"line_number":102,"context_line":"    \"\"\"Cisco NDFC REST API-based switch driver."},{"line_number":103,"context_line":""},{"line_number":104,"context_line":"    Manages Cisco NX-OS switches through Nexus Dashboard Fabric"},{"line_number":105,"context_line":"    Controller (NDFC) REST API instead of SSH. Supports VLAN"},{"line_number":106,"context_line":"    provisioning, port configuration, trunk management, and"},{"line_number":107,"context_line":"    VXLAN L2VNI configuration via NDFC fabric controller."},{"line_number":108,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"6ea643a6_ca42e93e","line":105,"range":{"start_line":105,"start_character":31,"end_line":105,"end_character":46},"in_reply_to":"90e3abe9_ff031a0e","updated":"2026-09-02 14:19:33.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":106,"context_line":"    provisioning, port configuration, trunk management, and"},{"line_number":107,"context_line":"    VXLAN L2VNI configuration via NDFC fabric controller."},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"    Port can be disabled: True"},{"line_number":110,"context_line":""},{"line_number":111,"context_line":"    Configuration Parameters"},{"line_number":112,"context_line":"    ~~~~~~~~~~~~~~~~~~~~~~~~"}],"source_content_type":"text/x-python","patch_set":9,"id":"3fbbe67b_2483f675","line":109,"range":{"start_line":109,"start_character":4,"end_line":109,"end_character":30},"updated":"2026-06-12 13:09:30.000000000","message":"In doc/source/admin.rst the opposite is in limitations?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":true,"context_lines":[{"line_number":106,"context_line":"    provisioning, port configuration, trunk management, and"},{"line_number":107,"context_line":"    VXLAN L2VNI configuration via NDFC fabric controller."},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"    Port can be disabled: True"},{"line_number":110,"context_line":""},{"line_number":111,"context_line":"    Configuration Parameters"},{"line_number":112,"context_line":"    ~~~~~~~~~~~~~~~~~~~~~~~~"}],"source_content_type":"text/x-python","patch_set":9,"id":"7100231e_83d571a4","line":109,"range":{"start_line":109,"start_character":4,"end_line":109,"end_character":30},"in_reply_to":"3fbbe67b_2483f675","updated":"2026-09-02 14:31:18.000000000","message":"Not really, but this likely doesn\u0027t need to be mentioned as verbosely as it has been detailed.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":170,"context_line":"    interface configuration, BGP EVPN control plane, and VXLAN data"},{"line_number":171,"context_line":"    plane automatically based on the fabric template."},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    Security Group Implementation"},{"line_number":174,"context_line":"    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"    Security groups are not currently implemented. Support for"},{"line_number":177,"context_line":"    NDFC policies and contracts is planned for a future release."},{"line_number":178,"context_line":"    \"\"\""},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"    # Signal L2VNI support (methods implemented dynamically)"}],"source_content_type":"text/x-python","patch_set":9,"id":"318837bd_a713242e","line":177,"range":{"start_line":173,"start_character":0,"end_line":177,"end_character":64},"updated":"2026-06-12 13:09:30.000000000","message":"May want to add this in admin.rst under limitation?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":false,"context_lines":[{"line_number":170,"context_line":"    interface configuration, BGP EVPN control plane, and VXLAN data"},{"line_number":171,"context_line":"    plane automatically based on the fabric template."},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    Security Group Implementation"},{"line_number":174,"context_line":"    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"},{"line_number":175,"context_line":""},{"line_number":176,"context_line":"    Security groups are not currently implemented. Support for"},{"line_number":177,"context_line":"    NDFC policies and contracts is planned for a future release."},{"line_number":178,"context_line":"    \"\"\""},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"    # Signal L2VNI support (methods implemented dynamically)"}],"source_content_type":"text/x-python","patch_set":9,"id":"b549652d_7e98a826","line":177,"range":{"start_line":173,"start_character":0,"end_line":177,"end_character":64},"in_reply_to":"318837bd_a713242e","updated":"2026-09-02 14:31:18.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":190,"context_line":"        return False"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"    def __init__(self, device_cfg, device_name\u003d\"\"):"},{"line_number":193,"context_line":"        # Extract ngs_* config before parent __init__ removes"},{"line_number":194,"context_line":"        # all ngs_* options from device_cfg."},{"line_number":195,"context_line":"        self.ndfc_max_connections \u003d device_cfg.get("},{"line_number":196,"context_line":"            \u0027ngs_max_connections\u0027, 5)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"        # Extract NDFC-specific config before super strips it"},{"line_number":199,"context_line":"        ndfc_host \u003d ("}],"source_content_type":"text/x-python","patch_set":9,"id":"ba19a36c_b2b7b65e","line":196,"range":{"start_line":193,"start_character":1,"end_line":196,"end_character":37},"updated":"2026-06-12 13:09:30.000000000","message":"Instead of this, other drivers use self.ngs_config. All options should be in NGS_INTERNAL_OPTS[1] and then after super().__init__() do:\n `self.ndfc_max_connections \u003d self.ngs_config[\u0027ngs_max_connections\u0027]`\n\n\n[1] https://opendev.org/openstack/networking-generic-switch/src/branch/master/networking_generic_switch/devices/__init__.py#L30","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":false,"context_lines":[{"line_number":190,"context_line":"        return False"},{"line_number":191,"context_line":""},{"line_number":192,"context_line":"    def __init__(self, device_cfg, device_name\u003d\"\"):"},{"line_number":193,"context_line":"        # Extract ngs_* config before parent __init__ removes"},{"line_number":194,"context_line":"        # all ngs_* options from device_cfg."},{"line_number":195,"context_line":"        self.ndfc_max_connections \u003d device_cfg.get("},{"line_number":196,"context_line":"            \u0027ngs_max_connections\u0027, 5)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"        # Extract NDFC-specific config before super strips it"},{"line_number":199,"context_line":"        ndfc_host \u003d ("}],"source_content_type":"text/x-python","patch_set":9,"id":"285f0842_779818d3","line":196,"range":{"start_line":193,"start_character":1,"end_line":196,"end_character":37},"in_reply_to":"ba19a36c_b2b7b65e","updated":"2026-09-02 14:19:33.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":"        # Extract NDFC-specific config before super strips it"},{"line_number":199,"context_line":"        ndfc_host \u003d ("},{"line_number":200,"context_line":"            device_cfg.get(\u0027host\u0027) or device_cfg.get(\u0027ip\u0027)"},{"line_number":201,"context_line":"        )"},{"line_number":202,"context_line":"        ndfc_port \u003d device_cfg.get(\u0027port\u0027, 443)"},{"line_number":203,"context_line":"        ndfc_username \u003d device_cfg.get(\u0027username\u0027)"}],"source_content_type":"text/x-python","patch_set":9,"id":"d1e99a58_543d417f","line":200,"range":{"start_line":200,"start_character":0,"end_line":200,"end_character":2},"updated":"2026-06-12 13:09:30.000000000","message":"I think we should use `host` only here? The `ip` is used for individual switch identification and would never be the same as the NDFC\u0027s `ip`?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":true,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":"        # Extract NDFC-specific config before super strips it"},{"line_number":199,"context_line":"        ndfc_host \u003d ("},{"line_number":200,"context_line":"            device_cfg.get(\u0027host\u0027) or device_cfg.get(\u0027ip\u0027)"},{"line_number":201,"context_line":"        )"},{"line_number":202,"context_line":"        ndfc_port \u003d device_cfg.get(\u0027port\u0027, 443)"},{"line_number":203,"context_line":"        ndfc_username \u003d device_cfg.get(\u0027username\u0027)"}],"source_content_type":"text/x-python","patch_set":9,"id":"ee1e5a01_faad5f8f","line":200,"range":{"start_line":200,"start_character":0,"end_line":200,"end_character":2},"in_reply_to":"a935371f_99be86aa","updated":"2026-09-02 14:31:18.000000000","message":"In terms of make sense, remove the use of ip.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":true,"context_lines":[{"line_number":197,"context_line":""},{"line_number":198,"context_line":"        # Extract NDFC-specific config before super strips it"},{"line_number":199,"context_line":"        ndfc_host \u003d ("},{"line_number":200,"context_line":"            device_cfg.get(\u0027host\u0027) or device_cfg.get(\u0027ip\u0027)"},{"line_number":201,"context_line":"        )"},{"line_number":202,"context_line":"        ndfc_port \u003d device_cfg.get(\u0027port\u0027, 443)"},{"line_number":203,"context_line":"        ndfc_username \u003d device_cfg.get(\u0027username\u0027)"}],"source_content_type":"text/x-python","patch_set":9,"id":"a935371f_99be86aa","line":200,"range":{"start_line":200,"start_character":0,"end_line":200,"end_character":2},"in_reply_to":"d1e99a58_543d417f","updated":"2026-09-02 14:19:33.000000000","message":"I think that makes a ton of sense.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":195,"context_line":"        self.ndfc_max_connections \u003d device_cfg.get("},{"line_number":196,"context_line":"            \u0027ngs_max_connections\u0027, 5)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"        # Extract NDFC-specific config before super strips it"},{"line_number":199,"context_line":"        ndfc_host \u003d ("},{"line_number":200,"context_line":"            device_cfg.get(\u0027host\u0027) or device_cfg.get(\u0027ip\u0027)"},{"line_number":201,"context_line":"        )"},{"line_number":202,"context_line":"        ndfc_port \u003d device_cfg.get(\u0027port\u0027, 443)"},{"line_number":203,"context_line":"        ndfc_username \u003d device_cfg.get(\u0027username\u0027)"},{"line_number":204,"context_line":"        ndfc_password \u003d device_cfg.get(\u0027password\u0027)"},{"line_number":205,"context_line":""},{"line_number":206,"context_line":"        super(CiscoNDFC, self).__init__(device_cfg, device_name)"},{"line_number":207,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"531d4ebd_3937e588","line":204,"range":{"start_line":198,"start_character":0,"end_line":204,"end_character":50},"updated":"2026-06-12 13:09:30.000000000","message":"These are not needed? Only `ngs_` prefixed options are stripped.\nRef: https://opendev.org/openstack/networking-generic-switch/src/branch/master/networking_generic_switch/devices/__init__.py#L116-L128","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":false,"context_lines":[{"line_number":195,"context_line":"        self.ndfc_max_connections \u003d device_cfg.get("},{"line_number":196,"context_line":"            \u0027ngs_max_connections\u0027, 5)"},{"line_number":197,"context_line":""},{"line_number":198,"context_line":"        # Extract NDFC-specific config before super strips it"},{"line_number":199,"context_line":"        ndfc_host \u003d ("},{"line_number":200,"context_line":"            device_cfg.get(\u0027host\u0027) or device_cfg.get(\u0027ip\u0027)"},{"line_number":201,"context_line":"        )"},{"line_number":202,"context_line":"        ndfc_port \u003d device_cfg.get(\u0027port\u0027, 443)"},{"line_number":203,"context_line":"        ndfc_username \u003d device_cfg.get(\u0027username\u0027)"},{"line_number":204,"context_line":"        ndfc_password \u003d device_cfg.get(\u0027password\u0027)"},{"line_number":205,"context_line":""},{"line_number":206,"context_line":"        super(CiscoNDFC, self).__init__(device_cfg, device_name)"},{"line_number":207,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"8ed6d5d0_36211b61","line":204,"range":{"start_line":198,"start_character":0,"end_line":204,"end_character":50},"in_reply_to":"531d4ebd_3937e588","updated":"2026-09-02 14:19:33.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":211,"context_line":"        self.ndfc_username \u003d ndfc_username"},{"line_number":212,"context_line":"        self.ndfc_password \u003d ndfc_password"},{"line_number":213,"context_line":"        self.ndfc_fabric \u003d device_cfg.get("},{"line_number":214,"context_line":"            \u0027ndfc_fabric_name\u0027, \u0027default\u0027)"},{"line_number":215,"context_line":"        self.ndfc_verify_ssl \u003d strutils.bool_from_string("},{"line_number":216,"context_line":"            device_cfg.get(\u0027ndfc_verify_ssl\u0027, True))"},{"line_number":217,"context_line":"        self.ndfc_timeout \u003d device_cfg.get(\u0027ndfc_timeout\u0027, 30)"}],"source_content_type":"text/x-python","patch_set":9,"id":"07629661_f3b7aa37","line":214,"range":{"start_line":214,"start_character":13,"end_line":214,"end_character":29},"updated":"2026-06-12 13:09:30.000000000","message":"Should all these be in NGS_INTERNAL_OPTS, or a new NDFC_OPTS?.\n\nAs it is now, there will be warning logged for all of these, ref: https://opendev.org/openstack/networking-generic-switch/src/branch/master/networking_generic_switch/devices/__init__.py#L125-L127","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":false,"context_lines":[{"line_number":211,"context_line":"        self.ndfc_username \u003d ndfc_username"},{"line_number":212,"context_line":"        self.ndfc_password \u003d ndfc_password"},{"line_number":213,"context_line":"        self.ndfc_fabric \u003d device_cfg.get("},{"line_number":214,"context_line":"            \u0027ndfc_fabric_name\u0027, \u0027default\u0027)"},{"line_number":215,"context_line":"        self.ndfc_verify_ssl \u003d strutils.bool_from_string("},{"line_number":216,"context_line":"            device_cfg.get(\u0027ndfc_verify_ssl\u0027, True))"},{"line_number":217,"context_line":"        self.ndfc_timeout \u003d device_cfg.get(\u0027ndfc_timeout\u0027, 30)"}],"source_content_type":"text/x-python","patch_set":9,"id":"ec931633_083770dd","line":214,"range":{"start_line":214,"start_character":13,"end_line":214,"end_character":29},"in_reply_to":"07629661_f3b7aa37","updated":"2026-09-02 14:31:18.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":213,"context_line":"        self.ndfc_fabric \u003d device_cfg.get("},{"line_number":214,"context_line":"            \u0027ndfc_fabric_name\u0027, \u0027default\u0027)"},{"line_number":215,"context_line":"        self.ndfc_verify_ssl \u003d strutils.bool_from_string("},{"line_number":216,"context_line":"            device_cfg.get(\u0027ndfc_verify_ssl\u0027, True))"},{"line_number":217,"context_line":"        self.ndfc_timeout \u003d device_cfg.get(\u0027ndfc_timeout\u0027, 30)"},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"        # Switch identification (IP used to find serial in NDFC)"}],"source_content_type":"text/x-python","patch_set":9,"id":"d7fefce8_bcd0f3b4","line":216,"range":{"start_line":216,"start_character":28,"end_line":216,"end_character":43},"updated":"2026-06-12 13:09:30.000000000","message":"In the proposed restconf changes I used `ngs_restconf_verify_ssl` - Should we add a generic `ngs_verify_ssl` option instead and align?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":true,"context_lines":[{"line_number":213,"context_line":"        self.ndfc_fabric \u003d device_cfg.get("},{"line_number":214,"context_line":"            \u0027ndfc_fabric_name\u0027, \u0027default\u0027)"},{"line_number":215,"context_line":"        self.ndfc_verify_ssl \u003d strutils.bool_from_string("},{"line_number":216,"context_line":"            device_cfg.get(\u0027ndfc_verify_ssl\u0027, True))"},{"line_number":217,"context_line":"        self.ndfc_timeout \u003d device_cfg.get(\u0027ndfc_timeout\u0027, 30)"},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"        # Switch identification (IP used to find serial in NDFC)"}],"source_content_type":"text/x-python","patch_set":9,"id":"38deac78_3525377c","line":216,"range":{"start_line":216,"start_character":28,"end_line":216,"end_character":43},"in_reply_to":"d7fefce8_bcd0f3b4","updated":"2026-09-02 14:19:33.000000000","message":"Ideally yes, and wire everything for it.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":216,"context_line":"            device_cfg.get(\u0027ndfc_verify_ssl\u0027, True))"},{"line_number":217,"context_line":"        self.ndfc_timeout \u003d device_cfg.get(\u0027ndfc_timeout\u0027, 30)"},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"        # Switch identification (IP used to find serial in NDFC)"},{"line_number":220,"context_line":"        self.switch_ip \u003d self.config.get(\u0027ip\u0027)"},{"line_number":221,"context_line":"        if not self.switch_ip:"},{"line_number":222,"context_line":"            LOG.error(\u0027Switch IP address is required for NDFC driver\u0027)"}],"source_content_type":"text/x-python","patch_set":9,"id":"be91034d_9770890e","line":219,"range":{"start_line":219,"start_character":8,"end_line":219,"end_character":64},"updated":"2026-06-12 13:09:30.000000000","message":"There is a potential scaling issue here?\nWe would define separate ini sections for each switch, all section has a common host (the NDFC) but the `ip` is for each individual switch managed by the NDFC.\n\nngs_max_connections is supposed to control the number of concurrent connections to the NDFC. Since that is per switch, not per NDFC we cannot keep that below `switches * 1` so 100 switches \u003d 100 connections.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":true,"context_lines":[{"line_number":216,"context_line":"            device_cfg.get(\u0027ndfc_verify_ssl\u0027, True))"},{"line_number":217,"context_line":"        self.ndfc_timeout \u003d device_cfg.get(\u0027ndfc_timeout\u0027, 30)"},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"        # Switch identification (IP used to find serial in NDFC)"},{"line_number":220,"context_line":"        self.switch_ip \u003d self.config.get(\u0027ip\u0027)"},{"line_number":221,"context_line":"        if not self.switch_ip:"},{"line_number":222,"context_line":"            LOG.error(\u0027Switch IP address is required for NDFC driver\u0027)"}],"source_content_type":"text/x-python","patch_set":9,"id":"10eae650_3f8397e1","line":219,"range":{"start_line":219,"start_character":8,"end_line":219,"end_character":64},"in_reply_to":"be91034d_9770890e","updated":"2026-09-02 14:19:33.000000000","message":"So, AIUI, we would define a single instance for the interaction with NDFC, not each switch in NDFC because that would be a management nightmare. The issue is the reliance and modeling on switch_ip which is not in LLDP data.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":217,"context_line":"        self.ndfc_timeout \u003d device_cfg.get(\u0027ndfc_timeout\u0027, 30)"},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"        # Switch identification (IP used to find serial in NDFC)"},{"line_number":220,"context_line":"        self.switch_ip \u003d self.config.get(\u0027ip\u0027)"},{"line_number":221,"context_line":"        if not self.switch_ip:"},{"line_number":222,"context_line":"            LOG.error(\u0027Switch IP address is required for NDFC driver\u0027)"},{"line_number":223,"context_line":"            raise exc.GenericSwitchNDFCConfigError()"}],"source_content_type":"text/x-python","patch_set":9,"id":"14dcfd34_a3b0e0a7","line":220,"range":{"start_line":220,"start_character":0,"end_line":220,"end_character":2},"updated":"2026-06-12 13:09:30.000000000","message":"Here we access `ip` after the above extract to `ndfc_host` - proving super does not strip these.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":true,"context_lines":[{"line_number":217,"context_line":"        self.ndfc_timeout \u003d device_cfg.get(\u0027ndfc_timeout\u0027, 30)"},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"        # Switch identification (IP used to find serial in NDFC)"},{"line_number":220,"context_line":"        self.switch_ip \u003d self.config.get(\u0027ip\u0027)"},{"line_number":221,"context_line":"        if not self.switch_ip:"},{"line_number":222,"context_line":"            LOG.error(\u0027Switch IP address is required for NDFC driver\u0027)"},{"line_number":223,"context_line":"            raise exc.GenericSwitchNDFCConfigError()"}],"source_content_type":"text/x-python","patch_set":9,"id":"40916880_d75d7939","line":220,"range":{"start_line":220,"start_character":0,"end_line":220,"end_character":2},"in_reply_to":"14dcfd34_a3b0e0a7","updated":"2026-09-02 14:19:33.000000000","message":"I believe the intent is device matching, but I have a follow-up patch which allows configuring a \"fallback device\" in simpler environments.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":227,"context_line":"        # plug_port_to_network, and delete_port). Using {network_id} would"},{"line_number":228,"context_line":"        # produce inconsistent names across these call sites."},{"line_number":229,"context_line":"        name_format \u003d self.ngs_config[\u0027ngs_network_name_format\u0027]"},{"line_number":230,"context_line":"        if \u0027{network_id}\u0027 in name_format:"},{"line_number":231,"context_line":"            LOG.error("},{"line_number":232,"context_line":"                \"ngs_network_name_format \u0027%s\u0027 contains {network_id} which \""},{"line_number":233,"context_line":"                \"is not supported by the NDFC driver. Use {segmentation_id} \""},{"line_number":234,"context_line":"                \"instead.\", name_format)"},{"line_number":235,"context_line":"            raise exc.GenericSwitchNDFCConfigError()"},{"line_number":236,"context_line":"        if \u0027{segmentation_id}\u0027 not in name_format:"},{"line_number":237,"context_line":"            LOG.error("},{"line_number":238,"context_line":"                \"ngs_network_name_format \u0027%s\u0027 must contain {segmentation_id} \""},{"line_number":239,"context_line":"                \"for the NDFC driver.\", name_format)"},{"line_number":240,"context_line":"            raise exc.GenericSwitchNDFCConfigError()"},{"line_number":241,"context_line":""},{"line_number":242,"context_line":"        # NDFC template and policy configuration"},{"line_number":243,"context_line":"        self.ndfc_network_template \u003d device_cfg.get("}],"source_content_type":"text/x-python","patch_set":9,"id":"b36d4c09_bdea6e61","line":240,"range":{"start_line":230,"start_character":0,"end_line":240,"end_character":52},"updated":"2026-06-12 13:09:30.000000000","message":"We only need the second condition? - Or we ignore the option, since segmentation_id is the only choice?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":false,"context_lines":[{"line_number":227,"context_line":"        # plug_port_to_network, and delete_port). Using {network_id} would"},{"line_number":228,"context_line":"        # produce inconsistent names across these call sites."},{"line_number":229,"context_line":"        name_format \u003d self.ngs_config[\u0027ngs_network_name_format\u0027]"},{"line_number":230,"context_line":"        if \u0027{network_id}\u0027 in name_format:"},{"line_number":231,"context_line":"            LOG.error("},{"line_number":232,"context_line":"                \"ngs_network_name_format \u0027%s\u0027 contains {network_id} which \""},{"line_number":233,"context_line":"                \"is not supported by the NDFC driver. Use {segmentation_id} \""},{"line_number":234,"context_line":"                \"instead.\", name_format)"},{"line_number":235,"context_line":"            raise exc.GenericSwitchNDFCConfigError()"},{"line_number":236,"context_line":"        if \u0027{segmentation_id}\u0027 not in name_format:"},{"line_number":237,"context_line":"            LOG.error("},{"line_number":238,"context_line":"                \"ngs_network_name_format \u0027%s\u0027 must contain {segmentation_id} \""},{"line_number":239,"context_line":"                \"for the NDFC driver.\", name_format)"},{"line_number":240,"context_line":"            raise exc.GenericSwitchNDFCConfigError()"},{"line_number":241,"context_line":""},{"line_number":242,"context_line":"        # NDFC template and policy configuration"},{"line_number":243,"context_line":"        self.ndfc_network_template \u003d device_cfg.get("}],"source_content_type":"text/x-python","patch_set":9,"id":"56cfef38_5164e57f","line":240,"range":{"start_line":230,"start_character":0,"end_line":240,"end_character":52},"in_reply_to":"b36d4c09_bdea6e61","updated":"2026-09-02 14:19:33.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":241,"context_line":""},{"line_number":242,"context_line":"        # NDFC template and policy configuration"},{"line_number":243,"context_line":"        self.ndfc_network_template \u003d device_cfg.get("},{"line_number":244,"context_line":"            \u0027ndfc_network_template\u0027,"},{"line_number":245,"context_line":"            \u0027Default_Network_Universal\u0027)"},{"line_number":246,"context_line":"        self.ndfc_network_extension_template \u003d device_cfg.get("},{"line_number":247,"context_line":"            \u0027ndfc_network_extension_template\u0027,"}],"source_content_type":"text/x-python","patch_set":9,"id":"9ff4a167_f4396b34","line":244,"range":{"start_line":244,"start_character":13,"end_line":244,"end_character":34},"updated":"2026-06-12 13:09:30.000000000","message":"same, use NGS_INTERNAL_OPTS pattern, or add separate NDFC_OPTS pattern to avoid the warning logs.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":false,"context_lines":[{"line_number":241,"context_line":""},{"line_number":242,"context_line":"        # NDFC template and policy configuration"},{"line_number":243,"context_line":"        self.ndfc_network_template \u003d device_cfg.get("},{"line_number":244,"context_line":"            \u0027ndfc_network_template\u0027,"},{"line_number":245,"context_line":"            \u0027Default_Network_Universal\u0027)"},{"line_number":246,"context_line":"        self.ndfc_network_extension_template \u003d device_cfg.get("},{"line_number":247,"context_line":"            \u0027ndfc_network_extension_template\u0027,"}],"source_content_type":"text/x-python","patch_set":9,"id":"7a1fa61e_81922f0e","line":244,"range":{"start_line":244,"start_character":13,"end_line":244,"end_character":34},"in_reply_to":"9ff4a167_f4396b34","updated":"2026-09-02 14:19:33.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":248,"context_line":"            \u0027Default_Network_Extension_Universal\u0027)"},{"line_number":249,"context_line":"        self.ndfc_vrf \u003d device_cfg.get(\u0027ndfc_vrf\u0027, \u0027default\u0027)"},{"line_number":250,"context_line":"        self.ndfc_interface_policy \u003d device_cfg.get("},{"line_number":251,"context_line":"            \u0027ndfc_interface_policy\u0027, \u0027int_trunk_host\u0027)"},{"line_number":252,"context_line":""},{"line_number":253,"context_line":"        # Generate session key from credentials (hashed)"},{"line_number":254,"context_line":"        # This ensures password changes result in new sessions."}],"source_content_type":"text/x-python","patch_set":9,"id":"46065f8e_708318c5","line":251,"range":{"start_line":251,"start_character":38,"end_line":251,"end_character":52},"updated":"2026-06-12 13:09:30.000000000","message":"This does not match the default in doc/source/admin.rst. Change it in docs to align.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":419,"context_line":"        except requests.exceptions.RequestException as e:"},{"line_number":420,"context_line":"            LOG.error(\"NDFC connection failed to %s:%s: %s\","},{"line_number":421,"context_line":"                      self.ndfc_host, self.ndfc_port, e)"},{"line_number":422,"context_line":"            raise exc.GenericSwitchNDFCConnectError()"},{"line_number":423,"context_line":""},{"line_number":424,"context_line":"    def _parse_response(self, response, method, endpoint, url):"},{"line_number":425,"context_line":"        \"\"\"Parse an NDFC HTTP response, checking for embedded failures."}],"source_content_type":"text/x-python","patch_set":9,"id":"34be630f_0f450bd4","line":422,"range":{"start_line":422,"start_character":0,"end_line":422,"end_character":2},"updated":"2026-06-12 13:09:30.000000000","message":"Use `from e` here ?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":456,"context_line":"    def _is_auth_error(e):"},{"line_number":457,"context_line":"        \"\"\"Return True if HTTPError indicates an authentication failure.\"\"\""},{"line_number":458,"context_line":"        status_code \u003d ("},{"line_number":459,"context_line":"            e.response.status_code if e.response is not None else None"},{"line_number":460,"context_line":"        )"},{"line_number":461,"context_line":"        body \u003d {}"},{"line_number":462,"context_line":"        if e.response is not None:"}],"source_content_type":"text/x-python","patch_set":9,"id":"6fdd4631_07326a74","line":459,"range":{"start_line":459,"start_character":35,"end_line":459,"end_character":70},"updated":"2026-06-12 13:09:30.000000000","message":"This if else looks redundant?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":471,"context_line":"            or \u0027not authorized\u0027 in body_str"},{"line_number":472,"context_line":"        )"},{"line_number":473,"context_line":""},{"line_number":474,"context_line":"    def _ndfc_request(self, method, endpoint, **kwargs):"},{"line_number":475,"context_line":"        \"\"\"Execute NDFC REST API request with error handling."},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"        Automatically handles token expiration by re-authenticating and"}],"source_content_type":"text/x-python","patch_set":9,"id":"dc37a8a5_feba6d46","line":474,"range":{"start_line":474,"start_character":8,"end_line":474,"end_character":21},"updated":"2026-06-12 13:09:30.000000000","message":"May want to add some tests for this method?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":507,"context_line":"            if not self._is_auth_error(e):"},{"line_number":508,"context_line":"                detail \u003d self._http_error_detail(e)"},{"line_number":509,"context_line":"                LOG.error(\"NDFC API error: %s\", detail if detail else e)"},{"line_number":510,"context_line":"                raise exc.GenericSwitchNDFCConfigError()"},{"line_number":511,"context_line":""},{"line_number":512,"context_line":"            status \u003d ("},{"line_number":513,"context_line":"                e.response.status_code if e.response is not None else None"}],"source_content_type":"text/x-python","patch_set":9,"id":"4e0a5ba5_cf685ac3","line":510,"range":{"start_line":510,"start_character":0,"end_line":510,"end_character":2},"updated":"2026-06-12 13:09:30.000000000","message":"Use `from e` here ?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":false,"context_lines":[{"line_number":507,"context_line":"            if not self._is_auth_error(e):"},{"line_number":508,"context_line":"                detail \u003d self._http_error_detail(e)"},{"line_number":509,"context_line":"                LOG.error(\"NDFC API error: %s\", detail if detail else e)"},{"line_number":510,"context_line":"                raise exc.GenericSwitchNDFCConfigError()"},{"line_number":511,"context_line":""},{"line_number":512,"context_line":"            status \u003d ("},{"line_number":513,"context_line":"                e.response.status_code if e.response is not None else None"}],"source_content_type":"text/x-python","patch_set":9,"id":"33de1ee9_fa3aa91c","line":510,"range":{"start_line":510,"start_character":0,"end_line":510,"end_character":2},"in_reply_to":"4e0a5ba5_cf685ac3","updated":"2026-09-02 14:31:18.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":510,"context_line":"                raise exc.GenericSwitchNDFCConfigError()"},{"line_number":511,"context_line":""},{"line_number":512,"context_line":"            status \u003d ("},{"line_number":513,"context_line":"                e.response.status_code if e.response is not None else None"},{"line_number":514,"context_line":"            )"},{"line_number":515,"context_line":"            LOG.info(\"NDFC token expired (HTTP %s), \""},{"line_number":516,"context_line":"                     \"re-authenticating and retrying request\", status)"}],"source_content_type":"text/x-python","patch_set":9,"id":"7b2ddcd7_0ada48d1","line":513,"range":{"start_line":513,"start_character":39,"end_line":513,"end_character":74},"updated":"2026-06-12 13:09:30.000000000","message":"same, redundant if else pattern?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":false,"context_lines":[{"line_number":510,"context_line":"                raise exc.GenericSwitchNDFCConfigError()"},{"line_number":511,"context_line":""},{"line_number":512,"context_line":"            status \u003d ("},{"line_number":513,"context_line":"                e.response.status_code if e.response is not None else None"},{"line_number":514,"context_line":"            )"},{"line_number":515,"context_line":"            LOG.info(\"NDFC token expired (HTTP %s), \""},{"line_number":516,"context_line":"                     \"re-authenticating and retrying request\", status)"}],"source_content_type":"text/x-python","patch_set":9,"id":"2dac9779_fb535927","line":513,"range":{"start_line":513,"start_character":39,"end_line":513,"end_character":74},"in_reply_to":"7b2ddcd7_0ada48d1","updated":"2026-09-02 14:31:18.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":531,"context_line":"                detail \u003d self._http_error_detail(retry_error)"},{"line_number":532,"context_line":"                LOG.error(\"NDFC API error after re-auth: %s\","},{"line_number":533,"context_line":"                          detail if detail else retry_error)"},{"line_number":534,"context_line":"                raise exc.GenericSwitchNDFCConfigError()"},{"line_number":535,"context_line":""},{"line_number":536,"context_line":"        except requests.exceptions.RequestException as e:"},{"line_number":537,"context_line":"            # Attempt to extract a response body from the cause chain"}],"source_content_type":"text/x-python","patch_set":9,"id":"00dda269_9755009e","line":534,"range":{"start_line":534,"start_character":0,"end_line":534,"end_character":2},"updated":"2026-06-12 13:09:30.000000000","message":"Use `from e` here ?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":false,"context_lines":[{"line_number":531,"context_line":"                detail \u003d self._http_error_detail(retry_error)"},{"line_number":532,"context_line":"                LOG.error(\"NDFC API error after re-auth: %s\","},{"line_number":533,"context_line":"                          detail if detail else retry_error)"},{"line_number":534,"context_line":"                raise exc.GenericSwitchNDFCConfigError()"},{"line_number":535,"context_line":""},{"line_number":536,"context_line":"        except requests.exceptions.RequestException as e:"},{"line_number":537,"context_line":"            # Attempt to extract a response body from the cause chain"}],"source_content_type":"text/x-python","patch_set":9,"id":"f084f1d6_8ebe17fb","line":534,"range":{"start_line":534,"start_character":0,"end_line":534,"end_character":2},"in_reply_to":"00dda269_9755009e","updated":"2026-09-02 14:31:18.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":550,"context_line":"                else f\"NDFC request failed: {e}\""},{"line_number":551,"context_line":"            )"},{"line_number":552,"context_line":"            LOG.error(error_msg)"},{"line_number":553,"context_line":"            raise exc.GenericSwitchNDFCConfigError()"},{"line_number":554,"context_line":""},{"line_number":555,"context_line":"    def _get_network_attachments(self, network_name):"},{"line_number":556,"context_line":"        \"\"\"Query current network attachments from NDFC."}],"source_content_type":"text/x-python","patch_set":9,"id":"8eac5fa2_51c3fe39","line":553,"range":{"start_line":553,"start_character":0,"end_line":553,"end_character":2},"updated":"2026-06-12 13:09:30.000000000","message":"Use `from e` here ?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":false,"context_lines":[{"line_number":550,"context_line":"                else f\"NDFC request failed: {e}\""},{"line_number":551,"context_line":"            )"},{"line_number":552,"context_line":"            LOG.error(error_msg)"},{"line_number":553,"context_line":"            raise exc.GenericSwitchNDFCConfigError()"},{"line_number":554,"context_line":""},{"line_number":555,"context_line":"    def _get_network_attachments(self, network_name):"},{"line_number":556,"context_line":"        \"\"\"Query current network attachments from NDFC."}],"source_content_type":"text/x-python","patch_set":9,"id":"fb6acca0_0c6dacb8","line":553,"range":{"start_line":553,"start_character":0,"end_line":553,"end_character":2},"in_reply_to":"8eac5fa2_51c3fe39","updated":"2026-09-02 14:31:18.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":799,"context_line":"        # Modern API wraps switches in a \"switches\" key"},{"line_number":800,"context_line":"        switches \u003d response.get(\u0027switches\u0027, [])"},{"line_number":801,"context_line":""},{"line_number":802,"context_line":"        # Match by IP address (v2 uses \u0027fabricManagementIp\u0027)"},{"line_number":803,"context_line":"        for switch in switches:"},{"line_number":804,"context_line":"            if switch.get(\u0027fabricManagementIp\u0027) \u003d\u003d self.switch_ip:"},{"line_number":805,"context_line":"                self._switch_serial \u003d switch.get(\u0027serialNumber\u0027)"},{"line_number":806,"context_line":"                LOG.debug(\"Found switch %s with serial %s\","},{"line_number":807,"context_line":"                          self.switch_ip, self._switch_serial)"},{"line_number":808,"context_line":"                return self._switch_serial"},{"line_number":809,"context_line":""},{"line_number":810,"context_line":"        LOG.error(f\"Switch with IP {self.switch_ip} not found in \""},{"line_number":811,"context_line":"                  f\"fabric \u0027{self.ndfc_fabric}\u0027\")"}],"source_content_type":"text/x-python","patch_set":9,"id":"cba5323d_309d764b","line":808,"range":{"start_line":802,"start_character":0,"end_line":808,"end_character":42},"updated":"2026-06-12 13:09:30.000000000","message":"I think we could move this filter server side? `f\u0027{self._api_base}switches?fabricManagementIp\u003d{self.switch_ip}\u0027`","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":831,"context_line":""},{"line_number":832,"context_line":"        :param switch_serial: Serial number of the switch to deploy to"},{"line_number":833,"context_line":"        \"\"\""},{"line_number":834,"context_line":"        if not self._get_save_configuration():"},{"line_number":835,"context_line":"            LOG.debug(\"Configuration deployment disabled\")"},{"line_number":836,"context_line":"            return"},{"line_number":837,"context_line":""},{"line_number":838,"context_line":"        _control_base \u003d ("},{"line_number":839,"context_line":"            \"appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control\""}],"source_content_type":"text/x-python","patch_set":9,"id":"05388f88_bcf87a3b","line":836,"range":{"start_line":834,"start_character":0,"end_line":836,"end_character":18},"updated":"2026-06-12 13:09:30.000000000","message":"This seems like the wrong usage of `ngs_save_configuration`.\n\n_get_save_configuration is for \"write memory\" i.e switch runtime config is applied, just not saved to survive reboot. In this case it would be \"do not configure switch att all\" just stage to NDFC\u0027s intent database?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"61809303e7098980d7efbb44031ef35c2237ff0e","unresolved":true,"context_lines":[{"line_number":831,"context_line":""},{"line_number":832,"context_line":"        :param switch_serial: Serial number of the switch to deploy to"},{"line_number":833,"context_line":"        \"\"\""},{"line_number":834,"context_line":"        if not self._get_save_configuration():"},{"line_number":835,"context_line":"            LOG.debug(\"Configuration deployment disabled\")"},{"line_number":836,"context_line":"            return"},{"line_number":837,"context_line":""},{"line_number":838,"context_line":"        _control_base \u003d ("},{"line_number":839,"context_line":"            \"appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control\""}],"source_content_type":"text/x-python","patch_set":9,"id":"283ded9e_7786d5df","line":836,"range":{"start_line":834,"start_character":0,"end_line":836,"end_character":18},"in_reply_to":"05388f88_bcf87a3b","updated":"2026-09-02 14:31:18.000000000","message":"Oh, ouch, good catch. Yes, this is wrong. Likely there is no parallel to \"don\u0027t save\" with ndfc because the classical switch behavior is \"applied, but not saved\", where as here it is \"set in the api but not applied\"","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":1216,"context_line":"        \"\"\""},{"line_number":1217,"context_line":"        switch_serial \u003d self._get_switch_serial()"},{"line_number":1218,"context_line":""},{"line_number":1219,"context_line":"        existing \u003d self._get_interface_allowed_vlans(switch_serial, port)"},{"line_number":1220,"context_line":"        new_vlans \u003d existing | {int(sp.get(\u0027segmentation_id\u0027))"},{"line_number":1221,"context_line":"                                for sp in subports}"},{"line_number":1222,"context_line":""},{"line_number":1223,"context_line":"        LOG.info(\"Adding subport VLANs %s to trunk port %s on %s\","},{"line_number":1224,"context_line":"                 [sp.get(\u0027segmentation_id\u0027) for sp in subports],"}],"source_content_type":"text/x-python","patch_set":9,"id":"2cbb12fd_d3956a7b","line":1221,"range":{"start_line":1219,"start_character":0,"end_line":1221,"end_character":51},"updated":"2026-06-12 13:09:30.000000000","message":"In a follow up, should we consider using the fact that the port object holds all the subport VLAN\u0027s and do a single PUT operation to \"converge\". Would remove the need to got GET -\u003e diff -\u003e PUT. Same goes for some other places where we do the GET -\u003e diff -\u003e PUT dance.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":true,"context_lines":[{"line_number":1216,"context_line":"        \"\"\""},{"line_number":1217,"context_line":"        switch_serial \u003d self._get_switch_serial()"},{"line_number":1218,"context_line":""},{"line_number":1219,"context_line":"        existing \u003d self._get_interface_allowed_vlans(switch_serial, port)"},{"line_number":1220,"context_line":"        new_vlans \u003d existing | {int(sp.get(\u0027segmentation_id\u0027))"},{"line_number":1221,"context_line":"                                for sp in subports}"},{"line_number":1222,"context_line":""},{"line_number":1223,"context_line":"        LOG.info(\"Adding subport VLANs %s to trunk port %s on %s\","},{"line_number":1224,"context_line":"                 [sp.get(\u0027segmentation_id\u0027) for sp in subports],"}],"source_content_type":"text/x-python","patch_set":9,"id":"fd713865_847b826f","line":1221,"range":{"start_line":1219,"start_character":0,"end_line":1221,"end_character":51},"in_reply_to":"2cbb12fd_d3956a7b","updated":"2026-09-02 14:19:33.000000000","message":"I think claude took this path more so to take a model of not inherently \"just stomping\" on configuration, which is a semi-similar model. Likely best to just assert, although I\u0027m personally super skeptical of \"host trunks\" for anything outside of hypervisors.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":1282,"context_line":""},{"line_number":1283,"context_line":"        self._deploy_config(switch_serial)"},{"line_number":1284,"context_line":""},{"line_number":1285,"context_line":"    def plug_switch_to_network(self, vni,"},{"line_number":1286,"context_line":"                               segmentation_id,"},{"line_number":1287,"context_line":"                               physnet\u003dNone):"},{"line_number":1288,"context_line":"        \"\"\"Configure L2VNI mapping in NDFC fabric."}],"source_content_type":"text/x-python","patch_set":9,"id":"77e67fb4_cafffee8","line":1285,"range":{"start_line":1285,"start_character":8,"end_line":1285,"end_character":30},"updated":"2026-06-12 13:09:30.000000000","message":"This is 99% the same as `add_network()` above, just the additional `_set_vlan_vni_mapping` and `_do_vlan_management`? I think a shared helper function to do the the bulk of this would be good. Just pass different `networkId`?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"6f607e94481925c0a1c02708d300fe9036142eb4","unresolved":false,"context_lines":[{"line_number":1282,"context_line":""},{"line_number":1283,"context_line":"        self._deploy_config(switch_serial)"},{"line_number":1284,"context_line":""},{"line_number":1285,"context_line":"    def plug_switch_to_network(self, vni,"},{"line_number":1286,"context_line":"                               segmentation_id,"},{"line_number":1287,"context_line":"                               physnet\u003dNone):"},{"line_number":1288,"context_line":"        \"\"\"Configure L2VNI mapping in NDFC fabric."}],"source_content_type":"text/x-python","patch_set":9,"id":"d1344b9e_be5ec02b","line":1285,"range":{"start_line":1285,"start_character":8,"end_line":1285,"end_character":30},"in_reply_to":"77e67fb4_cafffee8","updated":"2026-09-02 14:19:33.000000000","message":"Addressed through a _build_network_config helper and the network name is driven for the vni since everything needs to be vni backed in this model.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":1506,"context_line":"        LOG.debug(\"VLAN %s has no ports\", segmentation_id)"},{"line_number":1507,"context_line":"        return False"},{"line_number":1508,"context_line":""},{"line_number":1509,"context_line":"    def _parse_vlan_list(self, vlan_str):"},{"line_number":1510,"context_line":"        \"\"\"Parse a VLAN list string into a set of integers."},{"line_number":1511,"context_line":""},{"line_number":1512,"context_line":"        Handles formats like: \"1,10,20-25,30\" and \"none\"."},{"line_number":1513,"context_line":""},{"line_number":1514,"context_line":"        :param vlan_str: VLAN list string"},{"line_number":1515,"context_line":"        :returns: Set of VLAN IDs as integers"},{"line_number":1516,"context_line":"        \"\"\""},{"line_number":1517,"context_line":"        vlans \u003d set()"},{"line_number":1518,"context_line":"        for part in vlan_str.split(\u0027,\u0027):"},{"line_number":1519,"context_line":"            part \u003d part.strip()"},{"line_number":1520,"context_line":"            if \u0027-\u0027 in part:"},{"line_number":1521,"context_line":"                start, end \u003d part.split(\u0027-\u0027)"},{"line_number":1522,"context_line":"                vlans.update(range(int(start), int(end) + 1))"},{"line_number":1523,"context_line":"            elif part.isdigit():"},{"line_number":1524,"context_line":"                vlans.add(int(part))"},{"line_number":1525,"context_line":"        return vlans"},{"line_number":1526,"context_line":""},{"line_number":1527,"context_line":"    def _vlan_list_to_str(self, vlans):"},{"line_number":1528,"context_line":"        \"\"\"Serialise a set of VLAN IDs to a compact comma-separated string."},{"line_number":1529,"context_line":""},{"line_number":1530,"context_line":"        Sequential VLANs are collapsed into range notation, e.g."},{"line_number":1531,"context_line":"        {100, 200, 201, 202, 300} → \u0027100,200-202,300\u0027."},{"line_number":1532,"context_line":""},{"line_number":1533,"context_line":"        :param vlans: Set of VLAN IDs as integers"},{"line_number":1534,"context_line":"        :returns: Compact sorted string, or \u0027none\u0027 if empty"},{"line_number":1535,"context_line":"        \"\"\""},{"line_number":1536,"context_line":"        if not vlans:"},{"line_number":1537,"context_line":"            return \u0027none\u0027"},{"line_number":1538,"context_line":""},{"line_number":1539,"context_line":"        sorted_vlans \u003d sorted(vlans)"},{"line_number":1540,"context_line":"        parts \u003d []"},{"line_number":1541,"context_line":"        start \u003d prev \u003d sorted_vlans[0]"},{"line_number":1542,"context_line":""},{"line_number":1543,"context_line":"        for v in sorted_vlans[1:]:"},{"line_number":1544,"context_line":"            if v \u003d\u003d prev + 1:"},{"line_number":1545,"context_line":"                prev \u003d v"},{"line_number":1546,"context_line":"            else:"},{"line_number":1547,"context_line":"                parts.append(str(start) if start \u003d\u003d prev"},{"line_number":1548,"context_line":"                             else f\u0027{start}-{prev}\u0027)"},{"line_number":1549,"context_line":"                start \u003d prev \u003d v"},{"line_number":1550,"context_line":"        parts.append(str(start) if start \u003d\u003d prev else f\u0027{start}-{prev}\u0027)"},{"line_number":1551,"context_line":""},{"line_number":1552,"context_line":"        return \u0027,\u0027.join(parts)"},{"line_number":1553,"context_line":""},{"line_number":1554,"context_line":"    # Security group methods - not implemented"},{"line_number":1555,"context_line":"    def add_security_group(self, sg_id, rules):"}],"source_content_type":"text/x-python","patch_set":9,"id":"e6aa7916_81ba33a5","line":1552,"range":{"start_line":1509,"start_character":0,"end_line":1552,"end_character":30},"updated":"2026-06-12 13:09:30.000000000","message":"If we do an iteration, may want to move these out to some utils/lib package to re-use with future netmiko implementation of \"trunk_vlans_converge\" introduces in Change-Id: I1432ace9142feb1a405f9573d29222b03d290b4e.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":106,"context_line":"    if isinstance(data, list):"},{"line_number":107,"context_line":"        return any(_find_fail_recursively(item) for item in data)"},{"line_number":108,"context_line":"    if isinstance(data, str):"},{"line_number":109,"context_line":"        return \u0027fail\u0027 in data.lower()"},{"line_number":110,"context_line":"    return False"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"5322b93f_b9a8e519","line":109,"updated":"2026-09-17 10:46:25.000000000","message":"It looks like a lot of false negatives here..","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":226,"context_line":"        self.ndfc_username \u003d self.config.get(\u0027username\u0027)"},{"line_number":227,"context_line":"        self.ndfc_password \u003d self.config.get(\u0027password\u0027)"},{"line_number":228,"context_line":"        self.ndfc_fabric \u003d self.ngs_config[\u0027ndfc_fabric_name\u0027]"},{"line_number":229,"context_line":"        self.verify_ssl \u003d strutils.bool_from_string("},{"line_number":230,"context_line":"            self.ngs_config[\u0027ngs_verify_ssl\u0027])"},{"line_number":231,"context_line":"        self.ndfc_timeout \u003d int(self.ngs_config[\u0027ndfc_timeout\u0027])"},{"line_number":232,"context_line":"        # Session pool sized by ngs_max_connections, bounds per-NDFC not"}],"source_content_type":"text/x-python","patch_set":15,"id":"dec508a6_31867c7d","line":229,"updated":"2026-09-17 10:46:25.000000000","message":"nit: tls","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":301,"context_line":"                    \u0027token\u0027: None,"},{"line_number":302,"context_line":"                    \u0027lock\u0027: threading.Lock()"},{"line_number":303,"context_line":"                }"},{"line_number":304,"context_line":"            return _NDFC_SESSION_POOL[self._session_key]"},{"line_number":305,"context_line":""},{"line_number":306,"context_line":"    def _ensure_authenticated(self):"},{"line_number":307,"context_line":"        \"\"\"Ensure we have a valid authenticated session."}],"source_content_type":"text/x-python","patch_set":15,"id":"a1b03b16_2ccfa912","line":304,"updated":"2026-09-17 10:46:25.000000000","message":"You\u0027re returning a mutable object here that _invalidate_token (for example) will modify concurrently. It would be fine(ish) if it was always used with \u0027lock\u0027, but it isn\u0027t.","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":301,"context_line":"                    \u0027token\u0027: None,"},{"line_number":302,"context_line":"                    \u0027lock\u0027: threading.Lock()"},{"line_number":303,"context_line":"                }"},{"line_number":304,"context_line":"            return _NDFC_SESSION_POOL[self._session_key]"},{"line_number":305,"context_line":""},{"line_number":306,"context_line":"    def _ensure_authenticated(self):"},{"line_number":307,"context_line":"        \"\"\"Ensure we have a valid authenticated session."}],"source_content_type":"text/x-python","patch_set":15,"id":"e01bfad8_28ec728d","line":304,"in_reply_to":"a1b03b16_2ccfa912","updated":"2026-10-16 20:03:56.000000000","message":"Acknowledged","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":350,"context_line":""},{"line_number":351,"context_line":"        adapter \u003d HTTPAdapter("},{"line_number":352,"context_line":"            max_retries\u003dretry_strategy,"},{"line_number":353,"context_line":"            pool_connections\u003dself.ndfc_max_connections,"},{"line_number":354,"context_line":"            pool_maxsize\u003dself.ndfc_max_connections"},{"line_number":355,"context_line":"        )"},{"line_number":356,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"61db913d_a3e0a35c","line":353,"updated":"2026-09-17 10:46:25.000000000","message":"nit: I\u0027m curious why setting pool_maxsize is not enough.","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":446,"context_line":"                    \"NDFC API %s %s returned success status but \""},{"line_number":447,"context_line":"                    \"response indicates failure: %s\","},{"line_number":448,"context_line":"                    method, endpoint, result)"},{"line_number":449,"context_line":"                raise exc.GenericSwitchNDFCConfigError()"},{"line_number":450,"context_line":"            return result"},{"line_number":451,"context_line":"        LOG.debug(\"NDFC response: %s %s status\u003d%s (no body)\","},{"line_number":452,"context_line":"                  method, url, response.status_code)"}],"source_content_type":"text/x-python","patch_set":15,"id":"bffcc2d3_060b3cdc","line":449,"updated":"2026-09-17 10:46:25.000000000","message":"It\u0027s not great that we raise exception with zero details. Can we extract something useful?","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":446,"context_line":"                    \"NDFC API %s %s returned success status but \""},{"line_number":447,"context_line":"                    \"response indicates failure: %s\","},{"line_number":448,"context_line":"                    method, endpoint, result)"},{"line_number":449,"context_line":"                raise exc.GenericSwitchNDFCConfigError()"},{"line_number":450,"context_line":"            return result"},{"line_number":451,"context_line":"        LOG.debug(\"NDFC response: %s %s status\u003d%s (no body)\","},{"line_number":452,"context_line":"                  method, url, response.status_code)"}],"source_content_type":"text/x-python","patch_set":15,"id":"f3b1230a_2d42516c","line":449,"in_reply_to":"bffcc2d3_060b3cdc","updated":"2026-10-16 20:03:56.000000000","message":"Done","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":500,"context_line":"        self._ensure_authenticated()"},{"line_number":501,"context_line":""},{"line_number":502,"context_line":"        # Get shared session from pool"},{"line_number":503,"context_line":"        pool_entry \u003d self._get_session_pool_entry()"},{"line_number":504,"context_line":"        session \u003d pool_entry[\u0027session\u0027]"},{"line_number":505,"context_line":""},{"line_number":506,"context_line":"        # First attempt"}],"source_content_type":"text/x-python","patch_set":15,"id":"ec5c8bff_ec405419","line":503,"updated":"2026-09-17 10:46:25.000000000","message":"You\u0027re using a shared mutable object without locking here","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":500,"context_line":"        self._ensure_authenticated()"},{"line_number":501,"context_line":""},{"line_number":502,"context_line":"        # Get shared session from pool"},{"line_number":503,"context_line":"        pool_entry \u003d self._get_session_pool_entry()"},{"line_number":504,"context_line":"        session \u003d pool_entry[\u0027session\u0027]"},{"line_number":505,"context_line":""},{"line_number":506,"context_line":"        # First attempt"}],"source_content_type":"text/x-python","patch_set":15,"id":"a4801202_68d9eb48","line":503,"in_reply_to":"ec5c8bff_ec405419","updated":"2026-10-16 20:03:56.000000000","message":"Acknowledged","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":514,"context_line":"            if not self._is_auth_error(e):"},{"line_number":515,"context_line":"                detail \u003d self._http_error_detail(e)"},{"line_number":516,"context_line":"                LOG.error(\"NDFC API error: %s\", detail if detail else e)"},{"line_number":517,"context_line":"                raise exc.GenericSwitchNDFCConfigError() from e"},{"line_number":518,"context_line":""},{"line_number":519,"context_line":"            # HTTPError from raise_for_status() always carries a response."},{"line_number":520,"context_line":"            status \u003d e.response.status_code"}],"source_content_type":"text/x-python","patch_set":15,"id":"6f86f3a7_e9adbaca","line":517,"updated":"2026-09-17 10:46:25.000000000","message":"same","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":514,"context_line":"            if not self._is_auth_error(e):"},{"line_number":515,"context_line":"                detail \u003d self._http_error_detail(e)"},{"line_number":516,"context_line":"                LOG.error(\"NDFC API error: %s\", detail if detail else e)"},{"line_number":517,"context_line":"                raise exc.GenericSwitchNDFCConfigError() from e"},{"line_number":518,"context_line":""},{"line_number":519,"context_line":"            # HTTPError from raise_for_status() always carries a response."},{"line_number":520,"context_line":"            status \u003d e.response.status_code"}],"source_content_type":"text/x-python","patch_set":15,"id":"acbc3da4_c53c470d","line":517,"in_reply_to":"6f86f3a7_e9adbaca","updated":"2026-10-16 20:03:56.000000000","message":"Done","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":579,"context_line":"        except exc.GenericSwitchNDFCConfigError as e:"},{"line_number":580,"context_line":"            LOG.debug(\"Failed to query network attachments for %s: %s\","},{"line_number":581,"context_line":"                      network_name, e)"},{"line_number":582,"context_line":"            return {}"},{"line_number":583,"context_line":""},{"line_number":584,"context_line":"    def _set_vlan_vni_mapping(self, switch_serial, segmentation_id, vni,"},{"line_number":585,"context_line":"                              vni_value\u003dNone):"}],"source_content_type":"text/x-python","patch_set":15,"id":"ee78d3f2_81c1f77e","line":582,"updated":"2026-09-17 10:46:25.000000000","message":"This approach makes it impossible to handle error message on the higher levels. Is there a reason why it\u0027s not fatal?","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":579,"context_line":"        except exc.GenericSwitchNDFCConfigError as e:"},{"line_number":580,"context_line":"            LOG.debug(\"Failed to query network attachments for %s: %s\","},{"line_number":581,"context_line":"                      network_name, e)"},{"line_number":582,"context_line":"            return {}"},{"line_number":583,"context_line":""},{"line_number":584,"context_line":"    def _set_vlan_vni_mapping(self, switch_serial, segmentation_id, vni,"},{"line_number":585,"context_line":"                              vni_value\u003dNone):"}],"source_content_type":"text/x-python","patch_set":15,"id":"b14f5589_c3c75207","line":582,"in_reply_to":"ee78d3f2_81c1f77e","updated":"2026-10-16 20:03:56.000000000","message":"Acknowledged","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":652,"context_line":"                    return iface.get(\u0027nvPairs\u0027, {})"},{"line_number":653,"context_line":"        except exc.GenericSwitchNDFCConfigError as e:"},{"line_number":654,"context_line":"            LOG.debug(\"Failed to query interface nvPairs for %s:%s: %s\","},{"line_number":655,"context_line":"                      switch_serial, port, e)"},{"line_number":656,"context_line":"        return {}"},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    def _get_interface_allowed_vlans(self, switch_serial, port):"}],"source_content_type":"text/x-python","patch_set":15,"id":"dbe3d9dd_05cbb49c","line":655,"updated":"2026-09-17 10:46:25.000000000","message":"Same re error handling","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":652,"context_line":"                    return iface.get(\u0027nvPairs\u0027, {})"},{"line_number":653,"context_line":"        except exc.GenericSwitchNDFCConfigError as e:"},{"line_number":654,"context_line":"            LOG.debug(\"Failed to query interface nvPairs for %s:%s: %s\","},{"line_number":655,"context_line":"                      switch_serial, port, e)"},{"line_number":656,"context_line":"        return {}"},{"line_number":657,"context_line":""},{"line_number":658,"context_line":"    def _get_interface_allowed_vlans(self, switch_serial, port):"}],"source_content_type":"text/x-python","patch_set":15,"id":"fa0b2ff7_b436486d","line":655,"in_reply_to":"dbe3d9dd_05cbb49c","updated":"2026-10-16 20:03:56.000000000","message":"Acknowledged","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":1005,"context_line":"            )"},{"line_number":1006,"context_line":"        except exc.GenericSwitchNDFCConfigError as e:"},{"line_number":1007,"context_line":"            LOG.debug(\"Failed to detach switch from network %s: %s\","},{"line_number":1008,"context_line":"                      network_name, e)"},{"line_number":1009,"context_line":""},{"line_number":1010,"context_line":"        # Delete the network object from the fabric"},{"line_number":1011,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":15,"id":"d1a06d86_a04bd194","line":1008,"updated":"2026-09-17 10:46:25.000000000","message":"This is a potentially dangerous condition to ignore. It may mean that the node stays connected to the tenant network, for example.","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":1005,"context_line":"            )"},{"line_number":1006,"context_line":"        except exc.GenericSwitchNDFCConfigError as e:"},{"line_number":1007,"context_line":"            LOG.debug(\"Failed to detach switch from network %s: %s\","},{"line_number":1008,"context_line":"                      network_name, e)"},{"line_number":1009,"context_line":""},{"line_number":1010,"context_line":"        # Delete the network object from the fabric"},{"line_number":1011,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":15,"id":"7cced823_cfa527a3","line":1008,"in_reply_to":"d1a06d86_a04bd194","updated":"2026-10-16 20:03:56.000000000","message":"Done","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":1042,"context_line":"                str(sp[\u0027segmentation_id\u0027])"},{"line_number":1043,"context_line":"                for sp in trunk_details.get(\u0027sub_ports\u0027, [])"},{"line_number":1044,"context_line":"            ]"},{"line_number":1045,"context_line":"            LOG.info(\"Configuring port %s as trunk: native VLAN %s, \""},{"line_number":1046,"context_line":"                     \"sub-port VLANs %s on %s\","},{"line_number":1047,"context_line":"                     port, segmentation_id, sub_port_vlans, switch_serial)"},{"line_number":1048,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"1f9dede7_22b21fb8","line":1045,"updated":"2026-09-17 10:46:25.000000000","message":"s/info/debug/","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":1042,"context_line":"                str(sp[\u0027segmentation_id\u0027])"},{"line_number":1043,"context_line":"                for sp in trunk_details.get(\u0027sub_ports\u0027, [])"},{"line_number":1044,"context_line":"            ]"},{"line_number":1045,"context_line":"            LOG.info(\"Configuring port %s as trunk: native VLAN %s, \""},{"line_number":1046,"context_line":"                     \"sub-port VLANs %s on %s\","},{"line_number":1047,"context_line":"                     port, segmentation_id, sub_port_vlans, switch_serial)"},{"line_number":1048,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"2f10498e_370bb869","line":1045,"in_reply_to":"1f9dede7_22b21fb8","updated":"2026-10-16 20:03:56.000000000","message":"Done","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":1104,"context_line":"                str(sp[\u0027segmentation_id\u0027])"},{"line_number":1105,"context_line":"                for sp in trunk_details.get(\u0027sub_ports\u0027, [])"},{"line_number":1106,"context_line":"            ]"},{"line_number":1107,"context_line":"            LOG.info(\"Removing trunk VLANs from port %s: native %s, \""},{"line_number":1108,"context_line":"                     \"sub-ports %s on %s\","},{"line_number":1109,"context_line":"                     port, segmentation_id, sub_port_vlans, switch_serial)"},{"line_number":1110,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"cd776525_8e0a34a1","line":1107,"updated":"2026-09-17 10:46:25.000000000","message":"s/info/debug/","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":1104,"context_line":"                str(sp[\u0027segmentation_id\u0027])"},{"line_number":1105,"context_line":"                for sp in trunk_details.get(\u0027sub_ports\u0027, [])"},{"line_number":1106,"context_line":"            ]"},{"line_number":1107,"context_line":"            LOG.info(\"Removing trunk VLANs from port %s: native %s, \""},{"line_number":1108,"context_line":"                     \"sub-ports %s on %s\","},{"line_number":1109,"context_line":"                     port, segmentation_id, sub_port_vlans, switch_serial)"},{"line_number":1110,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"d6edbf56_fe950dcc","line":1107,"in_reply_to":"cd776525_8e0a34a1","updated":"2026-10-16 20:03:56.000000000","message":"Done","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"3cc3ea0f9baf87857d93f8525005cb0b3972f63c","unresolved":true,"context_lines":[{"line_number":1278,"context_line":"            # Idempotency: _find_fail_recursively triggered on the 207 body"},{"line_number":1279,"context_line":"            # because it contains \u0027failed\u0027 in the status field. Log and"},{"line_number":1280,"context_line":"            # continue — if the network genuinely failed to create, the"},{"line_number":1281,"context_line":"            # subsequent config policy call will also fail with a clear error."},{"line_number":1282,"context_line":"            LOG.debug(\"Network %s already exists or creation failed, \""},{"line_number":1283,"context_line":"                      \"continuing\", network_name)"},{"line_number":1284,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"1bdf960f_a9b16a93","line":1281,"updated":"2026-09-17 10:46:25.000000000","message":"Hmm, will it actually be clear that the creation failed or we\u0027ll get something like \"Network not found\"?","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"},{"author":{"_account_id":5890,"name":"Doug Goldstein","email":"cardoe@cardoe.com","username":"cardoe"},"change_message_id":"fb6b98bf888b74ecbcdd04707fbaf227fd3c4bf3","unresolved":false,"context_lines":[{"line_number":1278,"context_line":"            # Idempotency: _find_fail_recursively triggered on the 207 body"},{"line_number":1279,"context_line":"            # because it contains \u0027failed\u0027 in the status field. Log and"},{"line_number":1280,"context_line":"            # continue — if the network genuinely failed to create, the"},{"line_number":1281,"context_line":"            # subsequent config policy call will also fail with a clear error."},{"line_number":1282,"context_line":"            LOG.debug(\"Network %s already exists or creation failed, \""},{"line_number":1283,"context_line":"                      \"continuing\", network_name)"},{"line_number":1284,"context_line":""}],"source_content_type":"text/x-python","patch_set":15,"id":"ce08daf4_45f4527d","line":1281,"in_reply_to":"1bdf960f_a9b16a93","updated":"2026-10-16 20:03:56.000000000","message":"Acknowledged","commit_id":"647dfc708a7881e80cc7d235f4f0732c1f81ef7e"}],"networking_generic_switch/tests/unit/ndfc/test_cisco_ndfc.py":[{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":9,"id":"5a1325e2_95a77678","updated":"2026-06-12 13:09:30.000000000","message":"We could remove quite a bit of repetition by setting up the _get_switch_serial and _ndfc_request patches in setUp, and a common BASE_DEVICE_CFG with the common config keys pre-set.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"263aea8f05b821c0058f85b4569bbf5020a28eed","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":9,"id":"186c0215_986a06b4","in_reply_to":"5a1325e2_95a77678","updated":"2026-09-02 14:23:42.000000000","message":"Done","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":237,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_ndfc_request\u0027, autospec\u003dTrue)"},{"line_number":238,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_get_switch_serial\u0027, autospec\u003dTrue)"},{"line_number":239,"context_line":"    def test_add_network_with_trunk_ports("},{"line_number":240,"context_line":"            self, mock_serial, mock_request, mock_deploy):"},{"line_number":241,"context_line":"        \"\"\"Test add_network configures trunk ports via interface policy.\"\"\""},{"line_number":242,"context_line":"        mock_serial.return_value \u003d \u0027ABC1234567\u0027"},{"line_number":243,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"d6de756d_a8a70e8f","line":240,"range":{"start_line":240,"start_character":31,"end_line":240,"end_character":43},"updated":"2026-06-12 13:09:30.000000000","message":"May want to make this mock return existing vlans on the port, to cover appending to existing?","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"263aea8f05b821c0058f85b4569bbf5020a28eed","unresolved":true,"context_lines":[{"line_number":237,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_ndfc_request\u0027, autospec\u003dTrue)"},{"line_number":238,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_get_switch_serial\u0027, autospec\u003dTrue)"},{"line_number":239,"context_line":"    def test_add_network_with_trunk_ports("},{"line_number":240,"context_line":"            self, mock_serial, mock_request, mock_deploy):"},{"line_number":241,"context_line":"        \"\"\"Test add_network configures trunk ports via interface policy.\"\"\""},{"line_number":242,"context_line":"        mock_serial.return_value \u003d \u0027ABC1234567\u0027"},{"line_number":243,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"4ab6eb99_9ee896cf","line":240,"range":{"start_line":240,"start_character":31,"end_line":240,"end_character":43},"in_reply_to":"d6de756d_a8a70e8f","updated":"2026-09-02 14:23:42.000000000","message":"Given the model of the testing, yes, we ought to ensure that we\u0027re matching the pattern of behavior in the code.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":24245,"name":"Harald Jensås","email":"hjensas@redhat.com","username":"harald.jensas"},"change_message_id":"e7531e73f41b2095dab07509561772748b747e5d","unresolved":true,"context_lines":[{"line_number":945,"context_line":""},{"line_number":946,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_ndfc_request\u0027, autospec\u003dTrue)"},{"line_number":947,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_get_switch_serial\u0027, autospec\u003dTrue)"},{"line_number":948,"context_line":"    def test_plug_switch_to_network_idempotent("},{"line_number":949,"context_line":"            self, mock_serial, mock_request):"},{"line_number":950,"context_line":"        \"\"\"Test L2VNI creation is idempotent when network exists.\"\"\""},{"line_number":951,"context_line":"        mock_serial.return_value \u003d \u0027ABC1234567\u0027"}],"source_content_type":"text/x-python","patch_set":9,"id":"c269dd02_90d51926","line":948,"range":{"start_line":948,"start_character":8,"end_line":948,"end_character":46},"updated":"2026-06-12 13:09:30.000000000","message":"unsure about test name, is it really testing idempotency? It just verfies the same calls happen at each invocation.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"817891e32844accf30fb3d86f8fa71fad46f45ed","unresolved":false,"context_lines":[{"line_number":945,"context_line":""},{"line_number":946,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_ndfc_request\u0027, autospec\u003dTrue)"},{"line_number":947,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_get_switch_serial\u0027, autospec\u003dTrue)"},{"line_number":948,"context_line":"    def test_plug_switch_to_network_idempotent("},{"line_number":949,"context_line":"            self, mock_serial, mock_request):"},{"line_number":950,"context_line":"        \"\"\"Test L2VNI creation is idempotent when network exists.\"\"\""},{"line_number":951,"context_line":"        mock_serial.return_value \u003d \u0027ABC1234567\u0027"}],"source_content_type":"text/x-python","patch_set":9,"id":"dcff6a3e_5de33c73","line":948,"range":{"start_line":948,"start_character":8,"end_line":948,"end_character":46},"in_reply_to":"c269dd02_90d51926","updated":"2026-09-18 20:53:30.000000000","message":"Dropping this test.","commit_id":"b43a60ec7e8b23aa672ae21b1f37db0090d41bf8"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"263aea8f05b821c0058f85b4569bbf5020a28eed","unresolved":true,"context_lines":[{"line_number":945,"context_line":"        self.switch.plug_switch_to_network(vni\u003d5000, segmentation_id\u003d100)"},{"line_number":946,"context_line":"        self.switch.plug_switch_to_network(vni\u003d5000, segmentation_id\u003d100)"},{"line_number":947,"context_line":""},{"line_number":948,"context_line":"        # 3 calls per invocation \u003d 6 total"},{"line_number":949,"context_line":"        self.assertEqual(mock_request.call_count, 6)"},{"line_number":950,"context_line":""},{"line_number":951,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_ndfc_request\u0027, autospec\u003dTrue)"},{"line_number":952,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_get_switch_serial\u0027, autospec\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":14,"id":"d56cafd5_d354e378","line":949,"range":{"start_line":948,"start_character":0,"end_line":949,"end_character":52},"updated":"2026-09-02 14:23:42.000000000","message":"So going back to harald\u0027s prior comment on patchset 9, the test as written is only looking at the call count to dtermine nothing has actually been changed. The test needs to look at the substance of the calls to verify if its repeated/idempotent properly.","commit_id":"4d20bfbc04993b1c1f1e9cbeeccad3982167b9eb"},{"author":{"_account_id":11655,"name":"Julia Kreger","email":"juliaashleykreger@gmail.com","username":"jkreger","status":"Flying to the moon with a Jetpack!"},"change_message_id":"817891e32844accf30fb3d86f8fa71fad46f45ed","unresolved":false,"context_lines":[{"line_number":945,"context_line":"        self.switch.plug_switch_to_network(vni\u003d5000, segmentation_id\u003d100)"},{"line_number":946,"context_line":"        self.switch.plug_switch_to_network(vni\u003d5000, segmentation_id\u003d100)"},{"line_number":947,"context_line":""},{"line_number":948,"context_line":"        # 3 calls per invocation \u003d 6 total"},{"line_number":949,"context_line":"        self.assertEqual(mock_request.call_count, 6)"},{"line_number":950,"context_line":""},{"line_number":951,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_ndfc_request\u0027, autospec\u003dTrue)"},{"line_number":952,"context_line":"    @mock.patch.object(cisco.CiscoNDFC, \u0027_get_switch_serial\u0027, autospec\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":14,"id":"98f3529e_39d3b497","line":949,"range":{"start_line":948,"start_character":0,"end_line":949,"end_character":52},"in_reply_to":"d56cafd5_d354e378","updated":"2026-09-18 20:53:30.000000000","message":"Dropped this test.","commit_id":"4d20bfbc04993b1c1f1e9cbeeccad3982167b9eb"}]}
