Merge pull request #11 from uggla/devel
My modifications for future version 0.3
This commit is contained in:
commit
df2c027823
@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
function start_apache {
|
||||
[ -f "/run/apache2/apache2.pid" ] && rm "/run/apache2/apache2.pid"
|
||||
echo "Launching apache2 in foreground with /usr/sbin/apache2ctl -DFOREGROUND -k start"
|
||||
/usr/sbin/apache2ctl -DFOREGROUND -k start
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import os
|
||||
import sys
|
||||
import json
|
||||
import redfish
|
||||
from time import sleep
|
||||
|
||||
|
||||
# Get $HOME environment.
|
||||
HOME = os.getenv('HOME')
|
||||
@ -24,17 +24,26 @@ except IOError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
URL = config["Nodes"]["default"]["url"]
|
||||
USER_NAME = config["Nodes"]["default"]["login"]
|
||||
PASSWORD = config["Nodes"]["default"]["password"]
|
||||
URL = config["Managers"]["default"]["url"]
|
||||
USER_NAME = config["Managers"]["default"]["login"]
|
||||
PASSWORD = config["Managers"]["default"]["password"]
|
||||
|
||||
''' remote_mgmt is a redfish.RedfishConnection object '''
|
||||
remote_mgmt = redfish.connect(URL, USER_NAME, PASSWORD, verify_cert=False)
|
||||
try:
|
||||
remote_mgmt = redfish.connect(URL,
|
||||
USER_NAME,
|
||||
PASSWORD,
|
||||
simulator=False,
|
||||
verify_cert=False)
|
||||
except redfish.exception.RedfishException as e:
|
||||
sys.stderr.write(str(e.message))
|
||||
sys.stderr.write(str(e.advices))
|
||||
sys.exit(1)
|
||||
|
||||
print ("Redfish API version : %s \n" % remote_mgmt.get_api_version())
|
||||
|
||||
# Uncomment following line to reset the blade !!!
|
||||
#remote_mgmt.Systems.systems_list[0].reset_system()
|
||||
# remote_mgmt.Systems.systems_list[0].reset_system()
|
||||
|
||||
# TODO : create an attribute to link the managed system directly
|
||||
# and avoid systems_list[0]
|
||||
|
@ -23,13 +23,22 @@ except IOError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
URL = config["Nodes"]["default"]["url"]
|
||||
USER_NAME = config["Nodes"]["default"]["login"]
|
||||
PASSWORD = config["Nodes"]["default"]["password"]
|
||||
URL = config["Managers"]["default"]["url"]
|
||||
USER_NAME = config["Managers"]["default"]["login"]
|
||||
PASSWORD = config["Managers"]["default"]["password"]
|
||||
|
||||
''' remoteMgmt is a redfish.RedfishConnection object '''
|
||||
remote_mgmt = redfish.connect(URL, USER_NAME, PASSWORD,
|
||||
simulator=True, enforceSSL=False)
|
||||
try:
|
||||
remote_mgmt = redfish.connect(URL,
|
||||
USER_NAME,
|
||||
PASSWORD,
|
||||
simulator=True,
|
||||
enforceSSL=False)
|
||||
except redfish.exception.RedfishException as e:
|
||||
sys.stderr.write(e.message)
|
||||
sys.stderr.write(e.advices)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
print("Redfish API version : {} \n".format(remote_mgmt.get_api_version()))
|
||||
print("UUID : {} \n".format(remote_mgmt.Root.get_api_UUID()))
|
||||
|
@ -2,125 +2,391 @@
|
||||
|
||||
# coding=utf-8
|
||||
|
||||
"""
|
||||
'''
|
||||
redfish-client
|
||||
|
||||
Usage:
|
||||
redfish-client.py [options] config add <manager_name> <manager_url> [<login>] [<password>]
|
||||
redfish-client.py [options] config del <manager_name>
|
||||
redfish-client.py [options] config modify <manager_name> (url | login | password) <changed_value>
|
||||
redfish-client.py [options] config modify <manager_name> (manager_name | url | login | password) <changed_value>
|
||||
redfish-client.py [options] config show
|
||||
redfish-client.py [options] config showall
|
||||
redfish-client.py [options] manager getinfo [<manager_name>]
|
||||
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].
|
||||
-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.
|
||||
|
||||
"""
|
||||
config commands : manage the configuration file.
|
||||
manager commands : manage the manager (Ligh out management). If <manager_name>
|
||||
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):
|
||||
self._config_file = 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":{}}
|
||||
self.data = {'Managers': {}}
|
||||
|
||||
def save(self):
|
||||
'''Save the configuration file data'''
|
||||
try:
|
||||
with open(self._config_file , 'w') as json_data:
|
||||
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)
|
||||
|
||||
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 != None:
|
||||
self.data['Managers'][manager_name]['login'] = login
|
||||
if password != None:
|
||||
self.data['Managers'][manager_name]['password'] = password
|
||||
|
||||
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]
|
||||
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)
|
||||
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"""
|
||||
|
||||
'''Base class for redfish client exceptions'''
|
||||
|
||||
def __init__(self, message=None, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
self.message = message
|
||||
self.message = message
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
'''Main application redfish-client'''
|
||||
# Functions
|
||||
|
||||
def show_manager(all=False):
|
||||
print("Managers configured :")
|
||||
'''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 == True:
|
||||
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']))
|
||||
|
||||
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 HOME == '':
|
||||
print("$HOME environment variable not set, please check your system")
|
||||
if not HOME:
|
||||
print('$HOME environment variable not set, please check your system')
|
||||
logger.error('$HOME environment variable not set')
|
||||
sys.exit(1)
|
||||
|
||||
arguments = docopt.docopt(__doc__, version='redfish-client 0.1')
|
||||
print(arguments)
|
||||
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'] == True:
|
||||
if arguments['show'] == True:
|
||||
if arguments['config'] is True:
|
||||
logger.debug("Config commands")
|
||||
if arguments['show'] is True:
|
||||
logger.debug('show command')
|
||||
show_manager()
|
||||
elif arguments['showall'] == True:
|
||||
elif arguments['showall'] is True:
|
||||
logger.debug('showall command')
|
||||
show_manager(True)
|
||||
elif arguments['add'] == True:
|
||||
elif arguments['add'] is True:
|
||||
logger.debug('add command')
|
||||
conf_file.add_manager(arguments['<manager_name>'],
|
||||
arguments['<manager_url>'],
|
||||
arguments['<login>'],
|
||||
arguments['password'])
|
||||
pprint.pprint(conf_file.data)
|
||||
|
||||
conf_file.save()
|
||||
|
||||
arguments['<password>'])
|
||||
logger.debug(conf_file.data)
|
||||
conf_file.save()
|
||||
elif arguments['del'] is True:
|
||||
logger.debug('del command')
|
||||
conf_file.delete_manager(arguments['<manager_name>'])
|
||||
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['<manager_name>'],
|
||||
'url',
|
||||
arguments['<changed_value>'])
|
||||
elif arguments['login'] is not False:
|
||||
conf_file.modify_manager(arguments['<manager_name>'],
|
||||
'login',
|
||||
arguments['<changed_value>'])
|
||||
elif arguments['password'] is not False:
|
||||
conf_file.modify_manager(arguments['<manager_name>'],
|
||||
'password',
|
||||
arguments['<changed_value>'])
|
||||
elif arguments['manager_name'] is not False:
|
||||
conf_file.modify_manager(arguments['<manager_name>'],
|
||||
'manager_name',
|
||||
arguments['<changed_value>'])
|
||||
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>']:
|
||||
manager_name = 'default'
|
||||
else:
|
||||
manager_name = arguments['<manager_name>']
|
||||
# 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)
|
||||
|
32
redfish-client/templates/bla.templates
Normal file
32
redfish-client/templates/bla.templates
Normal file
@ -0,0 +1,32 @@
|
||||
#=======================================================================
|
||||
# print('Redfish API version : %s' % remote_mgmt.get_api_version())
|
||||
# print(remote_mgmt.Root.get_name())
|
||||
# print('\n')
|
||||
# print('Managers information :')
|
||||
# print('----------------------')
|
||||
# for manager_index in sorted(remote_mgmt.Managers.managers_dict):
|
||||
# manager = remote_mgmt.Managers.managers_dict[manager_index]
|
||||
# print('\nManager id {} :').format(manager_index)
|
||||
# print('UUID : {}').format(manager.get_uuid())
|
||||
# print('Type : {}').format(manager.get_type())
|
||||
# print('Firmware version : {}').format(manager.get_firmware_version())
|
||||
# print('State : {}').format(manager.get_status())
|
||||
# print manager.get_managed_chassis()
|
||||
# print manager.get_managed_systems()
|
||||
# print('Ethernet interfaces :')
|
||||
# try :
|
||||
# for ethernetinterface_index in sorted(manager.ethernet_interfaces_collection.ethernet_interfaces_dict):
|
||||
# ei = manager.ethernet_interfaces_collection.ethernet_interfaces_dict[ethernetinterface_index]
|
||||
# print('\nEthernet Interface id {} :').format(ethernetinterface_index)
|
||||
# print(ei.get_name())
|
||||
# print(ei.get_parameter('FQDN'))
|
||||
# print ei.get_ipv4()
|
||||
# print ei.get_ipv6()
|
||||
# except AttributeError:
|
||||
# # We don't have ethernet interfaces
|
||||
# pass
|
||||
#=======================================================================
|
||||
|
||||
|
||||
Redfish API version : remote_mgmt.get_api_version()
|
||||
remote_mgmt.Root.get_name()
|
31
redfish-client/templates/manager_info.template
Normal file
31
redfish-client/templates/manager_info.template
Normal file
@ -0,0 +1,31 @@
|
||||
Redfish API version : {{ r.get_api_version() }}
|
||||
{{ r.Root.get_name() }}
|
||||
|
||||
Managers information :
|
||||
======================
|
||||
{% for manager_index in r.Managers.managers_dict | sort %}
|
||||
{%- set manager = r.Managers.managers_dict[manager_index] %}
|
||||
Manager id {{ manager_index }}:
|
||||
UUID : {{ manager.get_uuid() }}
|
||||
Type : {{ manager.get_type() }}
|
||||
Firmware version : {{ manager.get_firmware_version() }}
|
||||
State : {{ manager.get_status() }}
|
||||
Ethernet Interface :
|
||||
{%- if manager.ethernet_interfaces_collection %}
|
||||
{%- for ethernetinterface_index in manager.ethernet_interfaces_collection.ethernet_interfaces_dict | sort %}
|
||||
{%- set ei = manager.ethernet_interfaces_collection.ethernet_interfaces_dict[ethernetinterface_index] %}
|
||||
Ethernet Interface id {{ ethernetinterface_index }} :
|
||||
{{ ei.get_name() }}
|
||||
FQDN : {{ ei.get_fqdn() }}
|
||||
Address ipv4 : {{ ei.get_ipv4() | join(', ') }}
|
||||
Address ipv6 : {{ ei.get_ipv6() | join(', ') }}
|
||||
{%- endfor %}
|
||||
{%- else %}
|
||||
This manager has no ethernet interface
|
||||
{%- endif %}
|
||||
Managed Chassis :
|
||||
{{ manager.get_managed_chassis() | join(', ') }}
|
||||
Managed System :
|
||||
{{ manager.get_managed_systems() | join(', ') }}
|
||||
----------------------------
|
||||
{% endfor %}
|
@ -4,34 +4,46 @@ import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
# Global variable definition
|
||||
TORTILLADEBUG = True
|
||||
|
||||
logger = None
|
||||
TORTILLADEBUG = True
|
||||
REDFISH_LOGFILE = "/var/log/python-redfish/python-redfish.log"
|
||||
CONSOLE_LOGGER_LEVEL = logging.DEBUG
|
||||
FILE_LOGGER_LEVEL = logging.DEBUG
|
||||
|
||||
|
||||
def initialize_logger(redfish_logfile):
|
||||
"""Return api version.
|
||||
def initialize_logger(REDFISH_LOGFILE,
|
||||
CONSOLE_LOGGER_LEVEL,
|
||||
FILE_LOGGER_LEVEL,
|
||||
logger_name=None):
|
||||
'''Initialize a global logger to track application behaviour
|
||||
|
||||
:param redfish_logfile: redfish log
|
||||
:param redfish_logfile: Log filename
|
||||
:type str
|
||||
:returns: True
|
||||
:param screen_logger_level: Console log level
|
||||
(logging.DEBUG, logging.ERROR, ..) or nolog
|
||||
:type logging constant or string
|
||||
:param file_logger_level: File log level
|
||||
:type logging constant
|
||||
:returns: logging object
|
||||
|
||||
"""
|
||||
global logger
|
||||
logger = logging.getLogger()
|
||||
|
||||
'''
|
||||
|
||||
logger = logging.getLogger(logger_name)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s :: %(levelname)s :: %(message)s'
|
||||
)
|
||||
file_handler = RotatingFileHandler(redfish_logfile, 'a', 1000000, 1)
|
||||
file_handler = RotatingFileHandler(REDFISH_LOGFILE, 'a', 1000000, 1)
|
||||
|
||||
# First logger to file
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
file_handler.setLevel(FILE_LOGGER_LEVEL)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
# Second logger to console
|
||||
steam_handler = logging.StreamHandler()
|
||||
steam_handler.setLevel(logging.DEBUG)
|
||||
logger.addHandler(steam_handler)
|
||||
return True
|
||||
if CONSOLE_LOGGER_LEVEL != "nolog":
|
||||
steam_handler = logging.StreamHandler()
|
||||
steam_handler.setLevel(CONSOLE_LOGGER_LEVEL)
|
||||
logger.addHandler(steam_handler)
|
||||
return logger
|
||||
|
@ -1,21 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
import config
|
||||
|
||||
|
||||
class RedfishException(Exception):
|
||||
"""Base class for redfish exceptions"""
|
||||
def __init__(self, message=None, **kwargs):
|
||||
def __init__(self, message, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
self.message = message
|
||||
self.advices = None
|
||||
config.logger.error(message)
|
||||
|
||||
|
||||
class ConnectionFailureException(RedfishException):
|
||||
def __init__(self, message, **kwargs):
|
||||
super(ConnectionFailureException, self).__init__(message, **kwargs)
|
||||
self.advices = '1- Check if the url is the correct one\n' + \
|
||||
'2- Check if your device is answering on the network\n'
|
||||
|
||||
|
||||
class InvalidRedfishContentException(RedfishException):
|
||||
def __init__(self, message, **kwargs):
|
||||
super(InvalidRedfishContentException, self).__init__(message, **kwargs)
|
||||
self.advices = \
|
||||
'1- Check if the url is the correct one\n' + \
|
||||
' Most of the time you are not pointing to the rest API\n'
|
||||
|
||||
|
||||
class NonTrustedCertificatException(RedfishException):
|
||||
def __init__(self, message, **kwargs):
|
||||
super(NonTrustedCertificatException, self).__init__(message, **kwargs)
|
||||
self.advices = \
|
||||
'1- Check if the url is the correct one\n' + \
|
||||
'2- Check if your device has a valid trusted certificat\n' + \
|
||||
' You can use openssl to validate it using the command :\n' + \
|
||||
' openssl s_client -showcerts -connect <server>:443\n'
|
||||
|
||||
|
||||
class AuthenticationFailureException(RedfishException):
|
||||
def __init__(self, message=None, **kwargs):
|
||||
super(AuthenticationFailureException, self).__init__(message=None, **kwargs)
|
||||
config.logger.error(message)
|
||||
# TODO
|
||||
# Give a bit more details about the failure (check login etc...)
|
||||
sys.exit(1)
|
||||
|
||||
def __init__(self, message, **kwargs):
|
||||
super(AuthenticationFailureException, self).__init__(message, **kwargs)
|
||||
self.message += str(kwargs['code'])
|
||||
self.queryAnswer = kwargs['queryAnswer']
|
||||
if kwargs['code'] == 400:
|
||||
self.message += ': ' + self.queryAnswer['Messages'][0]['MessageID']
|
||||
self.advices = '1- Check your credentials\n'
|
||||
self.message += '\n'
|
||||
|
||||
|
||||
class LogoutFailureException(RedfishException):
|
||||
pass
|
||||
|
@ -117,7 +117,7 @@ Clients should always be prepared for:
|
||||
|
||||
# coding=utf-8
|
||||
|
||||
import sys
|
||||
|
||||
import json
|
||||
from urlparse import urlparse
|
||||
import requests
|
||||
@ -126,21 +126,7 @@ import types
|
||||
import mapping
|
||||
import exception
|
||||
|
||||
# Global variable definition
|
||||
redfish_logfile = "/var/log/python-redfish/python-redfish.log"
|
||||
|
||||
# ===============================================================================
|
||||
# TODO : create method to set logging level and TORTILLADEBUG.
|
||||
# ===============================================================================
|
||||
|
||||
|
||||
def set_log_file(logfile):
|
||||
global redfish_logfile
|
||||
redfish_logfile = logfile
|
||||
return True
|
||||
|
||||
|
||||
""" Function to wrap RedfishConnection """
|
||||
"""Function to wrap RedfishConnection"""
|
||||
|
||||
|
||||
def connect(
|
||||
@ -150,9 +136,8 @@ def connect(
|
||||
simulator=False,
|
||||
enforceSSL=True,
|
||||
verify_cert=True
|
||||
):
|
||||
global redfish_logfile
|
||||
config.initialize_logger(redfish_logfile)
|
||||
):
|
||||
|
||||
return RedfishConnection(
|
||||
url,
|
||||
user,
|
||||
@ -173,9 +158,16 @@ class RedfishConnection(object):
|
||||
simulator=False,
|
||||
enforceSSL=True,
|
||||
verify_cert=True
|
||||
):
|
||||
):
|
||||
"""Initialize a connection to a Redfish service."""
|
||||
super(RedfishConnection, self).__init__()
|
||||
# Specify a name for the logger as recommended by the logging
|
||||
# documentation. However for strange reason requests logs are not
|
||||
# anymore capture in the log file.
|
||||
# TODO : Check strange behavior about requests logs.
|
||||
config.logger = config.initialize_logger(config.REDFISH_LOGFILE,
|
||||
config.CONSOLE_LOGGER_LEVEL,
|
||||
config.FILE_LOGGER_LEVEL,
|
||||
__name__)
|
||||
|
||||
config.logger.info("Initialize python-redfish")
|
||||
|
||||
@ -217,9 +209,10 @@ class RedfishConnection(object):
|
||||
|
||||
config.logger.info("API Version : %s", self.get_api_version())
|
||||
mapping.redfish_version = self.get_api_version()
|
||||
mapping.redfish_root_name = self.Root.get_name()
|
||||
|
||||
# Instanciate a global mapping object to handle Redfish version variation
|
||||
mapping.redfish_mapper = mapping.RedfishVersionMapping(self.get_api_version())
|
||||
# Instantiate a global mapping object to handle 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
|
||||
if self.__simulator is False:
|
||||
@ -233,7 +226,7 @@ class RedfishConnection(object):
|
||||
|
||||
|
||||
|
||||
# Struture change with mockup 1.0.0, there is no links
|
||||
# Structure change with mockup 1.0.0, there is no links
|
||||
# section anymore.
|
||||
# ===================================================================
|
||||
# TODO : Add a switch to allow the both structure
|
||||
@ -271,7 +264,7 @@ class RedfishConnection(object):
|
||||
#
|
||||
# print self.systemCollection.Name
|
||||
#
|
||||
# ========================================================================
|
||||
# ========================================================================
|
||||
def get_api_version(self):
|
||||
"""Return api version.
|
||||
|
||||
@ -286,14 +279,15 @@ class RedfishConnection(object):
|
||||
url = self.Root.get_link_url(
|
||||
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
|
||||
if float(mapping.redfish_version) >= 1.00:
|
||||
url += '/Sessions'
|
||||
|
||||
# Craft request body and header
|
||||
requestBody = {"UserName": self.connection_parameters.user_name , "Password": self.connection_parameters.password}
|
||||
config.logger.debug(requestBody)
|
||||
header = {'Content-type': 'application/json'}
|
||||
# =======================================================================
|
||||
# Tortilla seems not able to provide the header of a post request answer.
|
||||
@ -308,13 +302,16 @@ class RedfishConnection(object):
|
||||
headers=header,
|
||||
verify=self.connection_parameters.verify_cert
|
||||
)
|
||||
|
||||
|
||||
# =======================================================================
|
||||
# TODO : Manage exception with a class.
|
||||
# =======================================================================
|
||||
if auth.status_code != 201:
|
||||
raise exception.AuthenticationFailureException("Login request return an invalid status code")
|
||||
#sysraise "Error getting token", auth.status_code
|
||||
try:
|
||||
answer=auth.json()
|
||||
except ValueError as e:
|
||||
answer = ""
|
||||
raise exception.AuthenticationFailureException("Login request return an invalid status code ", code=auth.status_code, queryAnswer=answer)
|
||||
|
||||
self.connection_parameters.auth_token = auth.headers.get("x-auth-token")
|
||||
self.connection_parameters.user_uri = auth.headers.get("location")
|
||||
|
@ -2,30 +2,51 @@
|
||||
|
||||
redfish_mapper = None
|
||||
redfish_version = None
|
||||
redfish_root_name = None
|
||||
|
||||
class RedfishVersionMapping(object):
|
||||
"""Implements basic url path mapping beetween Redfish versions."""
|
||||
'''Implements basic url path mapping beetween Redfish versions.'''
|
||||
|
||||
def __init__(self, version):
|
||||
def __init__(self, version, rootname):
|
||||
self.__version = version
|
||||
self.__rootname = rootname
|
||||
|
||||
def map_sessionservice(self):
|
||||
if self.__version == "0.95":
|
||||
return "Sessions"
|
||||
return("SessionService")
|
||||
|
||||
if self.__version == '0.95':
|
||||
return 'Sessions'
|
||||
return 'SessionService'
|
||||
|
||||
def map_links(self):
|
||||
if self.__version == "0.95":
|
||||
return "links"
|
||||
return("Links")
|
||||
def map_links(self, data_dict=None):
|
||||
if data_dict == None:
|
||||
if self.__version == '0.95':
|
||||
return 'links'
|
||||
else:
|
||||
# Checking if we have Links or links.
|
||||
# This is to deal with proliant firmware 2.40 bug that reports
|
||||
# incorrectly links instead of Links (Redfish standard)
|
||||
try:
|
||||
data_dict.links
|
||||
return 'links'
|
||||
except AttributeError:
|
||||
pass
|
||||
return 'Links'
|
||||
|
||||
def map_links_ref(self):
|
||||
if self.__version == "0.95":
|
||||
return "href"
|
||||
return("@odata.id")
|
||||
def map_links_ref(self, data_dict=None):
|
||||
if data_dict == None:
|
||||
if self.__version == '0.95':
|
||||
return 'href'
|
||||
else:
|
||||
# Checking if we have @odata.id or href.
|
||||
# This is to deal with proliant firmware 2.40 bug that reports
|
||||
# incorrectly href instead of @odata.id (Redfish standard)
|
||||
try:
|
||||
data_dict.href
|
||||
return 'href'
|
||||
except AttributeError:
|
||||
pass
|
||||
return '@odata.id'
|
||||
|
||||
def map_members(self):
|
||||
if self.__version == "0.95":
|
||||
return "Member"
|
||||
return("Members")
|
||||
if self.__version == '0.95':
|
||||
return 'Member'
|
||||
return 'Members'
|
396
redfish/types.py
396
redfish/types.py
@ -1,20 +1,22 @@
|
||||
# coding=utf-8
|
||||
|
||||
import pprint
|
||||
import re
|
||||
from urlparse import urljoin
|
||||
import requests
|
||||
import simplejson
|
||||
import tortilla
|
||||
import config
|
||||
import mapping
|
||||
import re
|
||||
import exception
|
||||
|
||||
# Global variable
|
||||
|
||||
|
||||
class Base(object):
|
||||
"""Abstract class to manage types (Chassis, Servers etc...)."""
|
||||
'''Abstract class to manage types (Chassis, Servers etc...).'''
|
||||
def __init__(self, url, connection_parameters):
|
||||
"""Class constructor"""
|
||||
'''Class constructor'''
|
||||
global TORTILLADEBUG
|
||||
self.connection_parameters = connection_parameters # Uggly hack to check
|
||||
self.url = url
|
||||
@ -28,22 +30,37 @@ class Base(object):
|
||||
headers={'x-auth-token': connection_parameters.auth_token}
|
||||
)
|
||||
except requests.ConnectionError as e:
|
||||
print e
|
||||
# Log and transmit the exception.
|
||||
config.logger.error("Connection error : %s", e)
|
||||
raise e
|
||||
print self.data
|
||||
config.logger.info('Raise a RedfishException to upper level')
|
||||
msg = 'Connection error : {}\n'.format(e.message)
|
||||
raise exception.ConnectionFailureException(msg)
|
||||
except simplejson.scanner.JSONDecodeError as e:
|
||||
# Log and transmit the exception.
|
||||
config.logger.info('Raise a RedfishException to upper level')
|
||||
msg = \
|
||||
'Ivalid content : Content does not appear to be a valid ' + \
|
||||
'Redfish json\n'
|
||||
raise exception.InvalidRedfishContentException(msg)
|
||||
except TypeError as e:
|
||||
# This happen connecting to a manager using non trusted
|
||||
# SSL certificats.
|
||||
# The exception is not what could be expected in such case but this
|
||||
# is the one provided by Tortilla.
|
||||
config.logger.info('Raise a RedfishException to upper level')
|
||||
msg = 'Connection error\n'
|
||||
raise exception.NonTrustedCertificatException(msg)
|
||||
config.logger.debug(self.data)
|
||||
|
||||
def get_link_url(self, link_type):
|
||||
"""Need to be explained.
|
||||
'''Need to be explained.
|
||||
|
||||
:param redfish_logfile: redfish log
|
||||
:type str
|
||||
:returns: True
|
||||
|
||||
"""
|
||||
'''
|
||||
self.links=[]
|
||||
|
||||
|
||||
# Manage standard < 1.0
|
||||
if float(mapping.redfish_version) < 1.00:
|
||||
links = getattr(self.data, mapping.redfish_mapper.map_links())
|
||||
@ -53,7 +70,7 @@ class Base(object):
|
||||
links = getattr(self.data, link_type)
|
||||
link = getattr(links, mapping.redfish_mapper.map_links_ref())
|
||||
return urljoin(self.url, link)
|
||||
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return self.__url
|
||||
@ -61,58 +78,70 @@ class Base(object):
|
||||
@url.setter
|
||||
def url(self, url):
|
||||
self.__url = url
|
||||
|
||||
|
||||
def get_parameter(self, parameter_name):
|
||||
"""Generic function to get any system parameter
|
||||
'''Generic function to get a specific parameter
|
||||
|
||||
:param parameter_name: name of the parameter
|
||||
:returns: string -- parameter value
|
||||
|
||||
"""
|
||||
|
||||
'''
|
||||
try:
|
||||
return self.data[parameter_name]
|
||||
except:
|
||||
return "Parameter does not exist"
|
||||
|
||||
return 'Parameter does not exist'
|
||||
|
||||
def get_parameters(self):
|
||||
"""Generic function to get all system parameters
|
||||
'''Generic function to get all parameters
|
||||
|
||||
:returns: string -- parameter value
|
||||
|
||||
"""
|
||||
|
||||
'''
|
||||
try:
|
||||
return self.data
|
||||
except:
|
||||
return -1
|
||||
|
||||
|
||||
def set_parameter(self, parameter_name, value):
|
||||
"""Generic function to set any system parameter
|
||||
'''Generic function to set a specific parameter
|
||||
|
||||
:param parameter_name: name of the parameter
|
||||
:param value: value to set
|
||||
:returns: string -- http response of PATCH request
|
||||
|
||||
"""
|
||||
|
||||
'''
|
||||
# Craft the request
|
||||
action = dict()
|
||||
action[parameter_name] = value
|
||||
print(action)
|
||||
config.logger.debug(action)
|
||||
|
||||
# Perform the POST action
|
||||
print self.api_url
|
||||
response = self.api_url.patch(verify=self.connection_parameters.verify_cert,
|
||||
headers={'x-auth-token': self.connection_parameters.auth_token},
|
||||
data=action
|
||||
)
|
||||
return response
|
||||
config.logger.debug(self.api_url)
|
||||
response = self.api_url.patch(
|
||||
verify=self.connection_parameters.verify_cert,
|
||||
headers={'x-auth-token': self.connection_parameters.auth_token},
|
||||
data=action)
|
||||
return response
|
||||
|
||||
def get_name(self):
|
||||
'''Get root name
|
||||
|
||||
:returns: string -- root name or "Not available"
|
||||
|
||||
'''
|
||||
try:
|
||||
return self.data.Name
|
||||
except AttributeError:
|
||||
return "Not available"
|
||||
|
||||
|
||||
class BaseCollection(Base):
|
||||
"""Abstract class to manage collection (Chassis, Servers etc...)."""
|
||||
'''Abstract class to manage collection (Chassis, Servers etc...).'''
|
||||
def __init__(self, url, connection_parameters):
|
||||
super(BaseCollection, self).__init__(url, connection_parameters)
|
||||
|
||||
self.links=[]
|
||||
|
||||
|
||||
|
||||
#linksmembers = self.data.Links.Members
|
||||
#linksmembers = self.data.links.Member
|
||||
@ -122,114 +151,189 @@ class BaseCollection(Base):
|
||||
else:
|
||||
linksmembers = getattr(self.data, mapping.redfish_mapper.map_members())
|
||||
for link in linksmembers:
|
||||
#self.links.append(getattr(link,"@odata.id"))
|
||||
#self.links.append(getattr(link,"href"))
|
||||
#self.links.append(getattr(link,'@odata.id'))
|
||||
#self.links.append(getattr(link,'href'))
|
||||
self.links.append(urljoin(self.url, getattr(link, mapping.redfish_mapper.map_links_ref())))
|
||||
|
||||
|
||||
print self.links
|
||||
config.logger.debug(self.links)
|
||||
|
||||
|
||||
class Root(Base):
|
||||
"""Class to manage redfish Root data."""
|
||||
'''Class to manage redfish Root data.'''
|
||||
def get_api_version(self):
|
||||
"""Return api version.
|
||||
'''Return api version.
|
||||
|
||||
:returns: string -- version
|
||||
:raises: AttributeError
|
||||
|
||||
"""
|
||||
'''
|
||||
try:
|
||||
version = self.data.RedfishVersion
|
||||
except AttributeError:
|
||||
version = self.data.ServiceVersion
|
||||
|
||||
|
||||
version = version.replace('.', '')
|
||||
version = version[0] + '.' + version[1:]
|
||||
return(version)
|
||||
|
||||
def get_api_UUID(self):
|
||||
"""Return UUID version.
|
||||
'''Return UUID version.
|
||||
|
||||
:returns: string -- UUID
|
||||
|
||||
"""
|
||||
'''
|
||||
return self.data.UUID
|
||||
|
||||
def get_api_link_to_server(self):
|
||||
"""Return api link to server.
|
||||
'''Return api link to server.
|
||||
|
||||
:returns: string -- path
|
||||
|
||||
"""
|
||||
return getattr(self.root.Links.Systems, "@odata.id")
|
||||
'''
|
||||
return getattr(self.root.Links.Systems, '@odata.id')
|
||||
|
||||
|
||||
class SessionService(Base):
|
||||
"""Class to manage redfish SessionService data."""
|
||||
'''Class to manage redfish SessionService data.'''
|
||||
pass
|
||||
|
||||
|
||||
class Managers(Base):
|
||||
"""Class to manage redfish Managers."""
|
||||
'''Class to manage redfish Managers.'''
|
||||
def __init__(self, url, connection_parameters):
|
||||
super(Managers, self).__init__(url, connection_parameters)
|
||||
try:
|
||||
|
||||
# self.ethernet_interfaces_collection = EthernetInterfacesCollection(
|
||||
# self.get_link_url("EthernetInterfaces"),
|
||||
# connection_parameters
|
||||
# )
|
||||
|
||||
# Works on proliant, need to treat 095 vs 0.96 differences
|
||||
# New proliant firmware now respects Redfish v1.00, so seems to correct below statement
|
||||
# TODO : better handle exception and if possible support old firmware ?
|
||||
self.ethernet_interfaces_collection = EthernetInterfacesCollection(
|
||||
self.get_link_url("EthernetNICs"),
|
||||
self.get_link_url('EthernetInterfaces'),
|
||||
connection_parameters
|
||||
)
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_firmware_version(self):
|
||||
"""Get bios version of the system.
|
||||
|
||||
:returns: string -- bios version
|
||||
# Works on proliant, need to treat 095 vs 0.96 differences
|
||||
#self.ethernet_interfaces_collection = EthernetInterfacesCollection(
|
||||
# self.get_link_url('EthernetNICs'),
|
||||
# connection_parameters
|
||||
# )
|
||||
except exception.InvalidRedfishContentException:
|
||||
# This is to avoid invalid content from the mockup
|
||||
self.ethernet_interfaces_collection = None
|
||||
|
||||
"""
|
||||
except AttributeError:
|
||||
# This means we don't have EthernetInterfaces
|
||||
self.ethernet_interfaces_collection = None
|
||||
|
||||
|
||||
def get_firmware_version(self):
|
||||
'''Get firmware version of the manager
|
||||
|
||||
:returns: string -- bios version or "Not available"
|
||||
|
||||
'''
|
||||
try:
|
||||
# Returned by proliant
|
||||
return self.data.FirmwareVersion
|
||||
except:
|
||||
# Returned by mockup.
|
||||
# Hopefully this kind of discrepencies will be fixed with Redfish 1.0 (August)
|
||||
return self.data.FirmwareVersion
|
||||
except AttributeError:
|
||||
# We are here because the attribute could be not defined.
|
||||
# This is the case with the mockup for manager 2 and 3
|
||||
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):
|
||||
'''Get managed chassis ids by the manager
|
||||
|
||||
:returns: list -- chassis ids or "Not available"
|
||||
|
||||
'''
|
||||
chassis_list = []
|
||||
links = getattr(self.data, mapping.redfish_mapper.map_links(self.data))
|
||||
|
||||
try:
|
||||
for chassis in links.ManagerForChassis:
|
||||
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_managed_systems(self):
|
||||
'''Get managed systems ids by the manager
|
||||
|
||||
:returns: list -- chassis ids or "Not available"
|
||||
|
||||
'''
|
||||
systems_list = []
|
||||
links = getattr(self.data, mapping.redfish_mapper.map_links(self.data))
|
||||
|
||||
try:
|
||||
for systems in links.ManagerForServers:
|
||||
result = re.search(r'Systems/(\w+)', systems[mapping.redfish_mapper.map_links_ref(systems)])
|
||||
systems_list.append(result.group(1))
|
||||
return systems_list
|
||||
except AttributeError:
|
||||
return "Not available"
|
||||
|
||||
class ManagersCollection(BaseCollection):
|
||||
"""Class to manage redfish ManagersCollection data."""
|
||||
'''Class to manage redfish ManagersCollection data.'''
|
||||
def __init__(self, url, connection_parameters):
|
||||
"""Class constructor"""
|
||||
'''Class constructor'''
|
||||
super(ManagersCollection, self).__init__(url, connection_parameters)
|
||||
self.managers_list = []
|
||||
self.managers_dict = {}
|
||||
for link in self.links:
|
||||
self.managers_list.append(Managers(link, connection_parameters))
|
||||
index = re.search(r'Managers/(\w+)', link)
|
||||
self.managers_dict[index.group(1)] = Managers(link, connection_parameters)
|
||||
|
||||
|
||||
class Systems(Base):
|
||||
"""Class to manage redfish Systems data."""
|
||||
'''Class to manage redfish Systems data.'''
|
||||
# TODO : Need to discuss with Bruno the required method.
|
||||
# Also to check with the ironic driver requirement.
|
||||
def __init__(self, url, connection_parameters):
|
||||
"""Class constructor"""
|
||||
'''Class constructor'''
|
||||
super(Systems, self).__init__(url, connection_parameters)
|
||||
try:
|
||||
self.bios = Bios(url + "Bios/Settings", connection_parameters)
|
||||
self.bios = Bios(url + 'Bios/Settings', connection_parameters)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def reset_system(self):
|
||||
"""Force reset of the system.
|
||||
'''Force reset of the system.
|
||||
|
||||
:returns: string -- http response of POST request
|
||||
|
||||
"""
|
||||
|
||||
'''
|
||||
# Craft the request
|
||||
action = dict()
|
||||
action['Action'] = 'Reset'
|
||||
@ -242,14 +346,14 @@ class Systems(Base):
|
||||
data=action
|
||||
)
|
||||
#TODO : treat response.
|
||||
return response
|
||||
|
||||
return response
|
||||
|
||||
def get_bios_version(self):
|
||||
"""Get bios version of the system.
|
||||
'''Get bios version of the system.
|
||||
|
||||
:returns: string -- bios version
|
||||
|
||||
"""
|
||||
|
||||
'''
|
||||
try:
|
||||
# Returned by proliant
|
||||
return self.data.Bios.Current.VersionString
|
||||
@ -259,37 +363,37 @@ class Systems(Base):
|
||||
return self.data.BiosVersion
|
||||
|
||||
def get_serial_number(self):
|
||||
"""Get serial number of the system.
|
||||
'''Get serial number of the system.
|
||||
|
||||
:returns: string -- serial number
|
||||
|
||||
"""
|
||||
|
||||
'''
|
||||
try:
|
||||
# Returned by proliant
|
||||
return self.data.SerialNumber
|
||||
except:
|
||||
# Returned by mockup.
|
||||
# Hopefully this kind of discrepencies will be fixed with Redfish 1.0 (August)
|
||||
return ""
|
||||
|
||||
return ''
|
||||
|
||||
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
|
||||
|
||||
"""
|
||||
|
||||
'''
|
||||
try:
|
||||
return self.data.Power
|
||||
except:
|
||||
return ""
|
||||
return ''
|
||||
|
||||
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
|
||||
|
||||
:param value: json structure with value to update
|
||||
:returns: string -- http response of PATCH request
|
||||
|
||||
"""
|
||||
|
||||
'''
|
||||
# perform the POST action
|
||||
#print self.api_url.url()
|
||||
response = requests.patch(self.api_url.url(),
|
||||
@ -297,9 +401,9 @@ class Systems(Base):
|
||||
headers={'x-auth-token': self.connection_parameters.auth_token, 'Content-type': 'application/json'},
|
||||
data=value)
|
||||
return response.reason
|
||||
|
||||
|
||||
def set_boot_source_override(self, target, enabled):
|
||||
"""Shotcut function to set boot source
|
||||
'''Shotcut function to set boot source
|
||||
|
||||
:param target: new boot source. Supported values:
|
||||
"None",
|
||||
@ -318,43 +422,107 @@ class Systems(Base):
|
||||
"Once",
|
||||
"Continuous"
|
||||
:returns: string -- http response of PATCH request
|
||||
"""
|
||||
'''
|
||||
return self.set_parameter_json('{"Boot": {"BootSourceOverrideTarget": "'+target+'"},{"BootSourceOverrideEnabled" : "'+enabled+'"}}')
|
||||
|
||||
|
||||
class SystemsCollection(BaseCollection):
|
||||
"""Class to manage redfish ManagersCollection data."""
|
||||
'''Class to manage redfish SystemsCollection data.'''
|
||||
def __init__(self, url, connection_parameters):
|
||||
super(SystemsCollection, self).__init__(url, connection_parameters)
|
||||
|
||||
|
||||
self.systems_list = []
|
||||
|
||||
|
||||
for link in self.links:
|
||||
self.systems_list.append(Systems(link, connection_parameters))
|
||||
|
||||
|
||||
class Bios(Base):
|
||||
"""Class to manage redfish Bios data."""
|
||||
'''Class to manage redfish Bios data.'''
|
||||
def __init__(self, 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 to manage redfish Boot data."""
|
||||
'''Class to manage redfish Boot data.'''
|
||||
def __init__(self, url, connection_parameters):
|
||||
super(Boot, self).__init__(url, connection_parameters)
|
||||
|
||||
|
||||
|
||||
class EthernetInterfacesCollection(BaseCollection):
|
||||
"""Class to manage redfish EthernetInterfacesColkection data."""
|
||||
'''Class to manage redfish EthernetInterfacesColkection data.'''
|
||||
def __init__(self, url, connection_parameters):
|
||||
super(EthernetInterfacesCollection, self).__init__(url, connection_parameters)
|
||||
|
||||
self.ethernet_interfaces_list = []
|
||||
|
||||
# Url returned by the mock up is wrong /redfish/v1/Managers/EthernetInterfaces/1 returns a 404.
|
||||
# The correct one should be /redfish/v1/Managers/1/EthernetInterfaces/1
|
||||
|
||||
self.ethernet_interfaces_dict = {}
|
||||
|
||||
# Url returned by the mock up is wrong /redfish/v1/Managers/EthernetInterfaces/1 returns a 404. --> this is not true anymore (2016/01/03)
|
||||
# The correct one should be /redfish/v1/Managers/1/EthernetInterfaces/1 --> correct by mockup return invalid content (not json)
|
||||
# Check more than 1 hour for this bug.... grrr....
|
||||
for link in self.links:
|
||||
self.ethernet_interfaces_list.append(EthernetInterfaces(link, connection_parameters))
|
||||
index = re.search(r'EthernetInterfaces/(\w+)', link)
|
||||
self.ethernet_interfaces_dict[index.group(1)] = EthernetInterfaces(link, connection_parameters)
|
||||
|
||||
|
||||
class EthernetInterfaces(Base):
|
||||
"""Class to manage redfish EthernetInterfaces data."""
|
||||
pass
|
||||
'''Class to manage redfish EthernetInterfaces.'''
|
||||
def get_mac(self):
|
||||
'''Get EthernetInterface MacAddress
|
||||
|
||||
:returns: string -- interface macaddress or "Not available"
|
||||
|
||||
'''
|
||||
try:
|
||||
return self.data.MacAddress
|
||||
except AttributeError:
|
||||
return "Not available"
|
||||
|
||||
def get_fqdn(self):
|
||||
'''Get EthernetInterface fqdn
|
||||
|
||||
:returns: string -- interface fqdn or "Not available"
|
||||
|
||||
'''
|
||||
try:
|
||||
return self.data.FQDN
|
||||
except AttributeError:
|
||||
return "Not available"
|
||||
|
||||
|
||||
def get_ipv4(self):
|
||||
'''Get EthernetInterface ipv4 address
|
||||
|
||||
:returns: list -- interface ip addresses or "Not available"
|
||||
|
||||
'''
|
||||
|
||||
ipaddresses = []
|
||||
|
||||
try:
|
||||
for ip_settings in self.data.IPv4Addresses:
|
||||
address = ip_settings['Address']
|
||||
ipaddresses.append(address)
|
||||
|
||||
return ipaddresses
|
||||
except AttributeError:
|
||||
return "Not available"
|
||||
|
||||
def get_ipv6(self):
|
||||
'''Get EthernetInterface ipv6 address
|
||||
|
||||
:returns: list -- interface ip addresses or "Not available"
|
||||
|
||||
'''
|
||||
|
||||
ipaddresses = []
|
||||
|
||||
try:
|
||||
for ip_settings in self.data.IPv6Addresses:
|
||||
address = ip_settings['Address']
|
||||
ipaddresses.append(address)
|
||||
|
||||
return ipaddresses
|
||||
except AttributeError:
|
||||
return "Not available"
|
||||
|
||||
|
@ -6,3 +6,4 @@ pbr>=0.6,!=0.7,<1.0
|
||||
#oslo.log>=1.0,<2.0
|
||||
Babel>=1.3
|
||||
tortilla>=0.4.1
|
||||
Jinja2>=2.7.3
|
||||
|
Loading…
Reference in New Issue
Block a user