From 567a75fac0cd48cd078aaf3db5a88c92a450889b Mon Sep 17 00:00:00 2001 From: Jan Horstmann Date: Fri, 13 Feb 2026 16:04:03 +0100 Subject: [PATCH] Fix listing of sonic devices The command `osism sonic list` requires the `NETBOX_FILTER_CONDUCTOR_SONIC` setting, which is not available in the osismclient container. Therefore the retrieval of devices from the netbox is moved into its own task executed in the conductor, where the parameter is set. Signed-off-by: Jan Horstmann --- osism/commands/sonic.py | 51 +++++-------------------- osism/tasks/conductor/__init__.py | 7 ++++ osism/tasks/conductor/sonic/__init__.py | 2 + osism/tasks/conductor/sonic/device.py | 50 ++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 41 deletions(-) diff --git a/osism/commands/sonic.py b/osism/commands/sonic.py index 3cb1ff3b..54e02be6 100644 --- a/osism/commands/sonic.py +++ b/osism/commands/sonic.py @@ -12,12 +12,11 @@ from tabulate import tabulate from osism import utils -from osism.tasks import netbox +from osism.tasks import netbox, conductor from osism.tasks.conductor.netbox import ( - get_nb_device_query_list_sonic, get_device_oob_ip, ) -from osism.tasks.conductor.sonic.constants import DEFAULT_SONIC_ROLES, SUPPORTED_HWSKUS +from osism.tasks.conductor.sonic.constants import SUPPORTED_HWSKUS from osism.utils.ssh import ( cleanup_ssh_known_hosts_for_node, ensure_known_hosts_file, @@ -1068,6 +1067,7 @@ def get_parser(self, prog_name): parser.add_argument( "device", nargs="?", + default=None, type=str, help="Optional device name to filter by (same as sonic sync parameter)", ) @@ -1077,44 +1077,13 @@ def take_action(self, parsed_args): device_name = parsed_args.device try: - devices = [] - - if device_name: - # When specific device is requested, fetch it directly - try: - device = utils.nb.dcim.devices.get(name=device_name) - if device: - # Check if device role matches allowed roles - if device.role and device.role.slug in DEFAULT_SONIC_ROLES: - devices.append(device) - logger.debug( - f"Found device: {device.name} with role: {device.role.slug}" - ) - else: - logger.warning( - f"Device {device_name} has role '{device.role.slug if device.role else 'None'}' " - f"which is not in allowed SONiC roles: {', '.join(DEFAULT_SONIC_ROLES)}" - ) - return 1 - else: - logger.error(f"Device {device_name} not found in NetBox") - return 1 - except Exception as e: - logger.error(f"Error fetching device {device_name}: {e}") - return 1 - else: - # Get device query list from NETBOX_FILTER_CONDUCTOR_SONIC - nb_device_query_list = get_nb_device_query_list_sonic() - - for nb_device_query in nb_device_query_list: - # Query devices with the NETBOX_FILTER_CONDUCTOR_SONIC criteria - for device in utils.nb.dcim.devices.filter(**nb_device_query): - # Check if device role matches allowed roles - if device.role and device.role.slug in DEFAULT_SONIC_ROLES: - devices.append(device) - logger.debug( - f"Found device: {device.name} with role: {device.role.slug}" - ) + task = conductor.get_sonic_devices.delay(device_name=device_name) + devices = task.wait() + if isinstance(devices, type(None)): + logger.error( + "Error listing SONiC devices. Check the conductor log for details" + ) + return 1 logger.info(f"Found {len(devices)} devices matching criteria") diff --git a/osism/tasks/conductor/__init__.py b/osism/tasks/conductor/__init__.py index 94897d4d..8542a445 100644 --- a/osism/tasks/conductor/__init__.py +++ b/osism/tasks/conductor/__init__.py @@ -10,6 +10,7 @@ from osism.tasks.conductor.ironic import sync_ironic as _sync_ironic from osism.tasks.conductor.redfish import get_resources as _get_redfish_resources from osism.tasks.conductor.sonic import sync_sonic as _sync_sonic +from osism.tasks.conductor.sonic import get_devices as _get_sonic_devices # App configuration @@ -69,10 +70,16 @@ def get_redfish_resources(self, hostname, resource_type): return _get_redfish_resources(hostname, resource_type) +@app.task(bind=True, name="osism.tasks.conductor.get_sonic_devices") +def get_sonic_devices(self, device_name=None): + return _get_sonic_devices(device_name) + + __all__ = [ "app", "get_ironic_parameters", "get_redfish_resources", + "get_sonic_devices", "sync_netbox", "sync_ironic", "sync_sonic", diff --git a/osism/tasks/conductor/sonic/__init__.py b/osism/tasks/conductor/sonic/__init__.py index 3bb23cea..97a10b7d 100644 --- a/osism/tasks/conductor/sonic/__init__.py +++ b/osism/tasks/conductor/sonic/__init__.py @@ -5,6 +5,7 @@ from .config_generator import generate_sonic_config from .exporter import save_config_to_netbox, export_config_to_file from .sync import sync_sonic +from .device import get_devices from .connections import ( get_connected_interfaces, get_connected_device_for_sonic_interface, @@ -23,4 +24,5 @@ "get_connected_device_via_interface", "find_interconnected_devices", "get_device_bgp_neighbors_via_loopback", + "get_devices", ] diff --git a/osism/tasks/conductor/sonic/device.py b/osism/tasks/conductor/sonic/device.py index 03020e07..d092ce79 100644 --- a/osism/tasks/conductor/sonic/device.py +++ b/osism/tasks/conductor/sonic/device.py @@ -5,6 +5,8 @@ from loguru import logger from osism import utils +from osism.tasks.conductor.netbox import get_nb_device_query_list_sonic +from osism.tasks.conductor.sonic.constants import DEFAULT_SONIC_ROLES def get_device_platform(device, hwsku): @@ -80,3 +82,51 @@ def get_device_mac_address(device): logger.warning(f"Could not get MAC address for device {device.name}: {e}") return mac_address + + +def get_devices(self, device_name=None): + try: + devices = [] + + if device_name: + # When specific device is requested, fetch it directly + try: + device = utils.nb.dcim.devices.get(name=device_name) + if device: + # Check if device role matches allowed roles + if device.role and device.role.slug in DEFAULT_SONIC_ROLES: + devices.append(device) + logger.debug( + f"Found device: {device.name} with role: {device.role.slug}" + ) + else: + logger.warning( + f"Device {device_name} has role '{device.role.slug if device.role else 'None'}' " + f"which is not in allowed SONiC roles: {', '.join(DEFAULT_SONIC_ROLES)}" + ) + return 1 + else: + logger.error(f"Device {device_name} not found in NetBox") + return 1 + except Exception as e: + logger.error(f"Error fetching device {device_name}: {e}") + return 1 + else: + # Get device query list from NETBOX_FILTER_CONDUCTOR_SONIC + nb_device_query_list = get_nb_device_query_list_sonic() + + for nb_device_query in nb_device_query_list: + # Query devices with the NETBOX_FILTER_CONDUCTOR_SONIC criteria + for device in utils.nb.dcim.devices.filter(**nb_device_query): + # Check if device role matches allowed roles + if device.role and device.role.slug in DEFAULT_SONIC_ROLES: + devices.append(device) + logger.debug( + f"Found device: {device.name} with role: {device.role.slug}" + ) + + except Exception as e: + logger.error(f"Error retrieving SONiC devices from NetBox: {e}") + return None + + return devices