#!/usr/bin/python # coding=utf-8 ''' redfish-client Usage: redfish-client.py [options] config add [] [] redfish-client.py [options] config del redfish-client.py [options] config modify (manager_name | url | login | password) redfish-client.py [options] config show redfish-client.py [options] config showall redfish-client.py [options] manager getinfo [] redfish-client.py (-h | --help) redfish-client.py --version Options: -h --help Show this screen. --version Show version. --conf_file FILE Configuration file [default: ~/.redfish.conf] --insecure Check SSL certificats --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: redfish-client.log] --libdebugfile FILE Specify python-redfish library log file [default: /var/log/python-redfish/python-redfish.log] config commands : manage the configuration file. manager commands : manage the manager (Ligh out management). If is not provided use the 'default' entry ''' import os import sys import json import pprint import docopt import logging import redfish import requests.packages.urllib3 import jinja2 class ConfigFile(object): '''redfisht-client configuration file management''' def __init__(self, config_file): '''Initialize the configuration file Open and load configuration file data. If the file does not exist create an empty one ready to receive data :param config_file: File name of the configuration file default: ~/.redfish.conf :type str :returns: Nothing ''' self._config_file = config_file # read json file try: with open(self._config_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._config_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('Incorect 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 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 str :param url: Url of the manager :type str :param login: Login of the manager :type str :param password: Password of the manager :type 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 str :param parameter: url | login | password :type str :param parameter_value: Value of the parameter :type 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 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 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 str :returns: info containing url, login, password :type 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 redfish-client''' # Functions def show_manager(all=False): '''Display manager info :param all: Add login and password info :type bool :returns: Nothing ''' print('Managers configured :') for manager in conf_file.get_managers(): print(manager) if all is True: info = conf_file.get_manager_info(manager) print('\tUrl : {}'.format(info['url'])) print('\tLogin : {}'.format(info['login'])) print('\tPassword : {}'.format(info['password'])) def get_manager_info(manager_name, check_SSL): connection_parameters = conf_file.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: sys.stderr.write(str(e.message)) sys.stderr.write(str(e.advices)) sys.exit(1) # Display manager information using jinja2 template template = jinja2_env.get_template("manager_info.template") print template.render(r=remote_mgmt) # Main program redfishclient_version = "redfish-client 0.1" # Parse and manage arguments arguments = docopt.docopt(__doc__, version=redfishclient_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 ***" % redfishclient_version) logger.info("Arguments parsed") logger.debug(arguments) # Get $HOME environment. HOME = os.getenv('HOME') if not HOME: print('$HOME environment variable not set, please check your system') logger.error('$HOME environment variable not set') sys.exit(1) logger.debug("Home directory : %s" % HOME) arguments['--conf_file'] = arguments['--conf_file'].replace('~', HOME) conf_file = ConfigFile(arguments['--conf_file']) # Initialize Template system (jinja2) # TODO : set the template file location into cmd line default to /usr/share/python-redfish/templates ? logger.debug("Initialize template system") jinja2_env = jinja2.Environment(loader=jinja2.FileSystemLoader("templates")) if arguments['config'] is True: logger.debug("Config commands") if arguments['show'] is True: logger.debug('show command') show_manager() elif arguments['showall'] is True: logger.debug('showall command') show_manager(True) elif arguments['add'] is True: logger.debug('add command') conf_file.add_manager(arguments[''], arguments[''], arguments[''], arguments['']) logger.debug(conf_file.data) conf_file.save() elif arguments['del'] is True: logger.debug('del command') conf_file.delete_manager(arguments['']) logger.debug(conf_file.data) conf_file.save() elif arguments['modify'] is True: logger.debug('modify command') if arguments['url'] is not False: conf_file.modify_manager(arguments[''], 'url', arguments['']) elif arguments['login'] is not False: conf_file.modify_manager(arguments[''], 'login', arguments['']) elif arguments['password'] is not False: conf_file.modify_manager(arguments[''], 'password', arguments['']) elif arguments['manager_name'] is not False: conf_file.modify_manager(arguments[''], 'manager_name', arguments['']) logger.debug(conf_file.data) conf_file.save() if arguments['manager'] is True: logger.debug("Manager commands") if arguments['getinfo'] is True: logger.debug('getinfo command') # 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 conf_file.check_manager(manager_name) if arguments['--insecure'] is True: get_manager_info(manager_name, False) else: get_manager_info(manager_name, True) logger.info("Client session teminated") sys.exit(0)