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,
you must follow the steps in this page:
If you would like to contribute to the development of this project.
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
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
You can also share and discuss on the mailing list as well.

View File

@ -20,14 +20,17 @@ Project Structure
This project follows the same convention as OpenStack projects, eg. using pbr
for build and test automation::
doc/ # documentation
doc/source # the doc source files live here
doc/build/html # output of building any docs will go here
doc/ # Documentation
doc/source # The doc source files live here
doc/build/html # Output of building any docs will go here
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
redfish/ # the redfish library
redfish/tests/ # python unit test suite
pbconf # Project builder file to build rpm/deb packages for
# distributions
redfish/ # The redfish library itself
redfish/tests/ # Python redfish unit test suite
redfish-client # Client tool to manage redfish devices
Requirements
------------
@ -41,23 +44,31 @@ are discouraged due to security.
Python requirements are listed in requirements.txt; additional requirements for
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)
you should run the following commands
The sources are available on github and can be retrieved using::
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
--------
Distribution list : python-redfish@mondorescue.org
Distribution list: python-redfish@mondorescue.org
Further References
------------------
The data model documentation can be found here:
http://www.redfishspecification.org/redfish-data-model-and-schema/
The overall protocol documentation can be found here:
http://www.redfishspecification.org/
Please look at `dmtf/README.rst <further_ref.html>`_ file.

View File

@ -1,12 +1,26 @@
DMTF Redfish specification
--------------------------
This directory contains the current references from the DMTF on the Redfish
specification (1.0.0 at the time of the writing)
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
This directory contains the current references from the DMTF on the Redfish
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
a Redfish based system so it is possible to write programs without real Redfish
compliant hardware platform.
Note: Mockup release is still 0.99.0a and so not aligned with specification realease
number.
Docker container
----------------

View File

@ -48,16 +48,16 @@ master_doc = 'index'
# General information about the project.
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
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.4'
version = 'PBVER'
# The full version, including alpha/beta/rc tags.
release = '0.4'
release = 'PBVER'
# The language for content autogenerated by Sphinx. Refer to documentation
# 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
installation
usage
contributing
develsetup
classesdoc
contributing
help
Indices and tables
==================

View File

@ -2,11 +2,226 @@
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
========
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": {
"url": "",
"login": "",

View File

