Merge pull request #22 from uggla/types4systems

Major update.
This commit is contained in:
Bruno Cornec 2016-02-17 19:43:17 +01:00
commit 1cf02e1aa1
28 changed files with 481 additions and 473 deletions

View File

@ -1,16 +1,5 @@
If you would like to contribute to the development of OpenStack, If you would like to contribute to the development of this project.
you must follow the steps in this page:
http://docs.openstack.org/infra/manual/developers.html Submit your pull request and issues to https://github.com/bcornec/python-redfish.
Once those steps have been completed, changes to OpenStack You can also share and discuss on the mailing list as well.
should be submitted for review via the Gerrit tool, following
the workflow documented at:
http://docs.openstack.org/infra/manual/developers.html#development-workflow
Pull requests submitted through GitHub will be ignored.
Bugs should be filed on Launchpad, not GitHub:
https://bugs.launchpad.net/python-redfish

View File

@ -20,14 +20,17 @@ Project Structure
This project follows the same convention as OpenStack projects, eg. using pbr This project follows the same convention as OpenStack projects, eg. using pbr
for build and test automation:: for build and test automation::
doc/ # documentation doc/ # Documentation
doc/source # the doc source files live here doc/source # The doc source files live here
doc/build/html # output of building any docs will go here doc/build/html # Output of building any docs will go here
dmtf # Reference documents and mockup provided by the DMTF dmtf # Reference documents and mockup provided by the DMTF
examples/ # any sample code using this library, eg. for education examples/ # Any sample code using this library, eg. for education
# should be put here # should be put here
redfish/ # the redfish library pbconf # Project builder file to build rpm/deb packages for
redfish/tests/ # python unit test suite # distributions
redfish/ # The redfish library itself
redfish/tests/ # Python redfish unit test suite
redfish-client # Client tool to manage redfish devices
Requirements Requirements
------------ ------------
@ -41,11 +44,24 @@ are discouraged due to security.
Python requirements are listed in requirements.txt; additional requirements for Python requirements are listed in requirements.txt; additional requirements for
running the unit test suite are listed in test-requirements.txt. running the unit test suite are listed in test-requirements.txt.
Developer setup Get the sources
--------------- ---------------
To initialize a local development environment (eg, so you can run unit tests) The sources are available on github and can be retrieved using::
you should run the following commands
git clone https://github.com/uggla/python-redfish
As python redefish is currently in heavy development we recommend to checkout the devel branch using::
cd python-redfish
git checkout devel
Installation
------------
Please refer to the following link.
http://pythonhosted.org/python-redfish/installation.html
Contacts Contacts
-------- --------
@ -55,9 +71,4 @@ Distribution list : python-redfish@mondorescue.org
Further References Further References
------------------ ------------------
The data model documentation can be found here: Please look at `dmtf/README.rst <further_ref.html>`_ file.
http://www.redfishspecification.org/redfish-data-model-and-schema/
The overall protocol documentation can be found here:
http://www.redfishspecification.org/

View File

@ -2,11 +2,25 @@ DMTF Redfish specification
-------------------------- --------------------------
This directory contains the current references from the DMTF on the Redfish This directory contains the current references from the DMTF on the Redfish
specification (1.0.0 at the time of the writing) specification (1.0.1 at the time of the writing)
The overall protocol documentation can be found online at:
http://www.dmtf.org/standards/redfish
The specification can be found locally in DSP0266_1.0.1.pdf or online at:
http://www.dmtf.org/sites/default/files/standards/documents/DSP0266_1.0.1.pdf
The data model documentation can be found locally in DSP8010_1.0.0.zip or online at:
http://redfish.dmtf.org/schemas/
In order to ease test, the DMTF has published a mockup environment to simulate In order to ease test, the DMTF has published a mockup environment to simulate
a Redfish based system so it is possible to write programs without real Redfish a Redfish based system so it is possible to write programs without real Redfish
compliant hardware platform. compliant hardware platform.
Note: Mockup release is still 0.99.0a and so not aligned with specification realease
number.
Docker container Docker container
---------------- ----------------

View File

@ -48,16 +48,16 @@ master_doc = 'index'
# General information about the project. # General information about the project.
project = u'python-redfish' project = u'python-redfish'
copyright = u'2016, Bruno Cornec, Vincent Misson, René Ribaud' copyright = u'2015-2016, Bruno Cornec, Vincent Misson, René Ribaud'
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.4' version = 'PBVER'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.4' release = 'PBVER'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -0,0 +1,8 @@
===============
Developer setup
===============
#. Follow `get the sources <http://pythonhosted.org/python-redfish/readme.html#get-the-sources>`_ section to retrieve the sources.
#. Follow `using pip and virtualenv <http://pythonhosted.org/python-redfish/installation.html#using-pip-and-virtualenv>`_ section to create your environment.
You can start hacking the code now.

View File

