From 5c4921b66dc2db33f3de0c2f09f27ff02b377c0c Mon Sep 17 00:00:00 2001 From: Mike Raineri Date: Thu, 8 Jun 2023 13:53:01 -0400 Subject: [PATCH] Updated collection handling for systems, managers, and chassis to differentiate between HTTP 404 from other non-successful responses Signed-off-by: Mike Raineri --- redfish_utilities/collections.py | 55 ++++++++++++++++++++++++++++++++ redfish_utilities/inventory.py | 13 ++------ redfish_utilities/managers.py | 35 ++++++-------------- redfish_utilities/systems.py | 18 +++-------- 4 files changed, 72 insertions(+), 49 deletions(-) create mode 100644 redfish_utilities/collections.py diff --git a/redfish_utilities/collections.py b/redfish_utilities/collections.py new file mode 100644 index 0000000..147a64e --- /dev/null +++ b/redfish_utilities/collections.py @@ -0,0 +1,55 @@ +#! /usr/bin/python +# Copyright Notice: +# Copyright 2019-2023 DMTF. All rights reserved. +# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/Redfish-Tacklebox/blob/main/LICENSE.md + +""" +Collections Module + +File : collections.py + +Brief : This file contains the definitions and functionalities for performing + operations with resource collections +""" + +from .messages import verify_response + +class RedfishCollectionNotFoundError( Exception ): + """ + Raised when the specified collection is not found (HTTP Status = 404) + """ + pass + +class RedfishCollectionMemberNotFoundError( Exception ): + """ + Raised when the specified member is not found (HTTP Status = 404) + """ + pass + +def get_collection_ids( context, collection_uri ): + """ + Iterates over a collection and returns the identifiers of all members + + Args: + context: The Redfish client object with an open session + collection_uri: The URI of the collection to process + + Returns: + A list of identifiers of the members of the collection + """ + + # Get the collection and iterate through its collection + avail_members = [] + collection = context.get( collection_uri ) + if collection.status == 404: + raise RedfishCollectionNotFoundError( "Service does not contain a collection at URI {}".format( collection_uri ) ) + verify_response( collection ) + while True: + for member in collection.dict["Members"]: + avail_members.append( member["@odata.id"].strip( "/" ).split( "/" )[-1] ) + if "Members@odata.nextLink" not in collection.dict: + break + collection = context.get( collection.dict["Members@odata.nextLink"] ) + verify_response( collection ) + + return avail_members diff --git a/redfish_utilities/inventory.py b/redfish_utilities/inventory.py index f1888cc..c012d86 100644 --- a/redfish_utilities/inventory.py +++ b/redfish_utilities/inventory.py @@ -14,6 +14,7 @@ import warnings import xlsxwriter +from .collections import get_collection_ids from .messages import verify_response from . import config @@ -406,16 +407,8 @@ def get_chassis_ids( context ): # Get the service root to find the chassis collection service_root = context.get( "/redfish/v1/" ) if "Chassis" not in service_root.dict: - # No system collection + # No chassis collection raise RedfishChassisNotFoundError( "Service does not contain a chassis collection" ) # Get the chassis collection and iterate through its collection - avail_chassis = [] - chassis_col = context.get( service_root.dict["Chassis"]["@odata.id"] ) - while True: - for chassis_member in chassis_col.dict["Members"]: - avail_chassis.append( chassis_member["@odata.id"].strip( "/" ).split( "/" )[-1] ) - if "Members@odata.nextLink" not in chassis_col.dict: - break - chassis_col = context.get( chassis_col.dict["Members@odata.nextLink"] ) - return avail_chassis + return get_collection_ids( context, service_root.dict["Chassis"]["@odata.id"] ) diff --git a/redfish_utilities/managers.py b/redfish_utilities/managers.py index 10a5968..5a86105 100644 --- a/redfish_utilities/managers.py +++ b/redfish_utilities/managers.py @@ -12,6 +12,7 @@ with the managers collection for a given Redfish service """ +from .collections import get_collection_ids from .messages import verify_response from .resets import reset_types @@ -51,15 +52,7 @@ def get_manager_ids( context ): raise RedfishManagerNotFoundError( "Service does not contain a manager collection" ) # Get the manager collection and iterate through its collection - avail_managers = [] - manager_col = context.get( service_root.dict["Managers"]["@odata.id"] ) - while True: - for manager_member in manager_col.dict["Members"]: - avail_managers.append( manager_member["@odata.id"].strip( "/" ).split( "/" )[-1] ) - if "Members@odata.nextLink" not in manager_col.dict: - break - manager_col = context.get( manager_col.dict["Members@odata.nextLink"] ) - return avail_managers + return get_collection_ids( context, service_root.dict["Managers"]["@odata.id"] ) def get_manager( context, manager_id = None ): """ @@ -88,12 +81,11 @@ def get_manager( context, manager_id = None ): raise RedfishManagerNotFoundError( "Service does not contain exactly one manager; a target manager needs to be specified: {}".format( ", ".join( avail_managers ) ) ) # Check the response and return the manager if the response is good - try: - verify_response( manager ) - except: + if manager.status == 404: if avail_managers is None: avail_managers = get_manager_ids( context ) - raise RedfishManagerNotFoundError( "Service does not contain a manager called {}; valid managers: {}".format( manager_id, ", ".join( avail_managers ) ) ) from None + raise RedfishManagerNotFoundError( "Service does not contain a manager called {}; valid managers: {}".format( manager_id, ", ".join( avail_managers ) ) ) + verify_response( manager ) return manager def print_manager( manager ): @@ -230,15 +222,7 @@ def get_manager_ethernet_interface_ids( context, manager_id = None ): raise RedfishManagerEthIntNotFoundError( "Manager {} does not contain an Ethernet interface collection".format( manager.dict["Id"] ) ) # Get the Ethernet interface collection and iterate through its collection - avail_interfaces = [] - interface_col = context.get( manager.dict["EthernetInterfaces"]["@odata.id"] ) - while True: - for interface_member in interface_col.dict["Members"]: - avail_interfaces.append( interface_member["@odata.id"].strip( "/" ).split( "/" )[-1] ) - if "Members@odata.nextLink" not in interface_col.dict: - break - interface_col = context.get( interface_col.dict["Members@odata.nextLink"] ) - return avail_interfaces + return get_collection_ids( context, manager.dict["EthernetInterfaces"]["@odata.id"] ) def get_manager_ethernet_interface( context, manager_id = None, interface_id = None ): """ @@ -273,12 +257,11 @@ def get_manager_ethernet_interface( context, manager_id = None, interface_id = N raise RedfishManagerEthIntNotFoundError( "Manager {} does not contain exactly one Ethernet interface; a target Ethernet interface needs to be specified: {}".format( manager_id, ", ".join( avail_interfaces ) ) ) # Check the response and return the Ethernet interface if the response is good - try: - verify_response( interface ) - except: + if interface.status == 404: if avail_interfaces is None: avail_interfaces = get_manager_ethernet_interface_ids( context, manager_id ) - raise RedfishManagerEthIntNotFoundError( "Manager {} does not contain an Ethernet interface called {}; valid Ethernet interfaces: {}".format( manager_id, interface_id, ", ".join( avail_interfaces ) ) ) from None + raise RedfishManagerEthIntNotFoundError( "Manager {} does not contain an Ethernet interface called {}; valid Ethernet interfaces: {}".format( manager_id, interface_id, ", ".join( avail_interfaces ) ) ) + verify_response( interface ) return interface def set_manager_ethernet_interface( context, manager_id = None, interface_id = None, vlan = None, ipv4_addresses = None, dhcpv4 = None, ipv6_addresses = None, ipv6_gateways = None, dhcpv6 = None ): diff --git a/redfish_utilities/systems.py b/redfish_utilities/systems.py index 8df7c94..f751bf6 100644 --- a/redfish_utilities/systems.py +++ b/redfish_utilities/systems.py @@ -14,6 +14,7 @@ import warnings import sys +from .collections import get_collection_ids from .messages import verify_response from .resets import reset_types from . import config @@ -77,15 +78,7 @@ def get_system_ids( context ): raise RedfishSystemNotFoundError( "Service does not contain a system collection" ) # Get the system collection and iterate through its collection - avail_systems = [] - system_col = context.get( service_root.dict["Systems"]["@odata.id"] ) - while True: - for system_member in system_col.dict["Members"]: - avail_systems.append( system_member["@odata.id"].strip( "/" ).split( "/" )[-1] ) - if "Members@odata.nextLink" not in system_col.dict: - break - system_col = context.get( system_col.dict["Members@odata.nextLink"] ) - return avail_systems + return get_collection_ids( context, service_root.dict["Systems"]["@odata.id"] ) def get_system( context, system_id = None ): """ @@ -114,12 +107,11 @@ def get_system( context, system_id = None ): raise RedfishSystemNotFoundError( "Service does not contain exactly one system; a target system needs to be specified: {}".format( ", ".join( avail_systems ) ) ) # Check the response and return the system if the response is good - try: - verify_response( system ) - except: + if system.status == 404: if avail_systems is None: avail_systems = get_system_ids( context ) - raise RedfishSystemNotFoundError( "Service does not contain a system called {}; valid systems: {}".format( system_id, ", ".join( avail_systems ) ) ) from None + raise RedfishSystemNotFoundError( "Service does not contain a system called {}; valid systems: {}".format( system_id, ", ".join( avail_systems ) ) ) + verify_response( system ) return system def get_system_boot( context, system_id = None ):