Merge pull request #30 from uggla/python3compat2

Python-redfish, Python3 compatibility
This commit is contained in:
Bruno Cornec 2016-03-07 19:38:32 +01:00
commit 77d9ba4eaf
22 changed files with 180 additions and 65 deletions

View File

@ -13,6 +13,11 @@ NOTE::
is still at version 0.99.0a and may not reflect what the standard provides is still at version 0.99.0a and may not reflect what the standard provides
fully fully
Documentation
-------------
The full documentation is available at
http://pythonhosted.org/python-redfish/installation.html
Project Structure Project Structure
------------------- -------------------
@ -35,7 +40,7 @@ for build and test automation::
Requirements Requirements
------------ ------------
To use the enclosed examples, you will need Python 2.7 To use the enclosed examples, you will need Python 2.7 or Python 3.4
(https://www.python.org/downloads/). Note that Python 2.7.9 enforces greater (https://www.python.org/downloads/). Note that Python 2.7.9 enforces greater
SSL verification requiring server certificates be installed. Parameters to SSL verification requiring server certificates be installed. Parameters to
relax the requirements are available in the library, but these configurations relax the requirements are available in the library, but these configurations
@ -44,6 +49,9 @@ 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.
Note: The program was tested with Python 2.7.10 and 3.4.2 however it might work
as well with all Python 3 releases.
Get the sources Get the sources
--------------- ---------------

11
doc/source/faq.rst Normal file
View File

@ -0,0 +1,11 @@
===
FAQ
===
- Q1 : error in setup command: Invalid environment marker: (python_version < '3')
This error is caused by old setuptools revisions that do not understant "python_version < '3'".
Upgrade setuptools using::
pip install --upgrade setuptools

View File

@ -18,6 +18,7 @@ Contents:
testing testing
classesdoc classesdoc
contributing contributing
faq
help help
Indices and tables Indices and tables

View File

@ -15,6 +15,10 @@ refish-client tests
#. Install docker using the `procedure <https://docs.docker.com/engine/installation/>`_. #. Install docker using the `procedure <https://docs.docker.com/engine/installation/>`_.
#. Ensure you can use docker with your current user. #. Ensure you can use docker with your current user.
#. Jump into redfish-python directory containing the sources. #. Jump into redfish-python directory containing the sources.
#. Depending of your distribution, you may have to upgrade setuptools::
pip install --upgrade setuptools
#. Install required modules for testings:: #. Install required modules for testings::
pip install -t test-requirements.txt pip install -t test-requirements.txt

View File

@ -1 +1,8 @@
__author__ = 'deva' # coding=utf-8
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
__author__ = 'uggla'

View File

@ -1,6 +1,13 @@
# coding=utf-8 # coding=utf-8
""" Simple example to use python-redfish on HP Proliant servers """ """ Simple example to use python-redfish on HP Proliant servers """
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
import os import os
import sys import sys

View File

@ -1,6 +1,12 @@
# coding=utf-8 # coding=utf-8
""" Simple example to use python-redfish with DMTF simulator """ """ Simple example to use python-redfish with DMTF simulator """
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
import os import os
import sys import sys

View File

@ -28,9 +28,17 @@ redfish-client ::
--libdebugfile FILE Specify python-redfish library log file [default: /var/log/python-redfish/python-redfish.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> manager commands : manage the manager (Light out management). If <manager_name>
is not provided use the 'default' entry is not provided use the 'default' entry
''' '''
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
from builtins import object
import os import os
import sys import sys
@ -38,7 +46,7 @@ import json
import pprint import pprint
import docopt import docopt
import logging import logging
import ConfigParser import configparser
import jinja2 import jinja2
import requests.packages.urllib3 import requests.packages.urllib3
import redfish import redfish
@ -268,7 +276,7 @@ if __name__ == '__main__':
% (e.message, jinja2_env.loader.searchpath[0])) % (e.message, jinja2_env.loader.searchpath[0]))
sys.exit(1) sys.exit(1)
print template.render(r=remote_mgmt) print(template.render(r=remote_mgmt))
################################################################# #################################################################
# Main program # Main program
@ -340,7 +348,7 @@ if __name__ == '__main__':
logger.debug("Home directory : %s" % HOME) logger.debug("Home directory : %s" % HOME)
# Load config # Load config
config = ConfigParser.ConfigParser(allow_no_value=True) config = configparser.ConfigParser(allow_no_value=True)
logger.debug("Read configuration file") logger.debug("Read configuration file")
configfile = 'PBCONFFILE' configfile = 'PBCONFFILE'

