From d7a6f821487bab8f3b3bdcb3dced47b572770675 Mon Sep 17 00:00:00 2001 From: Steve Keay Date: Fri, 30 Aug 2024 23:55:36 +0100 Subject: [PATCH] Update Nautobot Interface not Device for provisioning mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used to flip a bit on the nautobot Device object for “connected_to_network” when changing a device from/to “provisioning” and “tenant” settings. We need this to be interface specific. Because of Ironic's knowlege of the interface that is being used for PXE boot, we are called with a server interface UUID. We update the nautobot status field of connected switch interface. This tells undersync which mode the port should be in - provisioning or tenant (normal). We also make a change to the switch IDs that are passed to undersync. This used to represnt the set of all switches to which the server is connected. This is sub-optimal if there are multiple fabrics connected to the same server. We drop this logic and instead just pass a single switch ID, which is the switch where PXE is happening. Undersync will always update both switches in the VPC pair (VLAN GROUP) in any case - passing the extra switch IDs was redundant. --- .../main/undersync_device.py | 42 +++++++++++-------- .../understack_workflows/nautobot.py | 23 ++++++++++ 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/python/understack-workflows/understack_workflows/main/undersync_device.py b/python/understack-workflows/understack_workflows/main/undersync_device.py index c17cb773a..f4fb5fdda 100644 --- a/python/understack-workflows/understack_workflows/main/undersync_device.py +++ b/python/understack-workflows/understack_workflows/main/undersync_device.py @@ -12,26 +12,32 @@ logger = setup_logger(__name__) +network_name_status = { + "tenant": "Active", + "provisioning": "Provisioning Interface" +} -def update_nautobot(args) -> list[str]: - device_uuid = args.device_id - field_name = "connected_to_network" - field_value = args.network_name - nb_url = args.nautobot_url +def update_nautobot(args) -> UUID: + device_id = args.device_id + interface_id = args.interface_id + network_name = args.network_name + nb_url = args.nautobot_url nb_token = args.nautobot_token or credential("nb-token", "token") + + new_status = network_name_status[args.network_name] + nautobot = Nautobot(nb_url, nb_token, logger=logger) - logger.info( - f"Updating Device {device_uuid} and moving it to '{field_value}' network." - ) - nautobot.update_cf(device_uuid, field_name, field_value) - logger.debug(f"Updated Device.{field_name} to {field_value}") - switches = nautobot.uplink_switches(device_uuid) - logger.info(f"Obtained switch IDs: {switches}") - return switches + logger.info(f"Updating Nautobot {device_id=!s} {interface_id=!s} {network_name=}") + interface = nautobot.update_switch_interface_status(interface_id, new_status) + logger.info(f"Updated Nautobot {device_id=!s} {interface_id=!s} {network_name=}") + + switch_id = interface.device.id + logger.info(f"Interface connected to switch {switch_id!s}") + return switch_id -def call_undersync(args, switches): +def call_undersync(args, switch_id: UUID): undersync_token = credential("undersync", "token") if not undersync_token: logger.error("Please provide auth token for Undersync.") @@ -39,7 +45,7 @@ def call_undersync(args, switches): undersync = Undersync(undersync_token) try: - return undersync.sync_devices(switches, dry_run=args.dry_run, force=args.force) + return undersync.sync_devices([switch_id], dry_run=args.dry_run, force=args.force) except Exception as error: logger.error(error) sys.exit(2) @@ -54,7 +60,7 @@ def argument_parser(): "--interface-id", type=UUID, required=True, help="Nautobot interface UUID" ) parser.add_argument( - "--device-id", type=UUID, required=True, help="Nautobot device UUID" + "--device-id", type=UUID, required=False, help="Nautobot device UUID" ) parser.add_argument("--network-name", required=True) parser = parser_nautobot_args(parser) @@ -83,8 +89,8 @@ def main(): """ args = argument_parser().parse_args() - switches = update_nautobot(args) - response = call_undersync(args, switches) + switch_id = update_nautobot(args) + response = call_undersync(args, switch_id) logger.info(f"Undersync returned: {response.json()}") diff --git a/python/understack-workflows/understack_workflows/nautobot.py b/python/understack-workflows/understack_workflows/nautobot.py index 2349332e0..8e841f8e6 100644 --- a/python/understack-workflows/understack_workflows/nautobot.py +++ b/python/understack-workflows/understack_workflows/nautobot.py @@ -110,6 +110,13 @@ def device_by_id(self, device_id: UUID) -> NautobotDevice: self.exit_with_error(f"Device {device_id!s} not found in Nautobot") return device + def interface_by_id(self, interface_id: UUID) -> NautobotInterface: + interface = self.session.dcim.interfaces.get(interface_id) + if not interface: + self.exit_with_error(f"Interface {interface_id!s} not found in Nautobot") + return interface + + def device_interfaces(self, device_id: UUID): return self.session.dcim.interfaces.filter(device_id=device_id) @@ -120,6 +127,22 @@ def update_cf(self, device_id: UUID, field_name: str, field_value: str): self.logger.info(f"save result: {response}") return response + def update_switch_interface_status(self, server_interface_id: UUID, new_status: str) -> NautobotInterface: + server_interface = self.interface_by_id(server_interface_id) + connected_endpoint = server_interface.connected_endpoint + if not connected_endpoint: + raise Exception("Interface {server_interface_id} not connected in Nautobot") + switch_interface_id = connected_endpoint.id + self.logger.debug(f"Int {server_interface_id} connects to {switch_interface_id}") + switch_interface = self.interface_by_id(switch_interface_id) + switch_interface.status = new_status + result = switch_interface.save() + + self.logger.debug( + f"Interface {switch_interface_id} updated to Status {new_status} {result=}" + ) + return switch_interface + def update_device_status(self, device_id: UUID, device_status: str): device = self.device_by_id(device_id) device.status = device_status