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
This commit is contained in:
Bruno Cornec 2019-03-30 02:25:59 +01:00
parent 520bdc5605
commit b84dd6d2d9
6 changed files with 185 additions and 14 deletions

View File

@ -247,6 +247,11 @@ if __name__ == '__main__':
# Display system information using jinja2 template # Display system information using jinja2 template
render_template("system_info.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): def render_template(template):
try: try:
template = jinja2_env.get_template(template) template = jinja2_env.get_template(template)
@ -396,8 +401,8 @@ if __name__ == '__main__':
arguments['<changed_value>']) arguments['<changed_value>'])
logger.debug(inventory.data) logger.debug(inventory.data)
inventory.save() inventory.save()
elif arguments['getinfo'] is True: elif arguments['getinfo'] is True or arguments['getserial'] is True:
logger.debug('getinfo command') logger.debug('get commands')
# If manager is not defined set it to 'default' # If manager is not defined set it to 'default'
if not arguments['<manager_name>']: if not arguments['<manager_name>']:
manager_name = 'default' manager_name = 'default'
@ -416,6 +421,7 @@ if __name__ == '__main__':
redfish_data = get_redfish_data(connection_parameters, False) redfish_data = get_redfish_data(connection_parameters, False)
else: else:
redfish_data = get_redfish_data(connection_parameters, True) redfish_data = get_redfish_data(connection_parameters, True)
if arguments['getinfo'] is True:
if arguments['manager'] is True: if arguments['manager'] is True:
logger.debug("Manager commands") logger.debug("Manager commands")
display_manager_info(redfish_data) display_manager_info(redfish_data)
@ -425,5 +431,8 @@ if __name__ == '__main__':
elif arguments['chassis'] is True: elif arguments['chassis'] is True:
logger.debug("chassis commands") logger.debug("chassis commands")
display_chassis_info(redfish_data) 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") logger.info("Client session terminated")
sys.exit(0) sys.exit(0)

View File

@ -9,6 +9,7 @@ Usage:
redfish-client [options] manager getinfo [<manager_name>] redfish-client [options] manager getinfo [<manager_name>]
redfish-client [options] chassis getinfo [<manager_name>] redfish-client [options] chassis getinfo [<manager_name>]
redfish-client [options] system getinfo [<manager_name>] redfish-client [options] system getinfo [<manager_name>]
redfish-client [options] getserial [<manager_name>]
redfish-client (-h | --help) redfish-client (-h | --help)
redfish-client --version redfish-client --version

View File

@ -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 %}

View File

@ -114,6 +114,16 @@ class ArrayControllers(Device):
# This means we don't have ArrayControllers # This means we don't have ArrayControllers
self.logical_drives_collection = None 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 LogicalDrivesCollection(BaseCollection):
'''Class to manage redfish hpe oem LogicalDrivesCollection data.''' '''Class to manage redfish hpe oem LogicalDrivesCollection data.'''
@ -153,3 +163,36 @@ class LogicalDrives(Device):
return self.data.Raid return self.data.Raid
except AttributeError: except AttributeError:
return "Not available" 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

View File

@ -523,7 +523,7 @@ class EthernetInterfacesCollection(BaseCollection):
EthernetInterfaces(link, connection_parameters) EthernetInterfaces(link, connection_parameters)
class EthernetInterfaces(Base): class EthernetInterfaces(Device):
'''Class to manage redfish EthernetInterfaces.''' '''Class to manage redfish EthernetInterfaces.'''
def get_mac(self): def get_mac(self):
'''Get EthernetInterface MacAddress '''Get EthernetInterface MacAddress
@ -602,7 +602,7 @@ class ProcessorsCollection(BaseCollection):
Processors(link, connection_parameters) Processors(link, connection_parameters)
class Processors(Base): class Processors(Device):
'''Class to manage redfish Processors.''' '''Class to manage redfish Processors.'''
def get_speed(self): def get_speed(self):
'''Get processor speed '''Get processor speed
@ -655,7 +655,7 @@ class SimpleStorageCollection(BaseCollection):
SimpleStorage(link, connection_parameters) SimpleStorage(link, connection_parameters)
class SimpleStorage(Base): class SimpleStorage(Device):
'''Class to manage redfish SimpleStorage''' '''Class to manage redfish SimpleStorage'''
def get_status(self): def get_status(self):
'''Get storage status '''Get storage status

View File

@ -271,3 +271,40 @@ class Device(Base):
return self.data.PartNumber return self.data.PartNumber
except AttributeError: except AttributeError:
return "Not available" 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"