Merge pull request #65 from uggla/systemandchassis

System and chassis
This commit is contained in:
Bruno Cornec
2016-04-06 18:59:53 +02:00
12 changed files with 836 additions and 229 deletions

View File

@@ -6,13 +6,13 @@ from __future__ import print_function
from __future__ import division from __future__ import division
from __future__ import absolute_import from __future__ import absolute_import
from future import standard_library from future import standard_library
standard_library.install_aliases()
from builtins import str from builtins import str
import os import os
import sys import sys
import json import json
import redfish import redfish
standard_library.install_aliases()
# Get $HOME environment. # Get $HOME environment.
@@ -52,46 +52,57 @@ print ("Redfish API version : %s \n" % remote_mgmt.get_api_version())
# Uncomment following line to reset the blade !!! # Uncomment following line to reset the blade !!!
# remote_mgmt.Systems.systems_dict["1"].reset_system() # remote_mgmt.Systems.systems_dict["1"].reset_system()
# TODO : create an attribute to link the managed system directly print("Bios version : {}\n".format(
# and avoid systems_dict["1"] remote_mgmt.Systems.systems_dict["1"].get_bios_version()))
# --> will be something like : print("Serial Number : {}\n".format(
# remote_mgmt.Systems.systems_dict["1"] = remote_mgmt.Systems.managed_system remote_mgmt.Systems.systems_dict["1"].get_serial_number()))
print("Power State : {}\n".format(
remote_mgmt.Systems.systems_dict["1"].get_power()))
print("Parameter 'SystemType' : {}\n".format(
remote_mgmt.Systems.systems_dict["1"].get_parameter("SystemType")))
print("Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_bios_version())) print("Get bios parameters : {}\n".format(
print("Serial Number : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_serial_number())) remote_mgmt.Systems.systems_dict["1"].bios.get_parameters()))
print("Power State : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_power())) print("Get boot parameters : {}\n".format(
print("Parameter 'SystemType' : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_parameter("SystemType"))) remote_mgmt.Systems.systems_dict["1"].bios.boot.get_parameters()))
print("Get bios parameters : {}\n".format(remote_mgmt.Systems.systems_dict["1"].bios.get_parameters())) # print("Get bios parameter 'AdminPhone' : {}\n".format(
print("Get boot parameters : {}\n".format(remote_mgmt.Systems.systems_dict["1"].bios.boot.get_parameters())) # remote_mgmt.Systems.systems_dict["1"].bios.get_parameter("AdminPhone")))
# print("Set bios parameter 'AdminPhone' to '' : {}\n".format(
# remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("AdminPhone","")))
#print("Get bios parameter 'AdminPhone' : {}\n".format(remote_mgmt.Systems.systems_dict["1"].bios.get_parameter("AdminPhone"))) # Boot server with script
#print("Set bios parameter 'AdminPhone' to '' : {}\n".format(remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("AdminPhone",""))) # remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("Dhcpv4","Enabled")
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter(
"PreBootNetwork", "Auto")
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter(
"UefiShellStartup", "Enabled")
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter(
"UefiShellStartupLocation", "NetworkLocation")
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter(
"UefiShellStartupUrl", "http://10.3.222.88/deploy/startup.nsh")
#Boot server with script # remote_mgmt.Systems.systems_dict["1"].set_parameter_json(
#remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("Dhcpv4","Enabled") # '{"Boot": {"BootSourceOverrideTarget": "UefiShell"}}')
# remote_mgmt.Systems.systems_dict["1"].set_parameter_json(
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("PreBootNetwork", "Auto") # '{"Boot": {"BootSourceOverrideEnabled" : "Continuous"}}')
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("UefiShellStartup", "Enabled") # remote_mgmt.Systems.systems_dict["1"].set_parameter_json(
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("UefiShellStartupLocation", "NetworkLocation") # '{"Boot": {"BootSourceOverrideEnabled" : "Once"}}')
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("UefiShellStartupUrl", "http://10.3.222.88/deploy/startup.nsh")
#remote_mgmt.Systems.systems_dict["1"].set_parameter_json('{"Boot": {"BootSourceOverrideTarget": "UefiShell"}}')
# remote_mgmt.Systems.systems_dict["1"].set_parameter_json('{"Boot": {"BootSourceOverrideEnabled" : "Continuous"}}')
#remote_mgmt.Systems.systems_dict["1"].set_parameter_json('{"Boot": {"BootSourceOverrideEnabled" : "Once"}}')
mySystem = remote_mgmt.Systems.systems_dict["1"] mySystem = remote_mgmt.Systems.systems_dict["1"]
mySystem.set_boot_source_override("None","Disabled") mySystem.set_boot_source_override("None", "Disabled")
#Uncomment the next line to reset the server # Uncomment the next line to reset the server
#mySystem.reset_system() # mySystem.reset_system()
print("Get manager firmware version : {}\n".format(remote_mgmt.Managers.managers_dict["1"].get_firmware_version())) print("Get manager firmware version : {}\n".format(
print("Get system Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_bios_version())) remote_mgmt.Managers.managers_dict["1"].get_firmware_version()))
print("Get system Bios version : {}\n".format(
remote_mgmt.Systems.systems_dict["1"].get_bios_version()))
#Reset of the system is required to apply the changes # Reset of the system is required to apply the changes
#remote_mgmt.Systems.systems_dict["1"].reset_system() # remote_mgmt.Systems.systems_dict["1"].reset_system()
remote_mgmt.logout() remote_mgmt.logout()

View File

@@ -6,12 +6,12 @@ from __future__ import print_function
from __future__ import division from __future__ import division
from __future__ import absolute_import from __future__ import absolute_import
from future import standard_library from future import standard_library
standard_library.install_aliases()
import os import os
import sys import sys
import json import json
import redfish import redfish
standard_library.install_aliases()
# Get $HOME environment. # Get $HOME environment.
HOME = os.getenv('HOME') HOME = os.getenv('HOME')
@@ -49,7 +49,8 @@ except redfish.exception.RedfishException as e:
print("Redfish API version : {} \n".format(remote_mgmt.get_api_version())) print("Redfish API version : {} \n".format(remote_mgmt.get_api_version()))
print("UUID : {} \n".format(remote_mgmt.Root.get_api_UUID())) print("UUID : {} \n".format(remote_mgmt.Root.get_api_UUID()))
print("System 1 :\n") print("System 1 :\n")
print("Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_bios_version())) print("Bios version : {}\n".format(
remote_mgmt.Systems.systems_dict["1"].get_bios_version()))
print("System 2 :\n") print("System 2 :\n")
print("Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["2"].get_parameter("SerialNumber"))) print("Bios version : {}\n".format(
#print remoteMgmt.get_api_link_to_server() remote_mgmt.Systems.systems_dict["2"].get_parameter("SerialNumber")))

View File

@@ -12,6 +12,8 @@ redfish-client ::
redfish-client [options] config show redfish-client [options] config show
redfish-client [options] config showall redfish-client [options] config showall
redfish-client [options] manager getinfo [<manager_name>] redfish-client [options] manager getinfo [<manager_name>]
redfish-client [options] chassis getinfo [<manager_name>]
redfish-client [options] system getinfo [<manager_name>]
redfish-client (-h | --help) redfish-client (-h | --help)
redfish-client --version redfish-client --version
@@ -36,7 +38,6 @@ from __future__ import print_function
from __future__ import division from __future__ import division
from __future__ import absolute_import from __future__ import absolute_import
from future import standard_library from future import standard_library
standard_library.install_aliases()
from builtins import str from builtins import str
from builtins import object from builtins import object
@@ -50,6 +51,7 @@ import configparser
import jinja2 import jinja2
import requests.packages.urllib3 import requests.packages.urllib3
import redfish import redfish
standard_library.install_aliases()
class InventoryFile(object): class InventoryFile(object):
@@ -87,7 +89,7 @@ class InventoryFile(object):
def manager_incorect(self, exception): def manager_incorect(self, exception):
''' Log and exit if manager name is incorect''' ''' Log and exit if manager name is incorect'''
logger.error('Incorect manager name : %s' % exception.args) logger.error('Incorrect manager name : %s' % exception.args)
sys.exit(1) sys.exit(1)
def check_manager(self, manager_name): def check_manager(self, manager_name):
@@ -220,6 +222,27 @@ class RedfishClientException(Exception):
if __name__ == '__main__': if __name__ == '__main__':
'''Main application redfish-client''' '''Main application redfish-client'''
# Functions # Functions
def get_redfish_data(connection_parameters, check_SSL):
if not connection_parameters['login']:
simulator = True
enforceSSL = False
else:
simulator = False
enforceSSL = True
try:
redfish_data = redfish.connect(connection_parameters['url'],
connection_parameters['login'],
connection_parameters['password'],
verify_cert=check_SSL,
simulator=simulator,
enforceSSL=enforceSSL)
return(redfish_data)
except redfish.exception.RedfishException as e:
logger.error(str(e.message))
sys.stderr.write(str(e.message))
sys.stderr.write(str(e.advices))
sys.exit(1)
def show_manager(all=False): def show_manager(all=False):
'''Display manager info '''Display manager info
@@ -232,7 +255,7 @@ if __name__ == '__main__':
if(not inventory.get_managers()): if(not inventory.get_managers()):
print("None") print("None")
else: else:
for manager in inventory.get_managers(): for manager in sorted(inventory.get_managers()):
print(manager) print(manager)
if all is True: if all is True:
info = inventory.get_manager_info(manager) info = inventory.get_manager_info(manager)
@@ -240,35 +263,21 @@ if __name__ == '__main__':
print('\tLogin : {}'.format(info['login'])) print('\tLogin : {}'.format(info['login']))
print('\tPassword : {}'.format(info['password'])) print('\tPassword : {}'.format(info['password']))
def get_manager_info(manager_name, check_SSL): def display_manager_info(redfish_data):
connection_parameters = inventory.get_manager_info(manager_name)
if not connection_parameters['login']:
simulator = True
enforceSSL = False
else:
simulator = False
enforceSSL = True
try:
print('Gathering data from manager, please wait...\n')
# TODO : Add a rotating star showing program is running ?
# Could be a nice exercice for learning python. :)
logger.info('Gathering data from manager')
remote_mgmt = redfish.connect(connection_parameters['url'],
connection_parameters['login'],
connection_parameters['password'],
verify_cert=check_SSL,
simulator=simulator,
enforceSSL=enforceSSL
)
except redfish.exception.RedfishException as e:
logger.error(str(e.message))
sys.stderr.write(str(e.message))
sys.stderr.write(str(e.advices))
sys.exit(1)
# Display manager information using jinja2 template # Display manager information using jinja2 template
render_template("manager_info.template")
def display_chassis_info(redfish_data):
# Display system information using jinja2 template
render_template("chassis_info.template")
def display_system_info(redfish_data):
# Display system information using jinja2 template
render_template("system_info.template")
def render_template(template):
try: try:
template = jinja2_env.get_template("manager_info.template") template = jinja2_env.get_template(template)
except jinja2.exceptions.TemplateNotFound as e: except jinja2.exceptions.TemplateNotFound as e:
print('Template "{}" not found in {}.' print('Template "{}" not found in {}.'
.format(e.message, jinja2_env.loader.searchpath[0])) .format(e.message, jinja2_env.loader.searchpath[0]))
@@ -276,7 +285,7 @@ if __name__ == '__main__':
% (e.message, jinja2_env.loader.searchpath[0])) % (e.message, jinja2_env.loader.searchpath[0]))
sys.exit(1) sys.exit(1)
print(template.render(r=remote_mgmt)) print(template.render(r=redfish_data))
################################################################# #################################################################
# Main program # Main program
@@ -406,21 +415,34 @@ if __name__ == '__main__':
arguments['<changed_value>']) arguments['<changed_value>'])
logger.debug(inventory.data) logger.debug(inventory.data)
inventory.save() inventory.save()
if arguments['manager'] is True: elif arguments['getinfo'] is True:
logger.debug("Manager commands") logger.debug('getinfo command')
if arguments['getinfo'] is True: # If manager is not defined set it to 'default'
logger.debug('getinfo command') if not arguments['<manager_name>']:
# If manager is not defined set it to 'default' manager_name = 'default'
if not arguments['<manager_name>']: else:
manager_name = 'default' manager_name = arguments['<manager_name>']
else: # Check if the default section is available in our conf file
manager_name = arguments['<manager_name>'] inventory.check_manager(manager_name)
# Check if the default section is available in our conf file connection_parameters = inventory.get_manager_info(manager_name)
inventory.check_manager(manager_name)
if arguments['--insecure'] is True:
get_manager_info(manager_name, False)
else:
get_manager_info(manager_name, True)
print('Gathering data from manager, please wait...\n')
# TODO : Add a rotating star showing program is running ?
# Could be a nice exercice for learning python. :)
logger.info('Gathering data from manager')
if arguments['--insecure'] is True:
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)
logger.info("Client session terminated") logger.info("Client session terminated")
sys.exit(0) sys.exit(0)

View File

@@ -0,0 +1,91 @@
Redfish API version : {{ r.get_api_version() }}
{{ r.Root.get_name() }}
Chassis information :
=====================
{% for chassis_index in r.Chassis.chassis_dict | sort %}
{%- set chassis = r.Chassis.chassis_dict[chassis_index] %}
Chassis id {{ chassis_index }}:
Manufacturer : {{ chassis.get_manufacturer() }}
Model : {{ chassis.get_model() }}
Chassis Type : {{ chassis.get_type() }}
PartNumber : {{ chassis.get_part_number() }}
SKU : {{ chassis.get_sku() }}
Serial : {{ chassis.get_serial_number() }}
AssetTag : {{ chassis.get_asset_tag() }}
Status : State : {{ chassis.get_status().Health }} / Health : {{ chassis.get_status().Health }}
{%- if chassis.thermal %}
Temperatures :
{%- if chassis.thermal.get_temperatures() == 'Not available' %}
Not available
{%- else %}
{%- for sensor, temp in chassis.thermal.get_temperatures().items() | sort %}
{{ sensor }} : {{ temp }}
{%- endfor %}
{%- endif %}
Fans :
{%- if chassis.thermal.get_fans() == 'Not available' %}
Not available
{%- else %}
{%- for fan, rpm in chassis.thermal.get_fans().items() | sort %}
{{ fan }} : {{ rpm }}
{%- endfor %}
{%- endif %}
{%- endif %}
{#
Hostname : {{ system.get_hostname() }}
Bios version : {{ system.get_bios_version() }}
CPU number : {{ system.get_cpucount() }}
CPU model : {{ system.get_cpumodel() }}
{%- if system.processors_collection %}
CPU details :
{%- for cpu_index in system.processors_collection.processors_dict | sort %}
{%- set cpu = system.processors_collection.processors_dict[cpu_index] %}
Processor id {{ cpu_index }} :
Speed : {{ cpu.get_speed() }}
Cores : {{ cpu.get_cores() }}
Threads : {{ cpu.get_threads() }}
{% endfor %}
{%- endif %}
Available memory : {{ system.get_memory() }}
Status : State : {{ system.get_status().Health }} / Health : {{ system.get_status().Health }}
Power : {{ system.get_power() }}
Description : {{ system.get_description() }}
Chassis : {{ system.get_chassis() | join(', ') }}
Managers : {{ system.get_managers() | join(', ') }}
IndicatorLED : {{ system.get_indicatorled() }}
Ethernet Interface :
{%- if system.ethernet_interfaces_collection %}
{%- for ethernetinterface_index in system.ethernet_interfaces_collection.ethernet_interfaces_dict | sort %}
{%- set ei = system.ethernet_interfaces_collection.ethernet_interfaces_dict[ethernetinterface_index] %}
Ethernet Interface id {{ ethernetinterface_index }} :
{{ ei.get_name() }}
FQDN : {{ ei.get_fqdn() }}
Mac address : {{ ei.get_mac() }}
Address ipv4 : {{ ei.get_ipv4() | join(', ') }}
Address ipv6 : {{ ei.get_ipv6() | join(', ') }}
{%- endfor %}
{%- else %}
This system has no ethernet interface
{%- endif %}
Simple Storage :
{%- if system.simple_storage_collection %}
{%- for simplestorage_index in system.simple_storage_collection.simple_storage_dict | sort %}
{%- set ss = system.simple_storage_collection.simple_storage_dict[simplestorage_index] %}
Simple Storage id {{ simplestorage_index }} :
{{ ss.get_name() }}
Status : State : {{ system.get_status().Health }} / Health : {{ system.get_status().Health }}
{%- for dev in ss.get_devices() %}
Device id {{ loop.index }} : {{ dev.Name }} {{ dev.Manufacturer }} {{ dev.Model }}
{%- endfor %}
{%- endfor %}
{%- else %}
This system has no simple storage
{%- endif %}
--------------------------------------------------------------------------------
#}
{% endfor %}

View File

@@ -9,7 +9,7 @@ Manager id {{ manager_index }}:
UUID : {{ manager.get_uuid() }} UUID : {{ manager.get_uuid() }}
Type : {{ manager.get_type() }} Type : {{ manager.get_type() }}
Firmware version : {{ manager.get_firmware_version() }} Firmware version : {{ manager.get_firmware_version() }}
State : {{ manager.get_status() }} Status : State : {{ manager.get_status().Health }} / Health : {{ manager.get_status().Health }}
Ethernet Interface : Ethernet Interface :
{%- if manager.ethernet_interfaces_collection %} {%- if manager.ethernet_interfaces_collection %}
{%- for ethernetinterface_index in manager.ethernet_interfaces_collection.ethernet_interfaces_dict | sort %} {%- for ethernetinterface_index in manager.ethernet_interfaces_collection.ethernet_interfaces_dict | sort %}

View File

@@ -0,0 +1,68 @@
Redfish API version : {{ r.get_api_version() }}
{{ r.Root.get_name() }}
Systems information :
=====================
{% for system_index in r.Systems.systems_dict | sort %}
{%- set system = r.Systems.systems_dict[system_index] %}
System id {{ system_index }}:
UUID : {{ system.get_uuid() }}
Type : {{ system.get_type() }}
Manufacturer : {{ system.get_manufacturer() }}
Model : {{ system.get_model() }}
SKU : {{ system.get_sku() }}
Serial : {{ system.get_serial_number() }}
Hostname : {{ system.get_hostname() }}
Bios version : {{ system.get_bios_version() }}
CPU number : {{ system.get_cpucount() }}
CPU model : {{ system.get_cpumodel() }}
{%- if system.processors_collection %}
CPU details :
{%- for cpu_index in system.processors_collection.processors_dict | sort %}
{%- set cpu = system.processors_collection.processors_dict[cpu_index] %}
Processor id {{ cpu_index }} :
Speed : {{ cpu.get_speed() }}
Cores : {{ cpu.get_cores() }}
Threads : {{ cpu.get_threads() }}
{% endfor %}
{%- endif %}
Available memory : {{ system.get_memory() }} GB
Status : State : {{ system.get_status().Health }} / Health : {{ system.get_status().Health }}
Power : {{ system.get_power() }}
Description : {{ system.get_description() }}
Chassis : {{ system.get_chassis() | join(', ') }}
Managers : {{ system.get_managers() | join(', ') }}
IndicatorLED : {{ system.get_indicatorled() }}
Ethernet Interface :
{%- if system.ethernet_interfaces_collection %}
{%- for ethernetinterface_index in system.ethernet_interfaces_collection.ethernet_interfaces_dict | sort %}
{%- set ei = system.ethernet_interfaces_collection.ethernet_interfaces_dict[ethernetinterface_index] %}
Ethernet Interface id {{ ethernetinterface_index }} :
{{ ei.get_name() }}
FQDN : {{ ei.get_fqdn() }}
Mac address : {{ ei.get_mac() }}
Address ipv4 : {{ ei.get_ipv4() | join(', ') }}
Address ipv6 : {{ ei.get_ipv6() | join(', ') }}
{%- endfor %}
{%- else %}
This system has no ethernet interface
{%- endif %}
Simple Storage :
{%- if system.simple_storage_collection %}
{%- for simplestorage_index in system.simple_storage_collection.simple_storage_dict | sort %}
{%- set ss = system.simple_storage_collection.simple_storage_dict[simplestorage_index] %}
Simple Storage id {{ simplestorage_index }} :
{{ ss.get_name() }}
Status : State : {{ system.get_status().Health }} / Health : {{ system.get_status().Health }}
{%- for dev in ss.get_devices() %}
Device id {{ loop.index }} : {{ dev.Name }} {{ dev.Manufacturer }} {{ dev.Model }}
{%- endfor %}
{%- endfor %}
{%- else %}
This system has no simple storage
{%- endif %}
--------------------------------------------------------------------------------
{% endfor %}

View File

@@ -17,10 +17,10 @@ from __future__ import print_function
from __future__ import division from __future__ import division
from __future__ import absolute_import from __future__ import absolute_import
from future import standard_library from future import standard_library
standard_library.install_aliases()
import pbr.version import pbr.version
from redfish.main import * from redfish.main import connect
standard_library.install_aliases()
try: try:
__version__ = pbr.version.VersionInfo('redfish').release_string() __version__ = pbr.version.VersionInfo('redfish').release_string()

View File

@@ -8,7 +8,6 @@ from future import standard_library
import logging import logging
import sys import sys
import os import os
import getpass
from logging.handlers import RotatingFileHandler from logging.handlers import RotatingFileHandler
standard_library.install_aliases() standard_library.install_aliases()
@@ -30,8 +29,8 @@ if not os.path.exists(REDFISH_HOME):
os.mkdir(REDFISH_HOME) os.mkdir(REDFISH_HOME)
except IOError: except IOError:
print('ERROR: can\'t create {}.\n'.format(REDFISH_HOME)) print('ERROR: can\'t create {}.\n'.format(REDFISH_HOME))
print(' Try to create directory {}'.format(os.path.dirname(REDFISH_LOGFILE))) print(' Try to create directory {}'.format(REDFISH_HOME))
print(' using: mkdir -p {}'.format(os.path.dirname(REDFISH_LOGFILE))) print(' using: mkdir -p {}'.format(REDFISH_HOME))
sys.exit(1) sys.exit(1)
REDFISH_LOGFILE = os.path.join(REDFISH_HOME, "python-redfish.log") REDFISH_LOGFILE = os.path.join(REDFISH_HOME, "python-redfish.log")
@@ -59,15 +58,18 @@ def initialize_logger(REDFISH_LOGFILE,
logger = logging.getLogger(logger_name) logger = logging.getLogger(logger_name)
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
formatter = logging.Formatter( formatter = logging.Formatter(
'%(asctime)s :: %(levelname)s :: %(message)s' '%(asctime)s :: %(levelname)s :: %(message)s')
)
try: try:
file_handler = RotatingFileHandler(os.path.expandvars(REDFISH_LOGFILE), 'a', 1000000, 1) file_handler = RotatingFileHandler(
os.path.expandvars(REDFISH_LOGFILE), 'a', 1000000, 1)
except IOError: except IOError:
print('ERROR: {} does not exist or is not writeable.\n'.format(REDFISH_LOGFILE)) print('ERROR: {} does not exist or is not writeable.\n'.format(
print(' Try to create directory {}'.format(os.path.dirname(REDFISH_LOGFILE))) REDFISH_LOGFILE))
print(' using: mkdir -p {}'.format(os.path.dirname(REDFISH_LOGFILE))) print(' Try to create directory {}'.format(os.path.dirname(
REDFISH_LOGFILE)))
print(' using: mkdir -p {}'.format(os.path.dirname(
REDFISH_LOGFILE)))
sys.exit(1) sys.exit(1)
# First logger to file # First logger to file

View File

@@ -5,9 +5,9 @@ from __future__ import print_function
from __future__ import division from __future__ import division
from __future__ import absolute_import from __future__ import absolute_import
from future import standard_library from future import standard_library
standard_library.install_aliases()
from builtins import str from builtins import str
from . import config from . import config
standard_library.install_aliases()
class RedfishException(Exception): class RedfishException(Exception):
@@ -28,7 +28,8 @@ class ConnectionFailureException(RedfishException):
'3- Check if your device has a valid trusted certificat\n' + \ '3- Check if your device has a valid trusted certificat\n' + \
' You can use openssl to validate it using the command :\n' + \ ' You can use openssl to validate it using the command :\n' + \
' openssl s_client -showcerts -connect <server>:443\n' + \ ' openssl s_client -showcerts -connect <server>:443\n' + \
'4- Use option "--insecure" to connect without checking certificate\n' '4- Use option "--insecure" to connect without checking' + \
' certificate\n'
class InvalidRedfishContentException(RedfishException): class InvalidRedfishContentException(RedfishException):

View File

@@ -29,8 +29,9 @@ resources.
A URI should be treated by the client as opaque, and thus should not be A URI should be treated by the client as opaque, and thus should not be
attempted to be understood or deconstructed by the client. Only specific top attempted to be understood or deconstructed by the client. Only specific top
level URIs (any URI in this sample code) may be assumed, and even these may be level URIs (any URI in this sample code) may be assumed, and even these may be
absent based upon the implementation (e.g. there might be no /redfish/v1/Systems absent based upon the implementation
collection on something that doesn't have compute nodes.) (e.g. there might be no /redfish/v1/Systems collection on something
that doesn't have compute nodes.)
The other URIs must be discovered dynamically by following href links. This is The other URIs must be discovered dynamically by following href links. This is
because the API will eventually be implemented on a system that breaks any because the API will eventually be implemented on a system that breaks any
@@ -125,7 +126,6 @@ standard_library.install_aliases()
from builtins import object from builtins import object
import json import json
import socket
from urllib.parse import urlparse, urljoin, urlunparse from urllib.parse import urlparse, urljoin, urlunparse
import requests import requests
from . import config from . import config
@@ -142,8 +142,7 @@ def connect(
password, password,
simulator=False, simulator=False,
enforceSSL=True, enforceSSL=True,
verify_cert=True verify_cert=True):
):
return RedfishConnection( return RedfishConnection(
url, url,
@@ -206,9 +205,6 @@ class RedfishConnection(object):
"this is insecure and can allow" + "this is insecure and can allow" +
" a man in the middle attack") " a man in the middle attack")
# Show redfish standard headers
config.logger.debug(self.connection_parameters.headers)
config.logger.debug("Root url : %s", config.logger.debug("Root url : %s",
self.connection_parameters.rooturl) self.connection_parameters.rooturl)
self.Root = types.Root(self.connection_parameters.rooturl, self.Root = types.Root(self.connection_parameters.rooturl,
@@ -218,8 +214,10 @@ class RedfishConnection(object):
mapping.redfish_version = self.get_api_version() mapping.redfish_version = self.get_api_version()
mapping.redfish_root_name = self.Root.get_name() mapping.redfish_root_name = self.Root.get_name()
# Instantiate a global mapping object to handle Redfish version variation # Instantiate a global mapping object to handle
mapping.redfish_mapper = mapping.RedfishVersionMapping(self.get_api_version(), self.Root.get_name()) # Redfish version variation
mapping.redfish_mapper = mapping.RedfishVersionMapping(
self.get_api_version(), self.Root.get_name())
# Now we need to login otherwise we are not allowed to extract data # Now we need to login otherwise we are not allowed to extract data
if self.__simulator is False: if self.__simulator is False:
@@ -229,9 +227,8 @@ class RedfishConnection(object):
config.logger.info("Login successful") config.logger.info("Login successful")
except "Error getting token": except "Error getting token":
config.logger.error("Login fail, fail to get auth token") config.logger.error("Login fail, fail to get auth token")
raise exception.AuthenticationFailureException("Fail to get an auth token.") raise exception.AuthenticationFailureException(
"Fail to get an auth token.")
# Structure change with mockup 1.0.0, there is no links # Structure change with mockup 1.0.0, there is no links
# section anymore. # section anymore.
@@ -241,28 +238,25 @@ class RedfishConnection(object):
# Types # Types
self.SessionService = types.SessionService( self.SessionService = types.SessionService(
self.Root.get_link_url( self.Root.get_link_url(
mapping.redfish_mapper.map_sessionservice()), mapping.redfish_mapper.map_sessionservice()),
self.connection_parameters self.connection_parameters)
)
self.Managers = types.ManagersCollection(self.Root.get_link_url("Managers"), self.Managers = types.ManagersCollection(
self.connection_parameters self.Root.get_link_url("Managers"),
) self.connection_parameters)
self.Systems = types.SystemsCollection(self.Root.get_link_url("Systems"), self.Systems = types.SystemsCollection(
self.connection_parameters self.Root.get_link_url("Systems"),
) self.connection_parameters)
# self.Chassis self.Chassis = types.ChassisCollection(
self.Root.get_link_url("Chassis"), self.connection_parameters)
# self.EventService # self.EventService
# self.AccountService # self.AccountService
# self.Tasks # self.Tasks
# ======================================================================== # ========================================================================
# systemCollectionLink = getattr(self.root.Links.Systems,"@odata.id") # systemCollectionLink = getattr(self.root.Links.Systems,"@odata.id")
# self.systemCollection = self.apiUrl.redfish.v1.Systems.get() # self.systemCollection = self.apiUrl.redfish.v1.Systems.get()
@@ -282,8 +276,7 @@ class RedfishConnection(object):
def login(self): def login(self):
# Craft full url # Craft full url
url = self.Root.get_link_url( url = self.Root.get_link_url(
mapping.redfish_mapper.map_sessionservice() mapping.redfish_mapper.map_sessionservice())
)
# Handle login with redfish 1.00, url must be : # Handle login with redfish 1.00, url must be :
# /rest/v1/SessionService/Sessions as specified by the specification # /rest/v1/SessionService/Sessions as specified by the specification
@@ -295,14 +288,17 @@ class RedfishConnection(object):
"Password": self.connection_parameters.password} "Password": self.connection_parameters.password}
config.logger.debug(requestBody) config.logger.debug(requestBody)
headers = self.connection_parameters.headers headers = self.connection_parameters.headers
# ======================================================================= # ====================================================================
# Tortilla seems not able to provide the header of a post request answer. # Tortilla seems not able to provide the header of a post request
# answer.
# However this is required by redfish standard to get X-Auth-Token. # However this is required by redfish standard to get X-Auth-Token.
# So jump to "requests" library to get the required token. # So jump to "requests" library to get the required token.
# TODO : Patch tortilla to handle this case. # TODO : Patch tortilla to handle this case.
# ======================================================================= # ====================================================================
# sessionsUrl = tortilla.wrap("https://10.3.222.104/rest/v1/Sessions", debug=TORTILLADEBUG) # sessionsUrl = tortilla.wrap(
# sessions = sessionsUrl.post(verify=self.verify_cert, data=requestBody) # "https://10.3.222.104/rest/v1/Sessions", debug=TORTILLADEBUG)
# sessions = sessionsUrl.post(
# verify=self.verify_cert, data=requestBody)
auth = requests.post(url, auth = requests.post(url,
data=json.dumps(requestBody), data=json.dumps(requestBody),
headers=headers, headers=headers,

View File

@@ -4,13 +4,14 @@ from __future__ import print_function
from __future__ import division from __future__ import division
from __future__ import absolute_import from __future__ import absolute_import
from future import standard_library from future import standard_library
standard_library.install_aliases()
from builtins import object from builtins import object
standard_library.install_aliases()
redfish_mapper = None redfish_mapper = None
redfish_version = None redfish_version = None
redfish_root_name = None redfish_root_name = None
class RedfishVersionMapping(object): class RedfishVersionMapping(object):
'''Implements basic url path mapping beetween Redfish versions.''' '''Implements basic url path mapping beetween Redfish versions.'''
@@ -24,7 +25,7 @@ class RedfishVersionMapping(object):
return 'SessionService' return 'SessionService'
def map_links(self, data_dict=None): def map_links(self, data_dict=None):
if data_dict == None: if data_dict is None:
if self.__version == '0.95': if self.__version == '0.95':
return 'links' return 'links'
else: else:
@@ -39,7 +40,7 @@ class RedfishVersionMapping(object):
return 'Links' return 'Links'
def map_links_ref(self, data_dict=None): def map_links_ref(self, data_dict=None):
if data_dict == None: if data_dict is None:
if self.__version == '0.95': if self.__version == '0.95':
return 'href' return 'href'
else: else:
@@ -49,11 +50,11 @@ class RedfishVersionMapping(object):
try: try:
data_dict.href data_dict.href
return 'href' return 'href'
except AttributeError: except AttributeError:
pass pass
return '@odata.id' return '@odata.id'
def map_members(self): def map_members(self):
if self.__version == '0.95': if self.__version == '0.95':
return 'Member' return 'Member'
return 'Members' return 'Members'

View File

@@ -18,6 +18,8 @@ from . import mapping
from . import exception from . import exception
standard_library.install_aliases() standard_library.install_aliases()
standard_library.install_aliases()
# Global variable # Global variable
@@ -26,11 +28,16 @@ class Base(object):
def __init__(self, url, connection_parameters): def __init__(self, url, connection_parameters):
'''Class constructor''' '''Class constructor'''
global TORTILLADEBUG global TORTILLADEBUG
self.connection_parameters = connection_parameters # Uggly hack to check self.connection_parameters = connection_parameters # Uggly hack
self.url = url self.url = url
self.api_url = tortilla.wrap(url, debug=config.TORTILLADEBUG) self.api_url = tortilla.wrap(url, debug=config.TORTILLADEBUG)
config.logger.debug(connection_parameters.headers) config.logger.debug(
"------------------------------------------------------------")
config.logger.debug("Url: %s" % url)
config.logger.debug("Header: %s" % connection_parameters.headers)
config.logger.debug(
"------------------------------------------------------------")
try: try:
self.data = self.api_url.get( self.data = self.api_url.get(
@@ -48,7 +55,7 @@ class Base(object):
'Ivalid content : Content does not appear to be a valid ' + \ 'Ivalid content : Content does not appear to be a valid ' + \
'Redfish json\n' 'Redfish json\n'
raise exception.InvalidRedfishContentException(msg) raise exception.InvalidRedfishContentException(msg)
config.logger.debug(self.data) config.logger.debug(pprint.PrettyPrinter(indent=4).pformat(self.data))
def get_link_url(self, link_type): def get_link_url(self, link_type):
'''Need to be explained. '''Need to be explained.
@@ -62,7 +69,9 @@ class Base(object):
if float(mapping.redfish_version) < 1.00: if float(mapping.redfish_version) < 1.00:
links = getattr(self.data, mapping.redfish_mapper.map_links()) links = getattr(self.data, mapping.redfish_mapper.map_links())
if link_type in links: if link_type in links:
return urljoin(self.url, links[link_type][mapping.redfish_mapper.map_links_ref()]) return urljoin(
self.url,
links[link_type][mapping.redfish_mapper.map_links_ref()])
raise AttributeError raise AttributeError
else: else:
links = getattr(self.data, link_type) links = getattr(self.data, link_type)
@@ -140,27 +149,134 @@ class BaseCollection(Base):
self.links = [] self.links = []
#linksmembers = self.data.Links.Members # linksmembers = self.data.Links.Members
#linksmembers = self.data.links.Member # linksmembers = self.data.links.Member
if float(mapping.redfish_version) < 1.00: if float(mapping.redfish_version) < 1.00:
linksmembers = getattr(self.data, mapping.redfish_mapper.map_links()) linksmembers = getattr(
linksmembers = getattr(linksmembers, mapping.redfish_mapper.map_members()) self.data, mapping.redfish_mapper.map_links())
linksmembers = getattr(
linksmembers, mapping.redfish_mapper.map_members())
else: else:
linksmembers = getattr(self.data, mapping.redfish_mapper.map_members()) linksmembers = getattr(
self.data, mapping.redfish_mapper.map_members())
for link in linksmembers: for link in linksmembers:
#self.links.append(getattr(link,'@odata.id')) # self.links.append(getattr(link,'@odata.id'))
#self.links.append(getattr(link,'href')) # self.links.append(getattr(link,'href'))
self.links.append(urljoin(self.url, getattr(link, mapping.redfish_mapper.map_links_ref()))) self.links.append(urljoin(
self.url, getattr(
link, mapping.redfish_mapper.map_links_ref())))
config.logger.debug(self.links) config.logger.debug(self.links)
class Device(Base):
'''Abstract class to add common methods between devices
(Chassis, Servers, System).
'''
def get_uuid(self):
'''Get device uuid
:returns: device uuid or "Not available"
:rtype: string
'''
try:
return self.data.UUID
except AttributeError:
return "Not available"
def get_status(self):
'''Get device status
:returns: device status or "Not available"
:rtype: dict
'''
try:
return self.data.Status
except AttributeError:
return "Not available"
def get_model(self):
'''Get device model
:returns: device model or "Not available"
:rtype: string
'''
try:
return self.data.Model
except AttributeError:
return "Not available"
def get_manufacturer(self):
'''Get device manufacturer
:returns: device manufacturer or "Not available"
:rtype: string
'''
try:
return self.data.Manufacturer
except AttributeError:
return "Not available"
def get_serial_number(self):
'''Get serial number of the device.
:returns: serial number or "Not available"
:rtype: string
'''
try:
return self.data.SerialNumber
except AttributeError:
return "Not available"
def get_asset_tag(self):
'''Get asset tag of the device.
:returns: asset tag or "Not available"
:rtype: string
'''
try:
return self.data.AssetTag
except AttributeError:
return "Not available"
def get_sku(self):
'''Get sku number of the device.
:returns: sku number or "Not available"
:rtype: string
'''
try:
return self.data.SKU
except AttributeError:
return "Not available"
def get_part_number(self):
'''Get part number of the device.
:returns: part number or "Not available"
:rtype: string
'''
try:
return self.data.PartNumber
except AttributeError:
return "Not available"
class Root(Base): class Root(Base):
'''Class to manage redfish Root data.''' '''Class to manage redfish Root data.'''
def get_api_version(self): def get_api_version(self):
'''Return api version. '''Return api version.
:returns: string -- version :returns: api version
:rtype: string
:raises: AttributeError :raises: AttributeError
''' '''
@@ -174,44 +290,39 @@ class Root(Base):
return(version) return(version)
def get_api_UUID(self): def get_api_UUID(self):
'''Return UUID version. '''Return api UUID.
:returns: string -- UUID :returns: api UUID
:rtype: string
''' '''
return self.data.UUID return self.data.UUID
def get_api_link_to_server(self):
'''Return api link to server.
:returns: string -- path
'''
return getattr(self.root.Links.Systems, '@odata.id')
class SessionService(Base): class SessionService(Base):
'''Class to manage redfish SessionService data.''' '''Class to manage redfish SessionService data.'''
pass pass
class Managers(Base): class Managers(Device):
'''Class to manage redfish Managers.''' '''Class to manage redfish Managers.'''
def __init__(self, url, connection_parameters): def __init__(self, url, connection_parameters):
super(Managers, self).__init__(url, connection_parameters) super(Managers, self).__init__(url, connection_parameters)
try: try:
# New proliant firmware now respects Redfish v1.00, so seems to correct below statement # New proliant firmware now respects Redfish v1.00, so seems to
# TODO : better handle exception and if possible support old firmware ? # correct below statement
# TODO : better handle exception and if possible support
# old firmware ?
self.ethernet_interfaces_collection = \ self.ethernet_interfaces_collection = \
EthernetInterfacesCollection( EthernetInterfacesCollection(
self.get_link_url('EthernetInterfaces'), self.get_link_url('EthernetInterfaces'),
connection_parameters) connection_parameters)
# Works on proliant, need to treat 095 vs 0.96 differences # Works on proliant, need to treat 095 vs 0.96 differences
#self.ethernet_interfaces_collection = EthernetInterfacesCollection( # self.ethernet_interfaces_collection = \
# self.get_link_url('EthernetNICs'), # EthernetInterfacesCollection(
# connection_parameters # self.get_link_url('EthernetNICs'),
# ) # connection_parameters)
except exception.InvalidRedfishContentException: except exception.InvalidRedfishContentException:
# This is to avoid invalid content from the mockup # This is to avoid invalid content from the mockup
self.ethernet_interfaces_collection = None self.ethernet_interfaces_collection = None
@@ -220,6 +331,18 @@ class Managers(Base):
# This means we don't have EthernetInterfaces # This means we don't have EthernetInterfaces
self.ethernet_interfaces_collection = None self.ethernet_interfaces_collection = None
def get_type(self):
'''Get manager type
:returns: manager type or "Not available"
:rtype: string
'''
try:
return self.data.ManagerType
except AttributeError:
return "Not available"
def get_firmware_version(self): def get_firmware_version(self):
'''Get firmware version of the manager '''Get firmware version of the manager
@@ -233,43 +356,11 @@ class Managers(Base):
# This is the case with the mockup for manager 2 and 3 # This is the case with the mockup for manager 2 and 3
return "Not available" return "Not available"
def get_type(self):
'''Get manager type
:returns: string -- manager type or "Not available"
'''
try:
return self.data.ManagerType
except AttributeError:
return "Not available"
def get_uuid(self):
'''Get manager type
:returns: string -- manager uuid or "Not available"
'''
try:
return self.data.UUID
except AttributeError:
return "Not available"
def get_status(self):
'''Get manager status
:returns: string -- manager status or "Not available"
'''
try:
return self.data.Status.State
except AttributeError:
return "Not available"
def get_managed_chassis(self): def get_managed_chassis(self):
'''Get managed chassis ids by the manager '''Get managed chassis ids by the manager
:returns: list -- chassis ids or "Not available" :returns: chassis ids or "Not available"
:rtype: list
''' '''
chassis_list = [] chassis_list = []
@@ -277,7 +368,9 @@ class Managers(Base):
try: try:
for chassis in links.ManagerForChassis: for chassis in links.ManagerForChassis:
result = re.search(r'Chassis/(\w+)', chassis[mapping.redfish_mapper.map_links_ref(chassis)]) result = re.search(
r'Chassis/(\w+)',
chassis[mapping.redfish_mapper.map_links_ref(chassis)])
chassis_list.append(result.group(1)) chassis_list.append(result.group(1))
return chassis_list return chassis_list
except AttributeError: except AttributeError:
@@ -286,7 +379,8 @@ class Managers(Base):
def get_managed_systems(self): def get_managed_systems(self):
'''Get managed systems ids by the manager '''Get managed systems ids by the manager
:returns: list -- chassis ids or "Not available" :returns: systems ids or "Not available"
:rtype: list
''' '''
systems_list = [] systems_list = []
@@ -294,7 +388,9 @@ class Managers(Base):
try: try:
for systems in links.ManagerForServers: for systems in links.ManagerForServers:
result = re.search(r'Systems/(\w+)', systems[mapping.redfish_mapper.map_links_ref(systems)]) result = re.search(
r'Systems/(\w+)',
systems[mapping.redfish_mapper.map_links_ref(systems)])
systems_list.append(result.group(1)) systems_list.append(result.group(1))
return systems_list return systems_list
except AttributeError: except AttributeError:
@@ -328,10 +424,11 @@ class ManagersCollection(BaseCollection):
self.managers_dict = {} self.managers_dict = {}
for link in self.links: for link in self.links:
index = re.search(r'Managers/(\w+)', link) index = re.search(r'Managers/(\w+)', link)
self.managers_dict[index.group(1)] = Managers(link, connection_parameters) self.managers_dict[index.group(1)] = Managers(
link, connection_parameters)
class Systems(Base): class Systems(Device):
'''Class to manage redfish Systems data.''' '''Class to manage redfish Systems data.'''
# TODO : Need to discuss with Bruno the required method. # TODO : Need to discuss with Bruno the required method.
# Also to check with the ironic driver requirement. # Also to check with the ironic driver requirement.
@@ -343,6 +440,33 @@ class Systems(Base):
except: except:
pass pass
try:
self.ethernet_interfaces_collection = \
EthernetInterfacesCollection(
self.get_link_url('EthernetInterfaces'),
connection_parameters)
except AttributeError:
# This means we don't have EthernetInterfaces
self.ethernet_interfaces_collection = None
try:
self.processors_collection = \
ProcessorsCollection(
self.get_link_url('Processors'),
connection_parameters)
except AttributeError:
# This means we don't have Processors detailed data
self.processors_collection = None
try:
self.simple_storage_collection = \
SimpleStorageCollection(
self.get_link_url('SimpleStorage'),
connection_parameters)
except AttributeError:
# This means we don't have Processors detailed data
self.simple_storage_collection = None
def reset_system(self): def reset_system(self):
'''Force reset of the system. '''Force reset of the system.
@@ -366,43 +490,150 @@ class Systems(Base):
def get_bios_version(self): def get_bios_version(self):
'''Get bios version of the system. '''Get bios version of the system.
:returns: string -- bios version :returns: bios version or "Not available"
:rtype: string
''' '''
try: try:
# Returned by proliant
return self.data.Bios.Current.VersionString
except:
# Returned by mockup.
# Hopefully this kind of discrepencies will be fixed with
# Redfish 1.0 (August)
return self.data.BiosVersion return self.data.BiosVersion
except AttributeError:
return "Not available"
def get_serial_number(self): def get_hostname(self):
'''Get serial number of the system. '''Get hostname of the system.
:returns: string -- serial number :returns: hostname or "Not available"
:rtype: string
''' '''
try: try:
# Returned by proliant return self.data.HostName
return self.data.SerialNumber except AttributeError:
except: return "Not available"
# Returned by mockup.
# Hopefully this kind of discrepencies will be fixed with def get_indicatorled(self):
# Redfish 1.0 (August) '''Get indicatorled of the system.
return ''
:returns: indicatorled status or "Not available"
:rtype: string
'''
try:
return self.data.IndicatorLED
except AttributeError:
return "Not available"
def get_power(self): def get_power(self):
'''Get power status of the system. '''Get power status of the system.
:returns: string -- power status or NULL if there is an issue :returns: system power state or "Not available"
:rtype: string
''' '''
try: try:
return self.data.Power return self.data.PowerState
except: except AttributeError:
return '' return "Not available"
def get_description(self):
'''Get description of the system.
:returns: system description or "Not available"
:rtype: string
'''
try:
return self.data.Description
except AttributeError:
return "Not available"
def get_cpucount(self):
'''Get the number of cpu in the system.
:returns: number of cpu or "Not available"
:rtype: string
'''
try:
return self.data.ProcessorSummary.Count
except AttributeError:
return "Not available"
def get_cpumodel(self):
'''Get the cpu model available in the system.
:returns: cpu model or "Not available"
:rtype: string
'''
try:
return self.data.ProcessorSummary.Model
except AttributeError:
return "Not available"
def get_memory(self):
'''Get the memory available in the system.
:returns: memory available or "Not available"
:rtype: string
'''
try:
return self.data.MemorySummary.TotalSystemMemoryGiB
except AttributeError:
return "Not available"
def get_type(self):
'''Get system type
:returns: system type or "Not available"
:rtype: string
'''
try:
return self.data.SystemType
except AttributeError:
return "Not available"
def get_chassis(self):
'''Get chassis ids used by the system
:returns: chassis ids or "Not available"
:rtype: list
'''
chassis_list = []
links = getattr(self.data, mapping.redfish_mapper.map_links(self.data))
try:
for chassis in links.Chassis:
result = re.search(
r'Chassis/(\w+)',
chassis[mapping.redfish_mapper.map_links_ref(chassis)])
chassis_list.append(result.group(1))
return chassis_list
except AttributeError:
return "Not available"
def get_managers(self):
'''Get manager ids used by the system
:returns: managers ids or "Not available"
:rtype: list
'''
managers_list = []
links = getattr(self.data, mapping.redfish_mapper.map_links(self.data))
try:
for manager in links.ManagedBy:
result = re.search(
r'Managers/(\w+)',
manager[mapping.redfish_mapper.map_links_ref(manager)])
managers_list.append(result.group(1))
return managers_list
except AttributeError:
return "Not available"
def set_parameter_json(self, value): def set_parameter_json(self, value):
'''Generic function to set any system parameter using json structure '''Generic function to set any system parameter using json structure
@@ -455,14 +686,16 @@ class SystemsCollection(BaseCollection):
for link in self.links: for link in self.links:
index = re.search(r'Systems/(\w+)', link) index = re.search(r'Systems/(\w+)', link)
self.systems_dict[index.group(1)] = Systems(link, connection_parameters) self.systems_dict[index.group(1)] = Systems(
link, connection_parameters)
class Bios(Base): class Bios(Base):
'''Class to manage redfish Bios data.''' '''Class to manage redfish Bios data.'''
def __init__(self, url, connection_parameters): def __init__(self, url, connection_parameters):
super(Bios, self).__init__(url, connection_parameters) super(Bios, self).__init__(url, connection_parameters)
self.boot = Boot(re.findall('.+/Bios', url)[0] + '/Boot/Settings', connection_parameters) self.boot = Boot(re.findall('.+/Bios', url)[0] +
'/Boot/Settings', connection_parameters)
class Boot(Base): class Boot(Base):
@@ -500,9 +733,13 @@ class EthernetInterfaces(Base):
''' '''
try: try:
# Proliant firmware seems to not follow redfish systax
return self.data.MacAddress return self.data.MacAddress
except AttributeError: except AttributeError:
return "Not available" try:
return self.data.MACAddress
except AttributeError:
return "Not available"
def get_fqdn(self): def get_fqdn(self):
'''Get EthernetInterface fqdn '''Get EthernetInterface fqdn
@@ -551,3 +788,180 @@ class EthernetInterfaces(Base):
except AttributeError: except AttributeError:
return "Not available" return "Not available"
class ProcessorsCollection(BaseCollection):
'''Class to manage redfish ProcessorsCollection data.'''
def __init__(self, url, connection_parameters):
super(ProcessorsCollection,
self).__init__(url, connection_parameters)
self.processors_dict = {}
for link in self.links:
index = re.search(r'Processors/(\w+)', link)
self.processors_dict[index.group(1)] = \
Processors(link, connection_parameters)
class Processors(Base):
'''Class to manage redfish Processors.'''
def get_speed(self):
'''Get processor speed
:returns: processor speed or "Not available"
:rtype: string
'''
try:
return self.data.MaxSpeedMHz
except AttributeError:
return "Not available"
def get_cores(self):
'''Get processor cores number
:returns: cores number or "Not available"
:rtype: string
'''
try:
return self.data.TotalCores
except AttributeError:
return "Not available"
def get_threads(self):
'''Get processor threads number
:returns: threads number or "Not available"
:rtype: string
'''
try:
return self.data.TotalThreads
except AttributeError:
return "Not available"
class SimpleStorageCollection(BaseCollection):
'''Class to manage redfish SimpleStorageCollection data.'''
def __init__(self, url, connection_parameters):
super(SimpleStorageCollection,
self).__init__(url, connection_parameters)
self.simple_storage_dict = {}
for link in self.links:
index = re.search(r'SimpleStorage/(\w+)', link)
self.simple_storage_dict[index.group(1)] = \
SimpleStorage(link, connection_parameters)
class SimpleStorage(Base):
'''Class to manage redfish SimpleStorage'''
def get_status(self):
'''Get storage status
:returns: storage status or "Not available"
:rtype: dict
'''
try:
return self.data.Status
except AttributeError:
return "Not available"
def get_devices(self):
'''Get storage devices
:returns: storage devices or "Not available"
:rtype: list of dict
'''
try:
return self.data.Devices
except AttributeError:
return "Not available"
class ChassisCollection(BaseCollection):
'''Class to manage redfish ChassisCollection data.'''
def __init__(self, url, connection_parameters):
super(ChassisCollection, self).__init__(url, connection_parameters)
self.chassis_dict = {}
for link in self.links:
index = re.search(r'Chassis/(\w+)', link)
self.chassis_dict[index.group(1)] = Chassis(
link, connection_parameters)
class Chassis(Device):
'''Class to manage redfish Chassis data.'''
def __init__(self, url, connection_parameters):
'''Class constructor'''
super(Chassis, self).__init__(url, connection_parameters)
try:
self.thermal = Thermal(self.get_link_url('Thermal'),
connection_parameters)
except AttributeError:
self.thermal = None
try:
self.power = Power(self.get_link_url('Power'),
connection_parameters)
except AttributeError:
self.Power = None
def get_type(self):
'''Get chassis type
:returns: chassis type or "Not available"
:rtype: string
'''
try:
return self.data.ChassisType
except AttributeError:
return "Not available"
class Thermal(Base):
'''Class to manage redfish Thermal data.'''
def get_temperatures(self):
'''Get chassis sensors name and temparature
:returns: chassis sensor and temperature
:rtype: dict
'''
temperatures = {}
try:
for sensor in self.data.Temperatures:
temperatures[sensor.Name] = sensor.ReadingCelsius
return temperatures
except AttributeError:
return "Not available"
def get_fans(self):
'''Get chassis fan name and rpm
:returns: chassis fan and rpm
:rtype: dict
'''
fans = {}
try:
for fan in self.data.Fans:
fans[fan.FanName] = fan.ReadingRPM
return fans
except AttributeError:
return "Not available"
class Power(Base):
'''Class to manage redfish Power data.'''
pass