View File

@ -6,6 +6,9 @@ apt-get install -y python-pip
COPY python-redfish.src.tar.gz /python-redfish.src.tar.gz COPY python-redfish.src.tar.gz /python-redfish.src.tar.gz
RUN mkdir /var/log/python-redfish RUN mkdir /var/log/python-redfish
RUN tar xvvf python-redfish.src.tar.gz RUN tar xvvf python-redfish.src.tar.gz
# Need a really recent version of setuptools to support
# configparser>=3.3.0; python_version < '3' in requirements.txt
RUN pip install --upgrade setuptools
RUN cd python-redfish* && \ RUN cd python-redfish* && \
pip install -r requirements.txt && \ pip install -r requirements.txt && \
python setup.py install python setup.py install

View File

@ -1,6 +1,5 @@
FROM fedora:23 FROM fedora:23
RUN dnf install -y python-pip && \ RUN dnf install -y python-pip && \
dnf install -y git && \
dnf install -y tar dnf install -y tar
COPY python-redfish.src.tar.gz /python-redfish.src.tar.gz COPY python-redfish.src.tar.gz /python-redfish.src.tar.gz
RUN mkdir /var/log/python-redfish RUN mkdir /var/log/python-redfish

View File

@ -0,0 +1,11 @@
FROM fedora:23
RUN dnf install -y python3-pip && \
dnf install -y tar
COPY python-redfish.src.tar.gz /python-redfish.src.tar.gz
RUN mkdir /var/log/python-redfish
RUN tar xvvf python-redfish.src.tar.gz
RUN cd python-redfish* && \
pip3 install -r requirements.txt && \
python3 setup.py install
CMD ["/bin/bash"]

View File

@ -1,6 +1,5 @@
FROM fedora:23 FROM fedora:23
RUN dnf install -y python-pip && \ RUN dnf install -y python-pip
dnf install -y git
RUN mkdir /var/log/python-redfish RUN mkdir /var/log/python-redfish
RUN pip install python-redfish RUN pip install python-redfish
CMD ["/bin/bash"] CMD ["/bin/bash"]

View File

@ -6,6 +6,9 @@ apt-get install -y python-pip
COPY python-redfish.src.tar.gz /python-redfish.src.tar.gz COPY python-redfish.src.tar.gz /python-redfish.src.tar.gz
RUN mkdir /var/log/python-redfish RUN mkdir /var/log/python-redfish
RUN tar xvvf python-redfish.src.tar.gz RUN tar xvvf python-redfish.src.tar.gz
# Need a really recent version of setuptools to support
# configparser>=3.3.0; python_version < '3' in requirements.txt
RUN pip install --upgrade setuptools
RUN cd python-redfish* && \ RUN cd python-redfish* && \
pip install -r requirements.txt && \ pip install -r requirements.txt && \
python setup.py install python setup.py install

View File

