From b84dd6d2d93bb775591967d3f5fb92fd242b7186 Mon Sep 17 00:00:00 2001 From: Bruno Cornec Date: Sat, 30 Mar 2019 02:25:59 +0100 Subject: [PATCH] Add a getserial command to redfish-client - print Part or Serial numbers of Chassis and Systems using a specific jinja2 template - for HPE servers, print them for NICs and SmartArrays, and Physical drives behind (not seen with calls on standard components) Change-Id: I741c97847a07e126d7f34ceaa4695f9a8cdcec2b --- redfish-client/redfish-client | 31 ++++--- redfish-client/redfish-client_usage.txt | 1 + redfish-client/templates/serial_info.template | 81 +++++++++++++++++++ redfish/oem/hpe.py | 43 ++++++++++ redfish/standard.py | 6 +- redfish/types.py | 37 +++++++++ 6 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 redfish-client/templates/serial_info.template diff --git a/redfish-client/redfish-client b/redfish-client/redfish-client index 8bc3bfc..fb09bf6 100755 --- a/redfish-client/redfish-client +++ b/redfish-client/redfish-client @@ -247,6 +247,11 @@ if __name__ == '__main__': # Display system information using jinja2 template render_template("system_info.template") + def display_part_serial_numbers(redfish_data): + # Display PartNumbers and SerialNumber entries + # information using jinja2 template + render_template("serial_info.template") + def render_template(template): try: template = jinja2_env.get_template(template) @@ -396,8 +401,8 @@ if __name__ == '__main__': arguments['']) logger.debug(inventory.data) inventory.save() - elif arguments['getinfo'] is True: - logger.debug('getinfo command') + elif arguments['getinfo'] is True or arguments['getserial'] is True: + logger.debug('get commands') # If manager is not defined set it to 'default' if not arguments['']: manager_name = 'default' @@ -416,14 +421,18 @@ if __name__ == '__main__': redfish_data = get_redfish_data(connection_parameters, False) else: redfish_data = get_redfish_data(connection_parameters, True) - if arguments['manager'] is True: - logger.debug("Manager commands") - display_manager_info(redfish_data) - elif arguments['system'] is True: - logger.debug("system commands") - display_system_info(redfish_data) - elif arguments['chassis'] is True: - logger.debug("chassis commands") - display_chassis_info(redfish_data) + if arguments['getinfo'] is True: + if arguments['manager'] is True: + logger.debug("Manager commands") + display_manager_info(redfish_data) + elif arguments['system'] is True: + logger.debug("system commands") + display_system_info(redfish_data) + elif arguments['chassis'] is True: + logger.debug("chassis commands") + display_chassis_info(redfish_data) + if arguments['getserial'] is True: + logger.debug("serial & part number commands") + display_part_serial_numbers(redfish_data) logger.info("Client session terminated") sys.exit(0) diff --git a/redfish-client/redfish-client_usage.txt b/redfish-client/redfish-client_usage.txt index 762d6d8..f709aae 100644 --- a/redfish-client/redfish-client_usage.txt +++ b/redfish-client/redfish-client_usage.txt @@ -9,6 +9,7 @@ Usage: redfish-client [options] manager getinfo [] redfish-client [options] chassis getinfo [] redfish-client [options] system getinfo [] + redfish-client [options] getserial [] redfish-client (-h | --help) redfish-client --version diff --git a/redfish-client/templates/serial_info.template b/redfish-client/templates/serial_info.template new file mode 100644 index 0000000..154c7cc --- /dev/null +++ b/redfish-client/templates/serial_info.template @@ -0,0 +1,81 @@ +Redfish API version: {{ r.get_api_version() }} +{{ r.Root.get_name() }} + +Part|Serial Numbers information: +================================ +{% for chassis_index in r.Chassis.chassis_dict | sort %} +{%- set chassis = r.Chassis.chassis_dict[chassis_index] %} +Chassis #{{ chassis_index }}: +Name: {{ chassis.get_name() }} +Manufacturer: {{ chassis.get_manufacturer() }} +Model: {{ chassis.get_model() }} +Chassis Type: {{ chassis.get_type() }} +Part#: {{ chassis.get_part_number() }} +SKU: {{ chassis.get_sku() }} +Serial#: {{ chassis.get_serial_number() }} +AssetTag: {{ chassis.get_asset_tag() }} +FW version: {{ chassis.get_fw_version() }} +{%- endfor %} + +-------------------------------------------------------------------------------- +{% for system_index in r.Systems.systems_dict | sort %} +{%- set system = r.Systems.systems_dict[system_index] %} +System #{{ system_index }}: +Name: {{ system.get_name() }} +Type: {{ system.get_type() }} +Model: {{ system.get_model() }} +SKU: {{ system.get_sku() }} +Serial: {{ system.get_serial_number() }} +FW version: {{ system.get_fw_version() }} +CPU number: {{ system.get_cpucount() }} +CPU model: {{ system.get_cpumodel() }} +Available memory: {{ system.get_memory() }} GB +Status: State: {{ system.get_status().Health }} / Health: {{ system.get_status().Health }} +Power: {{ system.get_power() }} +{%- if system.data.Oem.Hpe or system.data.Oem.Hp %} +{%- if system.network_adapters_collection %} +{%- for nic_index in system.network_adapters_collection.network_adapters_dict | sort %} + {%- if system.network_adapters_collection.network_adapters_dict[nic_index] %} + {%- set na = system.network_adapters_collection.network_adapters_dict[nic_index] %} +Network Adapter #{{ nic_index }}: + Name: {{ na.get_name() }} + Mac address: + {%- for mac_index in na.get_mac() | sort %} + Mac #{{ loop.index }}: {{ mac_index }} + {%- endfor %} + Serial#: {{ na.get_serial_number() }} + Part#: {{ na.get_part_number() }} + FW version: {{ na.get_fw_version() }} + {%- endif %} +{%- endfor %} +{%- endif %} +{%- endif %} + +{%- if system.data.Oem.Hpe or system.data.Oem.Hp %} +{%- if system.smart_storage %} +{%- for ac_index in system.smart_storage.array_controllers_collection.array_controllers_dict | sort %} + {%- set ac = system.smart_storage.array_controllers_collection.array_controllers_dict[ac_index] %} +Array controller #{{ ac_index }}: + Model: {{ ac.get_model() }} + Serial #: {{ ac.get_serial_number() }} + Part #: {{ ac.get_part_number() }} + {%- for logical_drives_index in ac.logical_drives_collection.logical_drives_dict | sort %} + {%- set ld = ac.logical_drives_collection.logical_drives_dict[logical_drives_index] %} + Logical drive #{{ logical_drives_index }}: + Capacity: {{ ld.get_capacity() }} MB + Raid Level: {{ ld.get_raid() }} + {%- endfor %} + {%- for physical_drives_index in ac.physical_drives_collection.physical_drives_dict | sort %} + {%- set pd = ac.physical_drives_collection.physical_drives_dict[physical_drives_index] %} + Physical drive #{{ physical_drives_index }}: + {{ pd.get_model() }} + Capacity: {{ pd.get_capacity() }} MB + Serial #: {{ pd.get_serial_number() }} + Part #: {{ pd.get_part_number() }} + FW: {{ pd.get_fw_version() }} + {%- endfor %} +{%- endfor %} +{%- endif %} +{%- endif %} +-------------------------------------------------------------------------------- +{% endfor %} diff --git a/redfish/oem/hpe.py b/redfish/oem/hpe.py index 8780404..3b042c3 100644 --- a/redfish/oem/hpe.py +++ b/redfish/oem/hpe.py @@ -114,6 +114,16 @@ class ArrayControllers(Device): # This means we don't have ArrayControllers self.logical_drives_collection = None + try: + self.physical_drives_collection = \ + PhysicalDrivesCollection( + self.get_link_url('PhysicalDrives', self.data.Links), + connection_parameters) + + except AttributeError: + # This means we don't have ArrayControllers + self.physical_drives_collection = None + class LogicalDrivesCollection(BaseCollection): '''Class to manage redfish hpe oem LogicalDrivesCollection data.''' @@ -153,3 +163,36 @@ class LogicalDrives(Device): return self.data.Raid except AttributeError: return "Not available" + + +class PhysicalDrivesCollection(BaseCollection): + '''Class to manage redfish hpe oem PhysicalDrivesCollection data.''' + def __init__(self, url, connection_parameters): + super(PhysicalDrivesCollection, self).__init__(url, + connection_parameters) + self.physical_drives_dict = {} + + for link in self.links: + index = re.search(r'DiskDrives/(\w+)', link) + self.physical_drives_dict[index.group(1)] = DiskDrives( + link, connection_parameters) + + +class DiskDrives(Device): + '''Class to manage redfish hpe oem DiskDrives data.''' + def get_capacity(self): + '''Get Logical drive capacity + + :returns: Logical drive capacity or "Not available" + :rtype: string + + ''' + try: + return self.data.CapacityMiB + except AttributeError: + return "Not available" + + +class StorageEnclosures(Device): + '''Class to manage redfish hpe oem StorageEnclosures data.''' + pass diff --git a/redfish/standard.py b/redfish/standard.py index c28ab2b..8fa216c 100644 --- a/redfish/standard.py +++ b/redfish/standard.py @@ -523,7 +523,7 @@ class EthernetInterfacesCollection(BaseCollection): EthernetInterfaces(link, connection_parameters) -class EthernetInterfaces(Base): +class EthernetInterfaces(Device): '''Class to manage redfish EthernetInterfaces.''' def get_mac(self): '''Get EthernetInterface MacAddress @@ -602,7 +602,7 @@ class ProcessorsCollection(BaseCollection): Processors(link, connection_parameters) -class Processors(Base): +class Processors(Device): '''Class to manage redfish Processors.''' def get_speed(self): '''Get processor speed @@ -655,7 +655,7 @@ class SimpleStorageCollection(BaseCollection): SimpleStorage(link, connection_parameters) -class SimpleStorage(Base): +class SimpleStorage(Device): '''Class to manage redfish SimpleStorage''' def get_status(self): '''Get storage status diff --git a/redfish/types.py b/redfish/types.py index fd7c39a..3e9bfc6 100644 --- a/redfish/types.py +++ b/redfish/types.py @@ -271,3 +271,40 @@ class Device(Base): return self.data.PartNumber except AttributeError: return "Not available" + + def get_name(self): + '''Get name of the device. + + :returns: name or "Not available" + :rtype: string + + ''' + try: + return self.data.Name + except AttributeError: + try: + return self.data.ProductName + except AttributeError: + return "Not available" + + def get_fw_version(self): + '''Get firmware version of the device. + + :returns: firmware version or "Not available" + :rtype: string + + ''' + try: + return self.data.FirmwareVersion.Current.VersionString + except AttributeError: + try: + return self.data.Firmware.Current.VersionString + except AttributeError: + # For some NICs + try: + return self.data.FirmwareVersion + except AttributeError: + try: + return self.data.Firmware + except AttributeError: + return "Not available"