Moonshot add on
- Add redfish-check-cartridge to check cartridge changes into a HPE Moonshot chassis. - Fix for m510 cartridges with first revision of firmware that do not have Manager and Chassis data. - Various updates to be pep8 compliant. Change-Id: Ie38cc5539e71aaf1041394fbbc6596c313f9bb47
This commit is contained in:
parent
f567a175c7
commit
abd3012ec0
383
redfish-client/redfish-check-cartridge
Executable file
383
redfish-client/redfish-check-cartridge
Executable file
@ -0,0 +1,383 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# coding=utf-8
|
||||||
|
|
||||||
|
'''
|
||||||
|
redfish-check_cartridge ::
|
||||||
|
This is a small program to check cartridge changes in HEP moonshot chassis.
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from future import standard_library
|
||||||
|
from builtins import str
|
||||||
|
from builtins import object
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import docopt
|
||||||
|
import logging
|
||||||
|
import configparser
|
||||||
|
import requests.packages.urllib3
|
||||||
|
import redfish
|
||||||
|
standard_library.install_aliases()
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryFile(object):
|
||||||
|
'''redfisht-client inventory file management'''
|
||||||
|
def __init__(self, inventory_file):
|
||||||
|
'''Initialize the inventory file
|
||||||
|
|
||||||
|
Open and load configuration file data.
|
||||||
|
If the file does not exist create an empty one ready to receive data
|
||||||
|
|
||||||
|
:param inventory_file: File name of the configuration file
|
||||||
|
default: ~/.redfish/inventory
|
||||||
|
:type config-file: str
|
||||||
|
:returns: Nothing
|
||||||
|
|
||||||
|
'''
|
||||||
|
self._inventory_file = inventory_file
|
||||||
|
# read json file
|
||||||
|
try:
|
||||||
|
with open(self._inventory_file) as json_data:
|
||||||
|
self.data = json.load(json_data)
|
||||||
|
json_data.close()
|
||||||
|
except (ValueError, IOError):
|
||||||
|
self.data = {'Managers': {}}
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
'''Save the configuration file data'''
|
||||||
|
try:
|
||||||
|
with open(self._inventory_file, 'w') as json_data:
|
||||||
|
json.dump(self.data, json_data)
|
||||||
|
json_data.close()
|
||||||
|
except IOError as e:
|
||||||
|
print(e.msg)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def manager_incorect(self, exception):
|
||||||
|
''' Log and exit if manager name is incorect'''
|
||||||
|
logger.error('Incorrect manager name : %s' % exception.args)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def check_manager(self, manager_name):
|
||||||
|
'''Check if the manager exists in configuration file
|
||||||
|
|
||||||
|
:param manager_name: Name of the manager
|
||||||
|
:type manager_name: str
|
||||||
|
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
if manager_name not in self.get_managers():
|
||||||
|
raise KeyError(manager_name)
|
||||||
|
except KeyError as e:
|
||||||
|
self.manager_incorect(e)
|
||||||
|
|
||||||
|
def add_manager(self, manager_name, url, login, password):
|
||||||
|
'''Add a manager to the configuration file
|
||||||
|
|
||||||
|
:param manager_name: Name of the manager
|
||||||
|
:type manager_name: str
|
||||||
|
:param url: Url of the manager
|
||||||
|
:type url: str
|
||||||
|
:param login: Login of the manager
|
||||||
|
:type login: str
|
||||||
|
:param password: Password of the manager
|
||||||
|
:type password: str
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
self.data['Managers'][manager_name] = {}
|
||||||
|
self.data['Managers'][manager_name]['url'] = url
|
||||||
|
if login is None:
|
||||||
|
login = ''
|
||||||
|
if password is None:
|
||||||
|
password = ''
|
||||||
|
self.data['Managers'][manager_name]['login'] = login
|
||||||
|
self.data['Managers'][manager_name]['password'] = password
|
||||||
|
|
||||||
|
def modify_manager(self, manager_name, parameter, parameter_value):
|
||||||
|
'''Modify the manager settings
|
||||||
|
|
||||||
|
:param manager_name: Name of the manager
|
||||||
|
:type manager_name: str
|
||||||
|
:param parameter: url | login | password
|
||||||
|
:type url: str
|
||||||
|
:param parameter_value: Value of the parameter
|
||||||
|
:type parameter_value: str
|
||||||
|
:returns: Nothing
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
if parameter == 'url':
|
||||||
|
try:
|
||||||
|
self.data['Managers'][manager_name]['url'] = parameter_value
|
||||||
|
except KeyError as e:
|
||||||
|
self.manager_incorect(e)
|
||||||
|
elif parameter == 'login':
|
||||||
|
try:
|
||||||
|
self.data['Managers'][manager_name]['login'] = parameter_value
|
||||||
|
except KeyError as e:
|
||||||
|
self.manager_incorect(e)
|
||||||
|
elif parameter == 'password':
|
||||||
|
try:
|
||||||
|
self.data['Managers'][manager_name]['password'] \
|
||||||
|
= parameter_value
|
||||||
|
except KeyError as e:
|
||||||
|
self.manager_incorect(e)
|
||||||
|
elif parameter == 'manager_name':
|
||||||
|
# Create a new entry with the new name
|
||||||
|
self.add_manager(parameter_value,
|
||||||
|
self.data['Managers'][manager_name]['url'],
|
||||||
|
self.data['Managers'][manager_name]['login'],
|
||||||
|
self.data['Managers'][manager_name]['password'],
|
||||||
|
)
|
||||||
|
# Remove the previous one
|
||||||
|
self.delete_manager(manager_name)
|
||||||
|
|
||||||
|
def delete_manager(self, manager_name):
|
||||||
|
'''Delete manager
|
||||||
|
|
||||||
|
:param manager_name: Name of the manager
|
||||||
|
:type manager_name: str
|
||||||
|
:returns: Nothing
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
try:
|
||||||
|
del self.data['Managers'][manager_name]
|
||||||
|
except KeyError as e:
|
||||||
|
self.manager_incorect(e)
|
||||||
|
|
||||||
|
def get_managers(self):
|
||||||
|
'''Get manager configured
|
||||||
|
|
||||||
|
:returns: Managers
|
||||||
|
:type returns: list
|
||||||
|
|
||||||
|
'''
|
||||||
|
managers = []
|
||||||
|
for manager in self.data['Managers']:
|
||||||
|
managers += [manager]
|
||||||
|
return(managers)
|
||||||
|
|
||||||
|
def get_manager_info(self, manager):
|
||||||
|
'''Show manager info (url, login, password)
|
||||||
|
|
||||||
|
:param manager: Name of the manager
|
||||||
|
:type manager: str
|
||||||
|
:returns: info containing url, login, password
|
||||||
|
:type returns: dict
|
||||||
|
|
||||||
|
'''
|
||||||
|
info = {}
|
||||||
|
url = self.data['Managers'][manager]['url']
|
||||||
|
login = self.data['Managers'][manager]['login']
|
||||||
|
password = self.data['Managers'][manager]['password']
|
||||||
|
info = {'url': url, 'login': login, 'password': password}
|
||||||
|
return(info)
|
||||||
|
|
||||||
|
|
||||||
|
class RedfishClientException(Exception):
|
||||||
|
|
||||||
|
'''Base class for redfish client exceptions'''
|
||||||
|
|
||||||
|
def __init__(self, message=None, **kwargs):
|
||||||
|
self.kwargs = kwargs
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
'''Main application check_cartridge'''
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
# Main program
|
||||||
|
#################################################################
|
||||||
|
check_cartridge_version = "check_cartridge PBVER"
|
||||||
|
|
||||||
|
# Parse and manage arguments
|
||||||
|
try:
|
||||||
|
usagefp = os.path.dirname(sys.argv[0]) + \
|
||||||
|
"/redfish-check-cartridge_usage.txt"
|
||||||
|
with open(usagefp) as usagefile:
|
||||||
|
usage = usagefile.read()
|
||||||
|
usagefile.close()
|
||||||
|
except (ValueError, IOError):
|
||||||
|
print("Usage file {} cannot be found.".format(usagefp))
|
||||||
|
sys.exit(1)
|
||||||
|
arguments = docopt.docopt(usage, version=check_cartridge_version)
|
||||||
|
|
||||||
|
# Check debuging options
|
||||||
|
# Debugging LEVEL :
|
||||||
|
# 1- Only client
|
||||||
|
# 2- Client and lib
|
||||||
|
# 3- Client and lib + Tortilla
|
||||||
|
|
||||||
|
loglevel = {"console_logger_level": "nolog",
|
||||||
|
"file_logger_level": logging.INFO,
|
||||||
|
"tortilla": False,
|
||||||
|
"lib_console_logger_level": "nolog",
|
||||||
|
"lib_file_logger_level": logging.INFO,
|
||||||
|
"urllib3_disable_warning": True}
|
||||||
|
|
||||||
|
if arguments['--debug'] == '1':
|
||||||
|
loglevel['console_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['file_logger_level'] = logging.DEBUG
|
||||||
|
elif arguments['--debug'] == '2':
|
||||||
|
loglevel['console_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['file_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['lib_console_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['lib_file_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['urllib3_disable_warning'] = False
|
||||||
|
elif arguments['--debug'] == '3':
|
||||||
|
loglevel['console_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['file_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['lib_console_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['lib_file_logger_level'] = logging.DEBUG
|
||||||
|
loglevel['urllib3_disable_warning'] = False
|
||||||
|
loglevel['tortilla'] = True
|
||||||
|
|
||||||
|
# Initialize logger according to command line parameters
|
||||||
|
logger = redfish.config.initialize_logger(arguments['--debugfile'],
|
||||||
|
loglevel['console_logger_level'],
|
||||||
|
loglevel['file_logger_level'],
|
||||||
|
__name__)
|
||||||
|
redfish.config.REDFISH_LOGFILE = arguments['--libdebugfile']
|
||||||
|
redfish.config.TORTILLADEBUG = loglevel['tortilla']
|
||||||
|
redfish.config.CONSOLE_LOGGER_LEVEL = loglevel['lib_console_logger_level']
|
||||||
|
redfish.config.FILE_LOGGER_LEVEL = loglevel['lib_file_logger_level']
|
||||||
|
# Avoid warning messages from request / urllib3
|
||||||
|
# SecurityWarning: Certificate has no `subjectAltName`, falling back
|
||||||
|
# to check for a `commonName` for now. This feature is being removed
|
||||||
|
# by major browsers and deprecated by RFC 2818.
|
||||||
|
# (See https://github.com/shazow/urllib3/issues/497 for details.)
|
||||||
|
if loglevel['urllib3_disable_warning'] is True:
|
||||||
|
requests.packages.urllib3.disable_warnings()
|
||||||
|
|
||||||
|
logger.info("*** Starting %s ***" % check_cartridge_version)
|
||||||
|
logger.info("Arguments parsed")
|
||||||
|
logger.debug(arguments)
|
||||||
|
|
||||||
|
# Load config
|
||||||
|
config = configparser.ConfigParser(allow_no_value=True)
|
||||||
|
logger.debug("Read configuration file")
|
||||||
|
configfile = 'PBCONFFILE'
|
||||||
|
|
||||||
|
if(arguments['--config']):
|
||||||
|
configfile = arguments['--config']
|
||||||
|
logger.debug("Overwrite configuration specified by user at %s"
|
||||||
|
% configfile)
|
||||||
|
|
||||||
|
if(os.path.isfile(configfile)):
|
||||||
|
logger.debug('Configuration found at %s.' % configfile)
|
||||||
|
config.read(configfile)
|
||||||
|
else:
|
||||||
|
print('Configuration file not found at {}.'.format(configfile))
|
||||||
|
logger.error('Configuration file not found at %s.' % configfile)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
arguments['--inventory'] = os.path.expandvars(arguments['--inventory'])
|
||||||
|
inventory = InventoryFile(arguments['--inventory'])
|
||||||
|
|
||||||
|
# Check cmd line parameters
|
||||||
|
# If manager is not defined set it to 'default'
|
||||||
|
if not arguments['<manager_name>']:
|
||||||
|
manager_name = 'default'
|
||||||
|
else:
|
||||||
|
manager_name = arguments['<manager_name>']
|
||||||
|
# Check if the default section is available in our conf file
|
||||||
|
inventory.check_manager(manager_name)
|
||||||
|
connection_parameters = inventory.get_manager_info(manager_name)
|
||||||
|
|
||||||
|
print('Gathering data from manager, please wait...\n')
|
||||||
|
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)
|
||||||
|
print('Get cartridge list\n')
|
||||||
|
|
||||||
|
cartridge_file = os.path.join(os.path.dirname(arguments['--inventory']),
|
||||||
|
'cartridge.json')
|
||||||
|
|
||||||
|
current_cartridge = redfish_data.Systems.systems_dict.keys()
|
||||||
|
previous_cartridge = []
|
||||||
|
|
||||||
|
if os.path.isfile(cartridge_file):
|
||||||
|
with open(cartridge_file, 'r') as f:
|
||||||
|
previous_cartridge = json.load(f)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
print('Writing cartridge list to file')
|
||||||
|
with open(cartridge_file, 'w') as f:
|
||||||
|
if len(current_cartridge) > 0:
|
||||||
|
json.dump(current_cartridge, f)
|
||||||
|
else:
|
||||||
|
f.write('{}')
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
print("Current cartridges:")
|
||||||
|
print("{}\n".format(", ".join(current_cartridge)))
|
||||||
|
|
||||||
|
if not previous_cartridge:
|
||||||
|
print("First run, changes can not be evaluated")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
current_cartridge = set(current_cartridge)
|
||||||
|
previous_cartridge = set(previous_cartridge)
|
||||||
|
|
||||||
|
print("Computing changes...\n")
|
||||||
|
|
||||||
|
# Check if we have added a cartridge
|
||||||
|
diff = current_cartridge - previous_cartridge
|
||||||
|
print("Cartridges added:")
|
||||||
|
if diff:
|
||||||
|
print("{}".format(", ".join(diff)))
|
||||||
|
for item in diff:
|
||||||
|
system = redfish_data.Systems.systems_dict[item]
|
||||||
|
print(system.get_name())
|
||||||
|
print(system.get_model())
|
||||||
|
print(system.get_uuid())
|
||||||
|
print("Memory: {}".format(
|
||||||
|
system.data.Memory.TotalSystemMemoryGB))
|
||||||
|
print("MAC@: {}".format(
|
||||||
|
system.data.HostCorrelation.HostMACAddress))
|
||||||
|
print("------------------")
|
||||||
|
else:
|
||||||
|
print("None")
|
||||||
|
|
||||||
|
# Check if we have removed a cartridge
|
||||||
|
diff = previous_cartridge - current_cartridge
|
||||||
|
print("Cartridges removed:")
|
||||||
|
if diff:
|
||||||
|
print("{}\n".format(", ".join(diff)))
|
||||||
|
else:
|
||||||
|
print("None")
|
||||||
|
|
||||||
|
logger.info("Client session terminated")
|
||||||
|
sys.exit(0)
|
16
redfish-client/redfish-check-cartridge_usage.txt
Normal file
16
redfish-client/redfish-check-cartridge_usage.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Usage:
|
||||||
|
check_cartridge [options] <manager_name>
|
||||||
|
check_cartridge (-h | --help)
|
||||||
|
check_cartridge --version
|
||||||
|
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h --help Show this screen.
|
||||||
|
--version Show version.
|
||||||
|
-c --config FILE Configuration file
|
||||||
|
-i --inventory FILE Configuration file [default: $HOME/.redfish/inventory]
|
||||||
|
--insecure Ignore SSL certificates
|
||||||
|
--debug LEVEL Run in debug mode, LEVEL from 1 to 3 increase verbosity
|
||||||
|
Security warning LEVEL > 1 could reveal password into the logs
|
||||||
|
--debugfile FILE Specify the client debugfile [default: $HOME/.redfish/check_cartridge.log]
|
||||||
|
--libdebugfile FILE Specify python-redfish library log file [default: $HOME/.redfish/python-redfish.log]
|
@ -266,7 +266,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# Parse and manage arguments
|
# Parse and manage arguments
|
||||||
try:
|
try:
|
||||||
usagefp = os.path.dirname(sys.argv[0]) + "/usage.txt"
|
usagefp = os.path.dirname(sys.argv[0]) + "/redfish-client_usage.txt"
|
||||||
with open(usagefp) as usagefile:
|
with open(usagefp) as usagefile:
|
||||||
usage = usagefile.read()
|
usage = usagefile.read()
|
||||||
usagefile.close()
|
usagefile.close()
|
||||||
|
@ -242,16 +242,26 @@ class RedfishConnection(object):
|
|||||||
mapping.redfish_mapper.map_sessionservice()),
|
mapping.redfish_mapper.map_sessionservice()),
|
||||||
self.connection_parameters)
|
self.connection_parameters)
|
||||||
|
|
||||||
self.Managers = standard.ManagersCollection(
|
# Moonshot m510 cartridge has neither Managers nor Chassis, so handle
|
||||||
self.Root.get_link_url("Managers"),
|
# this case in the code.
|
||||||
self.connection_parameters)
|
# Note : m510 ilo firmware is in an early stage, this state could be
|
||||||
|
# temporary.
|
||||||
|
try:
|
||||||
|
self.Managers = standard.ManagersCollection(
|
||||||
|
self.Root.get_link_url("Managers"),
|
||||||
|
self.connection_parameters)
|
||||||
|
except AttributeError:
|
||||||
|
self.Managers = None
|
||||||
|
|
||||||
self.Systems = standard.SystemsCollection(
|
self.Systems = standard.SystemsCollection(
|
||||||
self.Root.get_link_url("Systems"),
|
self.Root.get_link_url("Systems"),
|
||||||
self.connection_parameters)
|
self.connection_parameters)
|
||||||
|
|
||||||
self.Chassis = standard.ChassisCollection(
|
try:
|
||||||
self.Root.get_link_url("Chassis"), self.connection_parameters)
|
self.Chassis = standard.ChassisCollection(
|
||||||
|
self.Root.get_link_url("Chassis"), self.connection_parameters)
|
||||||
|
except AttributeError:
|
||||||
|
self.Chassis = None
|
||||||
|
|
||||||
# self.EventService
|
# self.EventService
|
||||||
# self.AccountService
|
# self.AccountService
|
||||||
@ -283,6 +293,7 @@ class RedfishConnection(object):
|
|||||||
if float(mapping.redfish_version) >= 1.00:
|
if float(mapping.redfish_version) >= 1.00:
|
||||||
url = urljoin(url, "Sessions")
|
url = urljoin(url, "Sessions")
|
||||||
|
|
||||||
|
config.logger.debug("Login URL : %s" % url)
|
||||||
# Craft request body and header
|
# Craft request body and header
|
||||||
requestBody = {"UserName": self.connection_parameters.user_name,
|
requestBody = {"UserName": self.connection_parameters.user_name,
|
||||||
"Password": self.connection_parameters.password}
|
"Password": self.connection_parameters.password}
|
||||||
|
@ -19,6 +19,7 @@ classifier =
|
|||||||
Programming Language :: Python :: 2.7
|
Programming Language :: Python :: 2.7
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3.4
|
Programming Language :: Python :: 3.4
|
||||||
|
Programming Language :: Python :: 3.5
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
packages =
|
packages =
|
||||||
@ -27,7 +28,9 @@ packages =
|
|||||||
|
|
||||||
scripts =
|
scripts =
|
||||||
redfish-client/redfish-client
|
redfish-client/redfish-client
|
||||||
redfish-client/usage.txt
|
redfish-client/redfish-client_usage.txt
|
||||||
|
redfish-client/redfish-check-cartridge
|
||||||
|
redfish-client/redfish-check-cartridge_usage.txt
|
||||||
|
|
||||||
[data_files_helper]
|
[data_files_helper]
|
||||||
conf = 'redfish-client/etc/redfish-client.conf', 'etc'
|
conf = 'redfish-client/etc/redfish-client.conf', 'etc'
|
||||||
|
Loading…
Reference in New Issue
Block a user