diff --git a/redfish-client/redfish-check-cartridge b/redfish-client/redfish-check-cartridge new file mode 100755 index 0000000..27076aa --- /dev/null +++ b/redfish-client/redfish-check-cartridge @@ -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 = 'default' + else: + manager_name = arguments[''] + # 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) diff --git a/redfish-client/redfish-check-cartridge_usage.txt b/redfish-client/redfish-check-cartridge_usage.txt new file mode 100644 index 0000000..efa6030 --- /dev/null +++ b/redfish-client/redfish-check-cartridge_usage.txt @@ -0,0 +1,16 @@ +Usage: + check_cartridge [options] + 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] diff --git a/redfish-client/redfish-client b/redfish-client/redfish-client index e17ade8..f5a7d15 100755 --- a/redfish-client/redfish-client +++ b/redfish-client/redfish-client @@ -266,7 +266,7 @@ if __name__ == '__main__': # Parse and manage arguments 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: usage = usagefile.read() usagefile.close() diff --git a/redfish-client/usage.txt b/redfish-client/redfish-client_usage.txt similarity index 100% rename from redfish-client/usage.txt rename to redfish-client/redfish-client_usage.txt diff --git a/redfish/main.py b/redfish/main.py index fdfc1ea..c6be05f 100644 --- a/redfish/main.py +++ b/redfish/main.py @@ -242,16 +242,26 @@ class RedfishConnection(object): mapping.redfish_mapper.map_sessionservice()), self.connection_parameters) - self.Managers = standard.ManagersCollection( - self.Root.get_link_url("Managers"), - self.connection_parameters) + # Moonshot m510 cartridge has neither Managers nor Chassis, so handle + # this case in the code. + # 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.Root.get_link_url("Systems"), self.connection_parameters) - self.Chassis = standard.ChassisCollection( - self.Root.get_link_url("Chassis"), self.connection_parameters) + try: + self.Chassis = standard.ChassisCollection( + self.Root.get_link_url("Chassis"), self.connection_parameters) + except AttributeError: + self.Chassis = None # self.EventService # self.AccountService @@ -283,6 +293,7 @@ class RedfishConnection(object): if float(mapping.redfish_version) >= 1.00: url = urljoin(url, "Sessions") + config.logger.debug("Login URL : %s" % url) # Craft request body and header requestBody = {"UserName": self.connection_parameters.user_name, "Password": self.connection_parameters.password} diff --git a/setup.cfg b/setup.cfg index 6849e3d..bd13d2e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -19,6 +19,7 @@ classifier = Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.4 + Programming Language :: Python :: 3.5 [files] packages = @@ -27,7 +28,9 @@ packages = scripts = 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] conf = 'redfish-client/etc/redfish-client.conf', 'etc'