@ -0,0 +1,3 @@
:orphan:
.. include:: ../../dmtf/README.rst

12
doc/source/help.rst Normal file
View File

@ -0,0 +1,12 @@
=============
Help required
=============
We need help on the following topic:
- debian/ubuntu dependencies packaging.
- python3 testing.
- installation on distributions which are not Fedora or Mageia.
- documentation.
Any contribution will be welcomed.

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

View File

@ -14,8 +14,10 @@ Contents:
readme readme
installation installation
usage usage
contributing develsetup
classesdoc classesdoc
contributing
help
Indices and tables Indices and tables
================== ==================

View File

@ -2,11 +2,226 @@
Installation Installation
============ ============
At the command line:: Using pip
---------
Use::
$ pip install python-redfish sudo pip install python-redfish
Or, if you have virtualenvwrapper installed:: Pip will install :
1. The library and all dependencies into your site-packages directory
2. Redfish client master conf file into /etc/redfish_client.conf
3. Data file (templates) into /usr/share/redfish-client/templates
Point 2 and 3 above need root access to your system. If you don't have root
access on your system, please follow `Using pip and virtualenv`_ section.
Using pip and virtualenv
------------------------
1. Install virtualenv and virtualenvwrapper:
Fedora 22::
dnf install python-virtualenv python-virtualenvwrapper
Ubuntu 15.04::
apt-get install python-virtualenv virtualenvwrapper
2. Source virtualenvwrapper.sh::
. /usr/bin/virtualenvwrapper.sh
or::
. /usr/share/virtualenvwrapper/virtualenvwrapper.sh
3. Create a redfish virtual environement::
mkvirtualenv redfish
4. Install using pip::
pip install python-virtualenv
All files are installed under your virtualenv.
Using the sources
-----------------
#. Follow `get the sources <http://pythonhosted.org/python-redfish/readme.html#get-the-sources>`_ section to retrieve the sources.
#. Install from the source using::
python setup.py install
Using rpm package
-----------------
There is currently no oficial packages for distributions.
However part of the sources there is a mechanism to buil rpm or deb packages for distributions.
The mechanism is based on `project builder <http://www.project-builder.org/>`_ tool.
#. Follow `get the sources <http://pythonhosted.org/python-redfish/readme.html#get-the-sources>`_ section to retrieve the sources.
#. Download project builder for your distribution from ftp://ftp.project-builder.org.
#. Clone the project to your own github account.
#. Create a .pbrc with the following content, replace "/wokspace/python/redfish" and "uggla" with your own directory and account::
[uggla@ugglalaptop ~]$ cat .pbrc
pbdefdir python-redfish = $ENV{'HOME'}/workspace
pbconfdir python-redfish = $ENV{'HOME'}/workspace/python-redfish/pbconf
pbconfurl python-redfish = git+ssh://git@github.com:uggla/python-redfish.git
pburl python-redfish = git+ssh://git@github.com:uggla/python-redfish.git
#. Build the project::
pb -p python-redfish sbx2pkg
or::
pb -p python-redfish sbx2pkg2ins
#. All packages (srpm/rpm) should be available into the build directory, then install the package using rpm::
rpm -Uvh python-redfish/build/RPMS/python-redfish-devel20160213182552.rpm
#. Follow `get the sources <http://pythonhosted.org/python-redfish/readme.html#get-the-sources>`_ section to retrieve the sources.
Using deb package
-----------------
This installation in not yet possible due to missing deb package dependencies. We are working on it.
In the meantime we recommend to use `Using pip`_ or `Using pip and virtualenv`_.
=====================================
Host configuration file configuration
=====================================
#. Verify redfish-client is working correclty::
redfish-client.py -h
#. Create a default entry to use the mockup::
redfish-client.py config add default default http://localhost:8000/redfish/v1
#. Verify the entry is correctly registered::
redfish-client.py config showall
===================
Mockup installation
===================
#. Follow `get the sources <http://pythonhosted.org/python-redfish/readme.html#get-the-sources>`_ section to retrieve the sources.
#. Install docker using your distribution packages or the docker `procedure <https://docs.docker.com/engine/installation/>`_ (docker provide more recent packages for ubuntu)::
dnf install docker
systemctl enable docker.service
systemctl start docker.service
systemctl status docker.service
#. Jump into the dmtf directory.
#. Run ./buildImage.sh and ./run-redfish-simulator.sh
#. Check that a container is running and listening on port 8000::
(pypi)[uggla@ugglalaptop dmtf]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9943ff1d4d93 redfish-simulator:latest "/bin/sh -c /tmp/redf" 3 weeks ago Up 2 days 0.0.0.0:8000->80/tcp redfish-simulator
#. Try to connect using a navigator to http://localhost:8000 the following screen should apear.
.. image:: images/simulator.jpg
Note : in the above screenshot, firefox JSON-handle extension is used. If you want the same presentation install the extension and refresh the page.
==========================
Testing against the mockup
==========================
#. Follow `Host configuration file configuration`_ and `Mockup installation`_ section.
#. Run the following command::
redfish-client.py manager getinfo
The result should be like this::
(pypi)[uggla@ugglalaptop dmtf]$ redfish-client.py manager getinfo
Gathering data from manager, please wait...
Redfish API version : 1.00
Root Service
Managers information :
======================
Manager id 1:
UUID : 00000000-0000-0000-0000-000000000000
Type : BMC
Firmware version : 1.00
State : Enabled
Ethernet Interface :
This manager has no ethernet interface
Managed Chassis :
1
Managed System :
1
----------------------------
Manager id 2:
UUID : 00000000-0000-0000-0000-000000000000
Type : EnclosureManager
Firmware version : Not available
State : Enabled
Ethernet Interface :
This manager has no ethernet interface
Managed Chassis :
Enc1
Managed System :
2
----------------------------
Manager id 3:
UUID : 00000000-0000-0000-0000-000000000000
Type : EnclosureManager
Firmware version : Not available
State : Enabled
Ethernet Interface :
This manager has no ethernet interface
Managed Chassis :
Enc1
Managed System :
2
----------------------------
============================
Building local documentation
============================
Building the html documentation locally
#. Follow `get the sources <http://pythonhosted.org/python-redfish/readme.html#get-the-sources>`_ section to retrieve the sources.
#. Jump in the doc directory::
cd doc
#. Build the html documentation::
make html
If you want to build the documentation in pdf.
#. Get texlive full distribution, ex on Fedora::
dnf install texlive-scheme-full
#. Build the documentation::
make latexpdf
$ mkvirtualenv python-redfish
$ pip install python-redfish