@ -43,48 +43,48 @@ except redfish.exception.RedfishException as e:
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_dict["1"].reset_system()
# TODO : create an attribute to link the managed system directly
# and avoid systems_list[0]
# and avoid systems_dict["1"]
# --> 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("Serial Number : {}\n".format(remote_mgmt.Systems.systems_list[0].get_serial_number()))
print("Power State : {}\n".format(remote_mgmt.Systems.systems_list[0].get_power()))
print("Parameter 'SystemType' : {}\n".format(remote_mgmt.Systems.systems_list[0].get_parameter("SystemType")))
print("Bios version : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_bios_version()))
print("Serial Number : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_serial_number()))
print("Power State : {}\n".format(remote_mgmt.Systems.systems_dict["1"].get_power()))
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 boot parameters : {}\n".format(remote_mgmt.Systems.systems_list[0].bios.boot.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_dict["1"].bios.boot.get_parameters()))
#print("Get bios parameter 'AdminPhone' : {}\n".format(remote_mgmt.Systems.systems_list[0].bios.get_parameter("AdminPhone")))
#print("Set bios parameter 'AdminPhone' to '' : {}\n".format(remote_mgmt.Systems.systems_list[0].bios.set_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_dict["1"].bios.set_parameter("AdminPhone","")))
#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_list[0].bios.set_parameter("UefiShellStartup", "Enabled")
remote_mgmt.Systems.systems_list[0].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("PreBootNetwork", "Auto")
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("UefiShellStartup", "Enabled")
remote_mgmt.Systems.systems_dict["1"].bios.set_parameter("UefiShellStartupLocation", "NetworkLocation")
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_list[0].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": {"BootSourceOverrideTarget": "UefiShell"}}')
# remote_mgmt.Systems.systems_dict["1"].set_parameter_json('{"Boot": {"BootSourceOverrideEnabled" : "Continuous"}}')
#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")
#Uncomment the next line to reset the server
#mySystem.reset_system()
print("Get manager firmware version : {}\n".format(remote_mgmt.Managers.managers_list[0].get_firmware_version()))
print("Get system Bios version : {}\n".format(remote_mgmt.Systems.systems_list[0].get_bios_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_dict["1"].get_bios_version()))
#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()

View File

@ -43,7 +43,7 @@ except redfish.exception.RedfishException as e:
print("Redfish API version : {} \n".format(remote_mgmt.get_api_version()))
print("UUID : {} \n".format(remote_mgmt.Root.get_api_UUID()))
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("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()

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
# 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
# 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 docopt
import logging
import redfish
import requests.packages.urllib3
import ConfigParser
import jinja2
import requests.packages.urllib3
import redfish
class ConfigFile(object):
'''redfisht-client configuration file management'''
@ -253,7 +253,13 @@ if __name__ == '__main__':
sys.exit(1)
# Display manager information using jinja2 template
template = jinja2_env.get_template("manager_info.template")
try:
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)
@ -314,23 +320,48 @@ if __name__ == '__main__':
logger.info("Arguments parsed")
logger.debug(arguments)
# Get $HOME environment.
# Get $HOME and $VIRTUAL_ENV environment variables.
HOME = os.getenv('HOME')
VIRTUAL_ENV = os.getenv('VIRTUAL_ENV')
if not HOME:
print('$HOME environment variable not set, please check your system')
logger.error('$HOME environment variable not set')
sys.exit(1)
logger.debug("Home directory : %s" % HOME)
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)
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 ?
templates_path = config.get("redfish-client", "templates_path")
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:
logger.debug("Config commands")
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

@ -1,4 +1,4 @@
Redfish API version : {{ r.get_api_version() }}
Redfish API version : {{ r.get_api_version() }}
{{ r.Root.get_name() }}
Managers information :
@ -17,11 +17,12 @@ Ethernet Interface :
Ethernet Interface id {{ ethernetinterface_index }} :
{{ ei.get_name() }}
FQDN : {{ ei.get_fqdn() }}
Mac address : {{ ei.get_mac() }}
Address ipv4 : {{ ei.get_ipv4() | join(', ') }}
Address ipv6 : {{ ei.get_ipv6() | join(', ') }}
{%- endfor %}
{%- else %}
This manager has no ethernet interface
This manager has no ethernet interface
{%- endif %}
Managed Chassis :
{{ manager.get_managed_chassis() | join(', ') }}

View File

@ -12,11 +12,15 @@
# License for the specific language governing permissions and limitations
# under the License.
#import pbr.version
import pbr.version
from redfish.main import *
#import redfish.types
#__version__ = pbr.version.VersionInfo(
# 'redfish').version_string()
try:
__version__ = pbr.version.VersionInfo('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):
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'
self.advices = \
'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):

View File

@ -247,8 +247,6 @@ class RedfishConnection(object):
self.connection_parameters
)
#for system in self.Systems.systems_list:
#config.logger.debug(system.data.links.ManagedBy)
# self.Chassis
# 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)
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)
else:
self.data = self.api_url.get(verify=connection_parameters.verify_cert,
@ -63,11 +63,11 @@ class Base(object):
if float(mapping.redfish_version) < 1.00:
links = getattr(self.data, mapping.redfish_mapper.map_links())
if link_type in links:
return urljoin(self.url, links[link_type][mapping.redfish_mapper.map_links_ref()])
return urljoin(self.url, links[link_type][mapping.redfish_mapper.map_links_ref()])
else:
links = getattr(self.data, link_type)
link = getattr(links, mapping.redfish_mapper.map_links_ref())
return urljoin(self.url, link)
return urljoin(self.url, link)
@property
def url(self):
@ -120,7 +120,7 @@ class Base(object):
headers={'x-auth-token': self.connection_parameters.auth_token},
data=action)
return response
def get_name(self):
'''Get root name
@ -138,8 +138,7 @@ class BaseCollection(Base):
def __init__(self, url, connection_parameters):
super(BaseCollection, self).__init__(url, connection_parameters)
self.links=[]
self.links = []
#linksmembers = self.data.Links.Members
#linksmembers = self.data.links.Member
@ -153,7 +152,6 @@ class BaseCollection(Base):
#self.links.append(getattr(link,'href'))
self.links.append(urljoin(self.url, getattr(link, mapping.redfish_mapper.map_links_ref())))
config.logger.debug(self.links)
@ -189,7 +187,7 @@ class Root(Base):
:returns: string -- path
'''
return getattr(self.root.Links.Systems, '@odata.id')
return getattr(self.root.Links.Systems, '@odata.id')
class SessionService(Base):
@ -204,10 +202,10 @@ class Managers(Base):
try:
# 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('EthernetInterfaces'),
connection_parameters
)
self.ethernet_interfaces_collection = \
EthernetInterfacesCollection(
self.get_link_url('EthernetInterfaces'),
connection_parameters)
# Works on proliant, need to treat 095 vs 0.96 differences
#self.ethernet_interfaces_collection = EthernetInterfacesCollection(
@ -217,11 +215,10 @@ class Managers(Base):
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
@ -257,7 +254,7 @@ class Managers(Base):
return self.data.UUID
except AttributeError:
return "Not available"
def get_status(self):
'''Get manager status
@ -277,7 +274,7 @@ class Managers(Base):
'''
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)])
@ -294,15 +291,36 @@ class Managers(Base):
'''
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))
systems_list.append(result.group(1))
return systems_list
except AttributeError:
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 to manage redfish ManagersCollection data.'''
def __init__(self, url, connection_parameters):
@ -344,7 +362,7 @@ class Systems(Base):
data=action
)
#TODO : treat response.
return response
return response
def get_bios_version(self):
'''Get bios version of the system.
@ -429,10 +447,11 @@ class SystemsCollection(BaseCollection):
def __init__(self, url, connection_parameters):
super(SystemsCollection, self).__init__(url, connection_parameters)
self.systems_list = []
self.systems_dict = {}
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):
@ -451,7 +470,8 @@ class Boot(Base):
class EthernetInterfacesCollection(BaseCollection):
'''Class to manage redfish EthernetInterfacesColkection data.'''
def __init__(self, url, connection_parameters):
super(EthernetInterfacesCollection, self).__init__(url, connection_parameters)
super(EthernetInterfacesCollection,
self).__init__(url, connection_parameters)
self.ethernet_interfaces_dict = {}
@ -460,7 +480,8 @@ class EthernetInterfacesCollection(BaseCollection):
# Check more than 1 hour for this bug.... grrr....
for link in self.links:
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):
@ -486,40 +507,39 @@ class EthernetInterfaces(Base):
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"

View File

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

View File

@ -5,24 +5,32 @@ description-file =
README.rst
author = Redfish dev team
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 =
#Environment :: OpenStack
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 2.6
Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
Programming Language :: Python :: 3.4
Development Status :: 4 - Beta
Environment :: Console
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
[files]
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]
source-dir = doc/source