@ -1,3 +1,10 @@
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import object
# coding=utf-8 # coding=utf-8
import os import os
import stat import stat
@ -7,7 +14,7 @@ from docker import Client
from path import Path from path import Path
class DockerTest(): class DockerTest(object):
def __init__(self): def __init__(self):
self.cli = Client(base_url='unix://var/run/docker.sock') self.cli = Client(base_url='unix://var/run/docker.sock')
@ -30,7 +37,7 @@ class DockerTest():
self.cli.wait(container=container.get('Id')) self.cli.wait(container=container.get('Id'))
response = self.cli.logs(container=container.get('Id'), response = self.cli.logs(container=container.get('Id'),
stdout=True) stdout=True)
return(response) return(response.decode('utf8'))
def test_dockersocket(): def test_dockersocket():
@ -49,7 +56,7 @@ def test_docker():
def test_sources(): def test_sources():
output = subprocess.check_output(["python", "setup.py", "sdist"]) output = subprocess.check_output(["python", "setup.py", "sdist"])
search = re.search(r"removing '(\S+)'", output) search = re.search(r"removing '(\S+)'", str(output))
filename = Path('dist/' + search.group(1) + '.tar.gz') filename = Path('dist/' + search.group(1) + '.tar.gz')
filename.copy('redfish-client/tests/python-redfish.src.tar.gz') filename.copy('redfish-client/tests/python-redfish.src.tar.gz')
assert Path('redfish-client/tests/python-redfish.src.tar.gz').isfile() assert Path('redfish-client/tests/python-redfish.src.tar.gz').isfile()
@ -57,20 +64,23 @@ def test_sources():
def test_dockerbuild(): def test_dockerbuild():
docker = DockerTest() docker = DockerTest()
# Warning : Image tag is derived from file name, do not use uppercase !!!
dockerfiles = ('redfish-client/tests/Dockerfile.ubuntu', dockerfiles = ('redfish-client/tests/Dockerfile.ubuntu',
'redfish-client/tests/Dockerfile.debian', 'redfish-client/tests/Dockerfile.debian',
'redfish-client/tests/Dockerfile.fedora', 'redfish-client/tests/Dockerfile.fedora',
'redfish-client/tests/Dockerfile.fedorap3',
'redfish-client/tests/Dockerfile.fedorapip') 'redfish-client/tests/Dockerfile.fedorapip')
for dockerfile in dockerfiles: for dockerfile in dockerfiles:
print('Testing : {}'.format(dockerfile)) print('Testing : {}'.format(dockerfile))
response = docker.build(dockerfile) response = docker.build(dockerfile)
status = response.pop() status = str(response.pop())
assert 'Successfully built' in status assert 'Successfully built' in status
def test_install(): def test_install():
docker = DockerTest() docker = DockerTest()
images = ('rfubuntu', 'rfdebian', 'rffedora', 'rffedorapip') images = ('rfubuntu', 'rfdebian',
'rffedora', 'rffedorap3', 'rffedorapip')
for img in images: for img in images:
print('Testing : {}'.format(img)) print('Testing : {}'.format(img))
response = docker.run(img, 'redfish-client config showall') response = docker.run(img, 'redfish-client config showall')
@ -80,10 +90,11 @@ def test_install():
def test_versionformat(): def test_versionformat():
docker = DockerTest() docker = DockerTest()
images = ('rfubuntu', 'rfdebian', 'rffedora', 'rffedorapip') images = ('rfubuntu', 'rfdebian',
'rffedora', 'rffedorap3', 'rffedorapip')
for img in images: for img in images:
print('Testing : {}'.format(img)) print('Testing : {}'.format(img))
response = docker.run(img, 'redfish-client --version') response = docker.run(img, 'redfish-client --version')
print(response) print(response)
assert (re.match('redfish-client \d+\.\d+', response)) assert (re.match(r'redfish-client \d+\.\d+', response))

View File

@ -12,15 +12,21 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
import pbr.version import pbr.version
from redfish.main import * from redfish.main import *
#import redfish.types
try: try:
__version__ = pbr.version.VersionInfo('redfish').release_string() __version__ = pbr.version.VersionInfo('redfish').release_string()
except Exception, e: except Exception as e:
if "Versioning for this project requires either an sdist tarball" in e.message: if "Versioning for this project requires either an sdist tarball" \
in e.args[0]:
pass pass
else: else:
raise raise

View File

@ -1,5 +1,11 @@
# coding=utf-8 # coding=utf-8
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
import logging import logging
import sys import sys
import os import os

View File

@ -1,6 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import config from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
from . import config
class RedfishException(Exception): class RedfishException(Exception):
@ -32,16 +39,6 @@ class InvalidRedfishContentException(RedfishException):
' Most of the time you are not pointing to the rest API\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): class AuthenticationFailureException(RedfishException):
def __init__(self, message, **kwargs): def __init__(self, message, **kwargs):
super(AuthenticationFailureException, self).__init__(message, **kwargs) super(AuthenticationFailureException, self).__init__(message, **kwargs)

View File

@ -1,3 +1,5 @@
# coding=utf-8
#
# Copyright 2014 Hewlett-Packard Development Company, L.P. # Copyright 2014 Hewlett-Packard Development Company, L.P.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -114,17 +116,23 @@ Clients should always be prepared for:
* headers the service returns * headers the service returns
""" """
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import object
# coding=utf-8
import json import json
from urlparse import urlparse from urllib.parse import urlparse
import requests import requests
import config from . import config
import types from . import types
import mapping from . import mapping
import exception from . import exception
"""Function to wrap RedfishConnection""" """Function to wrap RedfishConnection"""
@ -199,10 +207,10 @@ class RedfishConnection(object):
"this is insecure and can allow" + "this is insecure and can allow" +
" a man in the middle attack") " a man in the middle attack")
config.logger.debug("Root url : %s", self.connection_parameters.rooturl) config.logger.debug("Root url : %s",
self.connection_parameters.rooturl)
self.Root = types.Root(self.connection_parameters.rooturl, self.Root = types.Root(self.connection_parameters.rooturl,
self.connection_parameters self.connection_parameters)
)
#self.api_url = tortilla.wrap(self.connection_parameters.rooturl, #self.api_url = tortilla.wrap(self.connection_parameters.rooturl,
# debug=TORTILLADEBUG) # debug=TORTILLADEBUG)
#self.root = self.api_url.get(verify=self.connection_parameters.verify_cert) #self.root = self.api_url.get(verify=self.connection_parameters.verify_cert)

View File

@ -1,4 +1,11 @@
# coding=utf-8 # coding=utf-8
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import object
redfish_mapper = None redfish_mapper = None
redfish_version = None redfish_version = None

View File

@ -1,14 +1,22 @@
# coding=utf-8 # coding=utf-8
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import object
import pprint import pprint
import re import re
from urlparse import urljoin from urllib.parse import urljoin
import requests import requests
import simplejson import simplejson
import tortilla import tortilla
import config import ssl
import mapping from . import config
import exception from . import mapping
from . import exception
# Global variable # Global variable
@ -24,15 +32,17 @@ class Base(object):
try: try:
if connection_parameters.auth_token is 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(
headers={'x-auth-token': connection_parameters.auth_token} verify=connection_parameters.verify_cert,
) headers={
except requests.ConnectionError as e: 'x-auth-token': connection_parameters.auth_token})
except (requests.ConnectionError, ssl.SSLError) as e:
# Log and transmit the exception. # Log and transmit the exception.
config.logger.info('Raise a RedfishException to upper level') config.logger.info('Raise a RedfishException to upper level')
msg = 'Connection error : {}\n'.format(e.message) msg = 'Connection error : {}\n'.format(e)
raise exception.ConnectionFailureException(msg) raise exception.ConnectionFailureException(msg)
except simplejson.scanner.JSONDecodeError as e: except simplejson.scanner.JSONDecodeError as e:
# Log and transmit the exception. # Log and transmit the exception.
@ -41,14 +51,6 @@ class Base(object):
'Ivalid content : Content does not appear to be a valid ' + \ 'Ivalid content : Content does not appear to be a valid ' + \
'Redfish json\n' 'Redfish json\n'
raise exception.InvalidRedfishContentException(msg) 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) config.logger.debug(self.data)
def get_link_url(self, link_type): def get_link_url(self, link_type):

View File

@ -8,3 +8,7 @@ Jinja2>=2.7.3
Sphinx>=1.2.3 Sphinx>=1.2.3
docopt>=0.6.2 docopt>=0.6.2
simplejson>=3.8.1 simplejson>=3.8.1
# Python3 compat
future>=0.15.2
configparser>=3.3.0; python_version < '3'

View File

@ -1,3 +1,10 @@
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import object
#!/usr/bin/env python #!/usr/bin/env python
# Licensed under the Apache License, Version 2.0 (the 'License'); # Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -19,7 +26,7 @@ import fileinput
import re import re
import pprint import pprint
import distutils import distutils
import ConfigParser import configparser
import setuptools import setuptools
from setuptools import Distribution from setuptools import Distribution
from setuptools.command.install import install from setuptools.command.install import install
@ -42,13 +49,13 @@ class OnlyGetScriptPath(install):
self.distribution.install_scripts = self.install_scripts self.distribution.install_scripts = self.install_scripts
class DataFilesHelper(): class DataFilesHelper(object):
'''Class to help manage data files''' '''Class to help manage data files'''
def __init__(self): def __init__(self):
'''Read setup.cfg and build the required data''' '''Read setup.cfg and build the required data'''
self.data = {} self.data = {}
self.setupstruc = [] self.setupstruc = []
config = ConfigParser.ConfigParser() config = configparser.ConfigParser()
config.read('setup.cfg') config.read('setup.cfg')
for datafile in config.options('data_files_helper'): for datafile in config.options('data_files_helper'):
src, dst = config.get('data_files_helper', datafile).split(',') src, dst = config.get('data_files_helper', datafile).split(',')
@ -65,7 +72,7 @@ class DataFilesHelper():
self.data['script'] = {'src': src, self.data['script'] = {'src': src,
'dst': 'bin', 'dst': 'bin',
'fdst': self.calculatedst(src, 'bin')} 'fdst': self.calculatedst(src, 'bin')}
except ConfigParser.NoOptionError: except configparser.NoOptionError:
pass pass
pp = pprint.PrettyPrinter(indent=4) pp = pprint.PrettyPrinter(indent=4)
pp.pprint(self.data) pp.pprint(self.data)