View File

@ -2,6 +2,25 @@
Usage Usage
======== ========
To use python-redfish in a project:: Example using the mockup
------------------------
example/simple-simulator.py provide a simple library usage to interact with the
redfish mockup.
Example using a proliant
------------------------
example/simple-proliant.py provide a simple library usage to interact with a HP
proliant BL460C G9 server. However this example should work on any server supplier following redfish
standard.
redfish-client usage
--------------------
The client usage can be display using::
redfish-client.py -h
This is also available at http://pythonhosted.org/python-redfish/redfish-client.html .
import redfish

View File

@ -1,5 +1,5 @@
{ {
"Nodes": { "Managers": {
"default": { "default": {
"url": "", "url": "",
"login": "", "login": "",

View File

@ -43,48 +43,48 @@ except redfish.exception.RedfishException as e:
print ("Redfish API version : %s \n" % remote_mgmt.get_api_version()) print ("Redfish API version : %s \n" % remote_mgmt.get_api_version())
# Uncomment following line to reset the blade !!! # Uncomment following line to reset the blade !!!
# remote_mgmt.Systems.systems_list[0].reset_system() # remote_mgmt.Systems.systems_dict["1"].reset_system()
# TODO : create an attribute to link the managed system directly # TODO : create an attribute to link the managed system directly
# and avoid systems_list[0] # and avoid systems_dict["1"]
# --> will be something like : # --> will be something like :
# remote_mgmt.Systems.systems_list[0] = remote_mgmt.Systems.managed_system # remote_mgmt.Systems.systems_dict["1"] = remote_mgmt.Systems.managed_system
print("Bios version : {}\n".format(remote_mgmt.Systems.systems_list[0].get_bios_version())) print("Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_bios_version()))
print("Serial Number : {}\n".format(remote_mgmt.Systems.systems_list[0].get_serial_number())) print("Serial Number : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_serial_number()))
print("Power State : {}\n".format(remote_mgmt.Systems.systems_list[0].get_power())) print("Power State : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_power()))
print("Parameter 'SystemType' : {}\n".format(remote_mgmt.Systems.systems_list[0].get_parameter("SystemType"))) print("Parameter 'SystemType' : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_parameter("SystemType")))
print("Get bios parameters : {}\n".format(remote_mgmt.Systems.systems_list[0].bios.get_parameters())) print("Get bios parameters : {}\n".format(remote_mgmt.Systems.systems_dict["1"].bios.get_parameters()))
print("Get boot parameters : {}\n".format(remote_mgmt.Systems.systems_list[0].bios.boot.get_parameters())) print("Get boot parameters : {}\n".format(remote_mgmt.Systems.systems_dict["1"].bios.boot.get_parameters()))
#print("Get bios parameter 'AdminPhone' : {}\n".format(remote_mgmt.Systems.systems_list[0].bios.get_parameter("AdminPhone"))) #print("Get bios parameter 'AdminPhone' : {}\n".format(remote_mgmt.Systems.systems_dict["1"].bios.get_parameter("AdminPhone")))
#print("Set bios parameter 'AdminPhone' to '' : {}\n".format(remote_mgmt.Systems.systems_list[0].bios.set_parameter("AdminPhone",""))) #print("Set bios parameter 'AdminPhone' to '' : {}\n".format(remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("AdminPhone","")))
#Boot server with script #Boot server with script
#remote_mgmt.Systems.systems_list[0].bios.set_parameter("Dhcpv4","Enabled") #remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("Dhcpv4","Enabled")
remote_mgmt.Systems.systems_list[0].bios.set_parameter("PreBootNetwork", "Auto") remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("PreBootNetwork", "Auto")
remote_mgmt.Systems.systems_list[0].bios.set_parameter("UefiShellStartup", "Enabled") remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("UefiShellStartup", "Enabled")
remote_mgmt.Systems.systems_list[0].bios.set_parameter("UefiShellStartupLocation", "NetworkLocation") remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("UefiShellStartupLocation", "NetworkLocation")
remote_mgmt.Systems.systems_list[0].bios.set_parameter("UefiShellStartupUrl", "http://10.3.222.88/deploy/startup.nsh") remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("UefiShellStartupUrl", "http://10.3.222.88/deploy/startup.nsh")
#remote_mgmt.Systems.systems_list[0].set_parameter_json('{"Boot": {"BootSourceOverrideTarget": "UefiShell"}}') #remote_mgmt.Systems.systems_dict["1"].set_parameter_json('{"Boot": {"BootSourceOverrideTarget": "UefiShell"}}')
# remote_mgmt.Systems.systems_list[0].set_parameter_json('{"Boot": {"BootSourceOverrideEnabled" : "Continuous"}}') # remote_mgmt.Systems.systems_dict["1"].set_parameter_json('{"Boot": {"BootSourceOverrideEnabled" : "Continuous"}}')
#remote_mgmt.Systems.systems_list[0].set_parameter_json('{"Boot": {"BootSourceOverrideEnabled" : "Once"}}') #remote_mgmt.Systems.systems_dict["1"].set_parameter_json('{"Boot": {"BootSourceOverrideEnabled" : "Once"}}')
mySystem = remote_mgmt.Systems.systems_list[0] mySystem = remote_mgmt.Systems.systems_dict["1"]
mySystem.set_boot_source_override("None","Disabled") mySystem.set_boot_source_override("None","Disabled")
#Uncomment the next line to reset the server #Uncomment the next line to reset the server
#mySystem.reset_system() #mySystem.reset_system()
print("Get manager firmware version : {}\n".format(remote_mgmt.Managers.managers_list[0].get_firmware_version())) print("Get manager firmware version : {}\n".format(remote_mgmt.Managers.managers_dict["1"].get_firmware_version()))
print("Get system Bios version : {}\n".format(remote_mgmt.Systems.systems_list[0].get_bios_version())) print("Get system Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_bios_version()))
#Reset of the system is required to apply the changes #Reset of the system is required to apply the changes
#remote_mgmt.Systems.systems_list[0].reset_system() #remote_mgmt.Systems.systems_dict["1"].reset_system()
remote_mgmt.logout() remote_mgmt.logout()

View File

@ -43,7 +43,7 @@ except redfish.exception.RedfishException as e:
print("Redfish API version : {} \n".format(remote_mgmt.get_api_version())) print("Redfish API version : {} \n".format(remote_mgmt.get_api_version()))
print("UUID : {} \n".format(remote_mgmt.Root.get_api_UUID())) print("UUID : {} \n".format(remote_mgmt.Root.get_api_UUID()))
print("System 1 :\n") print("System 1 :\n")
print("Bios version : {}\n".format(remote_mgmt.Systems.systems_list[0].get_bios_version())) print("Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_bios_version()))
print("System 2 :\n") print("System 2 :\n")
print("Bios version : {}\n".format(remote_mgmt.Systems.systems_list[1].get_parameter("SerialNumber"))) print("Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["2"].get_parameter("SerialNumber")))
#print remoteMgmt.get_api_link_to_server() #print remoteMgmt.get_api_link_to_server()

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python
#import logging
import sys
#from oslo_config import cfg
#from oslo_log import log as logging
import redfish
# Sets up basic logging for this module
#log_root = logging.getLogger('redfish')
#log_root.addHandler(logging.StreamHandler(sys.stdout))
#log_root.setLevel(logging.DEBUG)
#CONF = cfg.CONF
#logging.set_defaults(['redfish=DEBUG'])
#logging.register_options(CONF)
#logging.setup(CONF, "redfish")
# Connect to a redfish API endpoint
host = 'http://localhost'
user_name = ''
password = ''
# This returns a RedfishConnection object, which implements
# the low-level HTTP methods like GET, PUT, etc
connection = redfish.server.connect(host, user_name, password)
# From this connection, we can get the Root resource.
# Note that the root resource is somewhat special - you create it from
# the connection, but you create other resources from the root resource.
# (You don't strictly have to do this, but it's simpler.)
root = connection.get_root()
print("\n")
print("ROOT CONTROLLER")
print("===============")
print(root)
# The Root class has well-defined top-level resources, such as
# chassis, systems, managers, sessions, etc...
chassis = root.get_chassis()
print("\n")
print("CHASSIS DATA")
print("============")
print(chassis)
print("\n")
print("WALKING CHASSIS")
print("\n")
print("CHASSIS contains %d items" % len(chassis))
print("\n")
for item in chassis:
print("SYSTEM")
print("======")
print(item)
print("\n")

View File

@ -130,7 +130,7 @@ defpkgdir python-redfish = .
# List of files per pkg on which to apply filters # List of files per pkg on which to apply filters
# Files are mentioned relatively to pbroot/defpkgdir # Files are mentioned relatively to pbroot/defpkgdir
filteredfiles python-redfish = redfish-client/redfish-client.py filteredfiles python-redfish = redfish-client/redfish-client.py,doc/source/conf.py
#supfiles python-redfish = python-redfish.init #supfiles python-redfish = python-redfish.init
# For perl modules, names are different depending on distro # For perl modules, names are different depending on distro

View File

@ -0,0 +1,2 @@
[redfish-client]
templates_path = /usr/share/redfish-client/templates

View File

@ -37,10 +37,10 @@ import json
import pprint import pprint
import docopt import docopt
import logging import logging
import redfish import ConfigParser
import requests.packages.urllib3
import jinja2 import jinja2
import requests.packages.urllib3
import redfish
class ConfigFile(object): class ConfigFile(object):
'''redfisht-client configuration file management''' '''redfisht-client configuration file management'''
@ -253,7 +253,13 @@ if __name__ == '__main__':
sys.exit(1) sys.exit(1)
# Display manager information using jinja2 template # Display manager information using jinja2 template
try:
template = jinja2_env.get_template("manager_info.template") template = jinja2_env.get_template("manager_info.template")
except jinja2.exceptions.TemplateNotFound as e:
print('Template "{}" not found in {}.'.format(e.message, jinja2_env.loader.searchpath[0]))
logger.debug('Template "%s" not found in %s.' % (e.message, jinja2_env.loader.searchpath[0]))
sys.exit(1)
print template.render(r=remote_mgmt) print template.render(r=remote_mgmt)
@ -314,8 +320,9 @@ if __name__ == '__main__':
logger.info("Arguments parsed") logger.info("Arguments parsed")
logger.debug(arguments) logger.debug(arguments)
# Get $HOME environment. # Get $HOME and $VIRTUAL_ENV environment variables.
HOME = os.getenv('HOME') HOME = os.getenv('HOME')
VIRTUAL_ENV = os.getenv('VIRTUAL_ENV')
if not HOME: if not HOME:
print('$HOME environment variable not set, please check your system') print('$HOME environment variable not set, please check your system')
@ -323,14 +330,38 @@ if __name__ == '__main__':
sys.exit(1) sys.exit(1)
logger.debug("Home directory : %s" % HOME) logger.debug("Home directory : %s" % HOME)
if VIRTUAL_ENV:
logger.debug("Virtual env : %s" % VIRTUAL_ENV)
# Load master conf file
config = ConfigParser.ConfigParser(allow_no_value=True)
logger.debug("Read master configuration file")
master_conf_file_path = "/etc/redfish-client.conf"
if VIRTUAL_ENV:
logger.debug("Read master configuration file from virtual environment")
master_conf_file_path = VIRTUAL_ENV + master_conf_file_path
if not os.path.isfile(master_conf_file_path):
print('Master configuration file not found at {}.'.format(master_conf_file_path))
logger.error('Master configuration file not found at %s.' % master_conf_file_path)
sys.exit(1)
config.read(master_conf_file_path)
arguments['--conf_file'] = arguments['--conf_file'].replace('~', HOME) arguments['--conf_file'] = arguments['--conf_file'].replace('~', HOME)
conf_file = ConfigFile(arguments['--conf_file']) conf_file = ConfigFile(arguments['--conf_file'])
# Initialize Template system (jinja2) # Initialize Template system (jinja2)
# TODO : set the template file location into cmd line default to /usr/share/python-redfish/templates ? # TODO : set the template file location into cmd line default to /usr/share/python-redfish/templates ?
templates_path = config.get("redfish-client", "templates_path")
logger.debug("Initialize template system") logger.debug("Initialize template system")
jinja2_env = jinja2.Environment(loader=jinja2.FileSystemLoader("templates")) if VIRTUAL_ENV:
logger.debug("Read templates file from virtual environment")
templates_path = VIRTUAL_ENV + templates_path
jinja2_env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path))
# Check cmd line parameters
if arguments['config'] is True: if arguments['config'] is True:
logger.debug("Config commands") logger.debug("Config commands")
if arguments['show'] is True: if arguments['show'] is True:

View File

@ -1,32 +0,0 @@
#=======================================================================
# 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()

View File

@ -17,6 +17,7 @@ Ethernet Interface :
Ethernet Interface id {{ ethernetinterface_index }} : Ethernet Interface id {{ ethernetinterface_index }} :
{{ ei.get_name() }} {{ ei.get_name() }}
FQDN : {{ ei.get_fqdn() }} FQDN : {{ ei.get_fqdn() }}
Mac address : {{ ei.get_mac() }}
Address ipv4 : {{ ei.get_ipv4() | join(', ') }} Address ipv4 : {{ ei.get_ipv4() | join(', ') }}
Address ipv6 : {{ ei.get_ipv6() | join(', ') }} Address ipv6 : {{ ei.get_ipv6() | join(', ') }}
{%- endfor %} {%- endfor %}

View File

@ -12,11 +12,15 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
#import pbr.version import pbr.version
from redfish.main import * from redfish.main import *
#import redfish.types #import redfish.types
try:
#__version__ = pbr.version.VersionInfo( __version__ = pbr.version.VersionInfo('redfish').version_string()
# 'redfish').version_string() except Exception, e:
if "Versioning for this project requires either an sdist tarball" in e.message:
pass
else:
raise

View File

@ -15,8 +15,13 @@ class RedfishException(Exception):
class ConnectionFailureException(RedfishException): class ConnectionFailureException(RedfishException):
def __init__(self, message, **kwargs): def __init__(self, message, **kwargs):
super(ConnectionFailureException, self).__init__(message, **kwargs) super(ConnectionFailureException, self).__init__(message, **kwargs)
self.advices = '1- Check if the url is the correct one\n' + \ self.advices = \
'2- Check if your device is answering on the network\n' '1- Check if the url is the correct one\n' + \
'2- Check if your device is answering on the network\n' + \
'3- 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' + \
'4- Use option "--insecure" to connect without checking certificate\n'
class InvalidRedfishContentException(RedfishException): class InvalidRedfishContentException(RedfishException):

View File

@ -247,8 +247,6 @@ class RedfishConnection(object):
self.connection_parameters self.connection_parameters
) )
#for system in self.Systems.systems_list:
#config.logger.debug(system.data.links.ManagedBy)
# self.Chassis # self.Chassis
# self.EventService # self.EventService

View File

@ -1,49 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Provides functions for using the Redfish RESTful API.
"""
import collections
import json
import sys
from redfish import connection
class RedfishOperation(connection.RedfishConnection):
def reset_server(self):
(status, headers, system) = self.rest_get('/redfish/v1/Systems', None)
memberuri = system['links']['Member'][0]['href']
# verify expected type
# hint: don't limit to version 0 here as we will rev to 1.0 at some point hopefully with minimal changes
# assert(connection.get_type(system) == 'ComputerSystem.0' or connection.get_type(system) == 'ComputerSystem.1')
# verify it supports POST
# assert(connection.operation_allowed(headers, 'POST'))
action = dict()
action['Action'] = 'Reset'
action['ResetType'] = 'ForceRestart'
# perform the POST action
print('POST ' + json.dumps(action) + ' to ' + memberuri)
(status, headers, response) = self.rest_post(memberuri, None, action)
print('POST response = ' + str(status))
connection.print_extended_error(response)

View File

@ -1,197 +0,0 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Redfish Resource Types
"""
import base64
import gzip
import hashlib
import httplib
import json
import ssl
import StringIO
import sys
import urllib2
from urlparse import urlparse
#from oslo_log import log as logging
from redfish import exception
#LOG = logging.getLogger('redfish')
class Base(object):
def __init__(self, obj, connection=None):
self._conn = connection
"""handle to the redfish connection"""
self._attrs = []
"""list of discovered attributes"""
self._links = []
"""list of linked resources"""
# parse the individual resources, appending them to
# the list of object attributes
for k in obj.keys():
ref = k.lower()
if ref in ["links", "oem", "items"]:
continue
setattr(self, ref, obj[k])
self._attrs.append(ref)
# make sure the required attributes are present
if not getattr(self, 'name', False):
raise ObjectLoadException(
"Failed to load object. Reason: could not determine name.")
if not getattr(self, 'type', False):
raise ObjectLoadException(
"Failed to load object. Reason: could not determine type.")
if getattr(self, 'serviceversion', False):
self.type = self.type.replace('.' + self.serviceversion, '')
else:
# TODO: use a regex here to strip and store the version
# instead of assuming it is 7 chars long
self.type = self.type[:-7]
# Lastly, parse the 'links' resource.
# Note that this may have different nested structure, depending on
# what type of resource this is, or what vendor it is.
# subclasses may follow this by parsing other resources / collections
self._parse_links(obj)
def _parse_links(self, obj):
"""Map linked resources to getter functions
The root resource returns a dict of links to top-level resources
"""
def getter(connection, href):
def _get():
return connection.rest_get(href, {})
return _get
for k in obj['links']:
ref = "get_" + k.lower()
self._links.append(ref)
href = obj['links'][k]['href']
setattr(self, ref, getter(self._conn, href))
def __repr__(self):
"""Return this object's _attrs as a dict"""
res = {}
for a in self._attrs:
res[a] = getattr(self, a)
return res
def __str__(self):
"""Return the string representation of this object's _attrs"""
return json.dumps(self.__repr__())
class BaseCollection(Base):
"""Base class for collection types"""
def __init__(self, obj, connection=None):
super(BaseCollection, self).__init__(obj, connection=connection)
self._parse_items(obj)
self._attrs.append('items')
def _parse_links(self, obj):
"""links are special on a chassis; dont parse them"""
pass
def _parse_items(self, obj):
"""Map linked items to getter methods
The chassis resource returns a list of items and corresponding
link data in a separate entity.
"""
def getter(connection, href):
def _get():
return connection.rest_get(href, {})
return _get
self.items = []
self._item_getters = []
if 'links' in obj and 'Member' in obj['links']:
# NOTE: this assumes the lists are ordered the same
counter = 0
for item in obj['links']['Member']:
self.items.append(obj['Items'][counter])
self._item_getters.append(
getter(self._conn, item['href']))
counter+=1
elif 'Items' in obj:
# TODO: find an example of this format and make sure it works
for item in obj['Items']:
if 'links' in item and 'self' in item['links']:
href = item['links']['self']['href']
self.items.append(item)
# TODO: implement paging support
# if 'links' in obj and 'NextPage' in obj['links']:
# next_page = THIS_URI + '?page=' + str(obj['links']['NextPage']['page'])
# do something with next_page URI
def __iter__(self):
for getter in self._item_getters:
yield getter()
class Root(Base):
"""Root '/' resource class"""
def _parse_links(self, obj):
"""Map linked resources to getter functions
The root resource returns a dict of links to top-level resources
TODO: continue implementing customizations for top-level resources
"""
mapping = {
'Systems': Systems,
'Chassis': Chassis,
'Managers': Base,
'Schemas': Base,
'Registries': Base,
'Tasks': Base,
'AccountService': Base,
'Sessions': Base,
'EventService': Base,
}
def getter(connection, href, type):
def _get():
return mapping[type](connection.rest_get(href, {}), self._conn)
return _get
for k in obj['links']:
ref = "get_" + k.lower()
self._links.append(ref)
href = obj['links'][k]['href']
setattr(self, ref, getter(self._conn, href, k))
class Chassis(BaseCollection):
"""Chassis resource class"""
def __len__(self):
return len(self.items)
class Systems(Base):
pass

View File

@ -23,7 +23,7 @@ class Base(object):
self.api_url = tortilla.wrap(url, debug=config.TORTILLADEBUG) self.api_url = tortilla.wrap(url, debug=config.TORTILLADEBUG)
try: try:
if connection_parameters.auth_token == None: if connection_parameters.auth_token is None:
self.data = self.api_url.get(verify=connection_parameters.verify_cert) self.data = self.api_url.get(verify=connection_parameters.verify_cert)
else: else:
self.data = self.api_url.get(verify=connection_parameters.verify_cert, self.data = self.api_url.get(verify=connection_parameters.verify_cert,
@ -140,7 +140,6 @@ class BaseCollection(Base):
self.links = [] self.links = []
#linksmembers = self.data.Links.Members #linksmembers = self.data.Links.Members
#linksmembers = self.data.links.Member #linksmembers = self.data.links.Member
if float(mapping.redfish_version) < 1.00: if float(mapping.redfish_version) < 1.00:
@ -153,7 +152,6 @@ class BaseCollection(Base):
#self.links.append(getattr(link,'href')) #self.links.append(getattr(link,'href'))
self.links.append(urljoin(self.url, getattr(link, mapping.redfish_mapper.map_links_ref()))) self.links.append(urljoin(self.url, getattr(link, mapping.redfish_mapper.map_links_ref())))
config.logger.debug(self.links) config.logger.debug(self.links)
@ -204,10 +202,10 @@ class Managers(Base):
try: try:
# New proliant firmware now respects Redfish v1.00, so seems to correct below statement # New proliant firmware now respects Redfish v1.00, so seems to correct below statement
# TODO : better handle exception and if possible support old firmware ? # TODO : better handle exception and if possible support old firmware ?
self.ethernet_interfaces_collection = EthernetInterfacesCollection( self.ethernet_interfaces_collection = \
EthernetInterfacesCollection(
self.get_link_url('EthernetInterfaces'), self.get_link_url('EthernetInterfaces'),
connection_parameters connection_parameters)
)
# Works on proliant, need to treat 095 vs 0.96 differences # Works on proliant, need to treat 095 vs 0.96 differences
#self.ethernet_interfaces_collection = EthernetInterfacesCollection( #self.ethernet_interfaces_collection = EthernetInterfacesCollection(
@ -222,7 +220,6 @@ class Managers(Base):
# This means we don't have EthernetInterfaces # This means we don't have EthernetInterfaces
self.ethernet_interfaces_collection = None self.ethernet_interfaces_collection = None
def get_firmware_version(self): def get_firmware_version(self):
'''Get firmware version of the manager '''Get firmware version of the manager
@ -303,6 +300,27 @@ class Managers(Base):
except AttributeError: except AttributeError:
return "Not available" return "Not available"
def reset(self):
'''Reset the manager.
:returns: string -- http response of POST request
'''
# Craft the request
link = getattr(self.data.Actions, "#Manager.Reset")
link = link.target
reset_url = urljoin(self.url, link)
response = requests.post(
reset_url,
verify=self.connection_parameters.verify_cert,
headers={'x-auth-token': self.connection_parameters.auth_token,
'Content-type': 'application/json'})
# TODO : treat response.
return response
class ManagersCollection(BaseCollection): class ManagersCollection(BaseCollection):
'''Class to manage redfish ManagersCollection data.''' '''Class to manage redfish ManagersCollection data.'''
def __init__(self, url, connection_parameters): def __init__(self, url, connection_parameters):
@ -429,10 +447,11 @@ class SystemsCollection(BaseCollection):
def __init__(self, url, connection_parameters): def __init__(self, url, connection_parameters):
super(SystemsCollection, self).__init__(url, connection_parameters) super(SystemsCollection, self).__init__(url, connection_parameters)
self.systems_list = [] self.systems_dict = {}
for link in self.links: for link in self.links:
self.systems_list.append(Systems(link, connection_parameters)) index = re.search(r'Systems/(\w+)', link)
self.systems_dict[index.group(1)] = Systems(link, connection_parameters)
class Bios(Base): class Bios(Base):
@ -451,7 +470,8 @@ class Boot(Base):
class EthernetInterfacesCollection(BaseCollection): class EthernetInterfacesCollection(BaseCollection):
'''Class to manage redfish EthernetInterfacesColkection data.''' '''Class to manage redfish EthernetInterfacesColkection data.'''
def __init__(self, url, connection_parameters): def __init__(self, url, connection_parameters):
super(EthernetInterfacesCollection, self).__init__(url, connection_parameters) super(EthernetInterfacesCollection,
self).__init__(url, connection_parameters)
self.ethernet_interfaces_dict = {} self.ethernet_interfaces_dict = {}
@ -460,7 +480,8 @@ class EthernetInterfacesCollection(BaseCollection):
# Check more than 1 hour for this bug.... grrr.... # Check more than 1 hour for this bug.... grrr....
for link in self.links: for link in self.links:
index = re.search(r'EthernetInterfaces/(\w+)', link) index = re.search(r'EthernetInterfaces/(\w+)', link)
self.ethernet_interfaces_dict[index.group(1)] = EthernetInterfaces(link, connection_parameters) self.ethernet_interfaces_dict[index.group(1)] = \
EthernetInterfaces(link, connection_parameters)
class EthernetInterfaces(Base): class EthernetInterfaces(Base):
@ -487,7 +508,6 @@ class EthernetInterfaces(Base):
except AttributeError: except AttributeError:
return "Not available" return "Not available"
def get_ipv4(self): def get_ipv4(self):
'''Get EthernetInterface ipv4 address '''Get EthernetInterface ipv4 address

View File

@ -8,3 +8,5 @@ Babel>=1.3
tortilla>=0.4.1 tortilla>=0.4.1
Jinja2>=2.7.3 Jinja2>=2.7.3
Sphinx>=1.2.3 Sphinx>=1.2.3
docopt>=0.6.2
simplejson>=3.8.1

View File

@ -5,9 +5,11 @@ description-file =
README.rst README.rst
author = Redfish dev team author = Redfish dev team
author-email = python-redfish@mondorescue.org author-email = python-redfish@mondorescue.org
home-page = http://github.com/bcornec/python-redfish home-page = https://github.com/uggla/python-redfish/tree/devel
license = Apache-2
classifier = classifier =
#Environment :: OpenStack Development Status :: 4 - Beta
Environment :: Console
Intended Audience :: Information Technology Intended Audience :: Information Technology
Intended Audience :: System Administrators Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License License :: OSI Approved :: Apache Software License
@ -15,15 +17,21 @@ classifier =
Programming Language :: Python Programming Language :: Python
Programming Language :: Python :: 2 Programming Language :: Python :: 2
Programming Language :: Python :: 2.7 Programming Language :: Python :: 2.7
Programming Language :: Python :: 2.6
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.4
[files] [files]
packages = packages =
redfish redfish
scripts =
redfish-client/redfish-client.py
data_files =
usr/share/redfish-client/templates = redfish-client/templates/*
etc/ = redfish-client/etc/*
[build_sphinx] [build_sphinx]
source-dir = doc/source source-dir = doc/source
build-dir = doc/build build-dir = doc/build