Skip to content

kubectl us-net router audit: close one-directional coverage gaps #2342

Description

@cardoe

Follow-up from review of the router audit / router repair commands added for #2330.

Each item below is a case where the audit inspects state in only one direction, or omits a field, so real drift passes clean. They are the same class of bug and could land as one change. Line references are against python/kubectl-us-net/us_net/commands/router_health.py.

1. Stale HA_Chassis members in otherwise-live groups are PASS and never cleaned

_audit_network_ha_chassis_groups computes stale_names but only uses it in the FAIL branch. As soon as one live member exists the group is reported PASS and the stale members are not mentioned. _ha_chassis_group_repair_operations only populates remove_member_uuids for groups with zero live members, so no cleanup happens either.

tests/test_router_health.py::test_audit_loads_southbound_chassis_once encodes exactly this state (one live member, one dead) and asserts exit 0.

This is also the blocker for retiring phase 1 of scripts/cleanup_dead_ovn_ha_chassis.py.

2. Orphaned uplink-* LSPs are invisible

_audit_network_uplink starts from Neutron uplink-* ports and looks up the matching LSP, so an uplink-* LSP present in the OVN NB DB with no corresponding Neutron port is never reported. That exact condition is what scripts/cleanup_orphaned_ovn_uplinks.py exists to detect.

The equivalent OVN-to-Neutron direction is already covered for router ports (the orphaned LRP / orphaned peer LSP findings). Uplinks need the same treatment.

3. The shared uplink port's UUID-named LSP is never audited

Each uplink has two OVN objects:

  • the raw localnet LSP named uplink-<segment_id>, created by create_uplink_port in python/neutron-understack/neutron_understack/routers.py
  • the shared Neutron port's own LSP, named by port UUID, which needs the explicit delete_shared_port_lsp teardown path

_audit_network_uplink looks the LSP up by the Neutron port's name, so only the first is ever checked. The second is the one that leaks. The port UUID is already in hand at that point.

Worth a comment while in there: the name-based lookup works only because the localnet LSP and the shared Neutron port coincidentally share the uplink-<segment_id> string. That is load-bearing and non-obvious.

4. options:network_name on the uplink localnet LSP is unchecked

create_uplink_port sets options:network_name to the physnet, alongside the mcast/FDB options. The audit checks type, addresses and the VLAN tag but not network_name — the field that actually maps the localnet to physical hardware. A wrong or missing physnet is silent breakage.

Known trade-off, not a task

_network_uplink_ports issues one conn.network.ports(network_id=...) per router network and filters by name prefix client-side, so a single-router audit pulls every port on each attached network — potentially thousands on a busy external network. Neutron has no name-prefix filter, so there is no clean API-side fix. Recording it as a deliberate trade-off.

Lower priority

_router_ports accepts the three ML2/OVS-migrated interface device owners (network:router_interface_distributed, network:ha_router_replicated_interface, network:router_ha_interface), but neutron-understack's is_router_interface only covers network:router_interface and network:router_gateway, so no uplink is ever created for those. A migrated port would report expected exactly one uplink-* Neutron port, found none. Migrated environments only.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions