From 909467555552aa3ed155d2fc889b3ade01f3caa9 Mon Sep 17 00:00:00 2001 From: Uggla Date: Sun, 14 Feb 2016 19:30:49 +0100 Subject: [PATCH 1/5] Manage python3 compatibility - Use future module to allow python2/3 compatibility. - New dependencies added future and configparser. --- examples/__init__.py | 9 ++++++++- examples/simple-proliant.py | 7 +++++++ examples/simple-simulator.py | 6 ++++++ redfish-client/redfish-client | 16 +++++++++++---- redfish-client/tests/test_client.py | 9 ++++++++- redfish/__init__.py | 9 +++++++-- redfish/config.py | 6 ++++++ redfish/exception.py | 9 ++++++++- redfish/main.py | 30 ++++++++++++++++++----------- redfish/mapping.py | 7 +++++++ redfish/types.py | 15 +++++++++++---- requirements.txt | 4 ++++ setup.py | 15 +++++++++++---- 13 files changed, 114 insertions(+), 28 deletions(-) diff --git a/examples/__init__.py b/examples/__init__.py index acef755..13c5e6a 100644 --- a/examples/__init__.py +++ b/examples/__init__.py @@ -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' diff --git a/examples/simple-proliant.py b/examples/simple-proliant.py index 451b7a1..a2f2a54 100644 --- a/examples/simple-proliant.py +++ b/examples/simple-proliant.py @@ -1,6 +1,13 @@ # coding=utf-8 """ 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 sys diff --git a/examples/simple-simulator.py b/examples/simple-simulator.py index df44ca5..3e73387 100644 --- a/examples/simple-simulator.py +++ b/examples/simple-simulator.py @@ -1,6 +1,12 @@ # coding=utf-8 """ 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 sys diff --git a/redfish-client/redfish-client b/redfish-client/redfish-client index 917892e..c6d1ddb 100755 --- a/redfish-client/redfish-client +++ b/redfish-client/redfish-client @@ -28,9 +28,17 @@ redfish-client :: --libdebugfile FILE Specify python-redfish library log file [default: /var/log/python-redfish/python-redfish.log] config commands : manage the configuration file. - manager commands : manage the manager (Ligh out management). If + manager commands : manage the manager (Light out management). If 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 sys @@ -38,7 +46,7 @@ import json import pprint import docopt import logging -import ConfigParser +import configparser import jinja2 import requests.packages.urllib3 import redfish @@ -268,7 +276,7 @@ if __name__ == '__main__': % (e.message, jinja2_env.loader.searchpath[0])) sys.exit(1) - print template.render(r=remote_mgmt) + print(template.render(r=remote_mgmt)) ################################################################# # Main program @@ -340,7 +348,7 @@ if __name__ == '__main__': logger.debug("Home directory : %s" % HOME) # Load config - config = ConfigParser.ConfigParser(allow_no_value=True) + config = configparser.ConfigParser(allow_no_value=True) logger.debug("Read configuration file") configfile = 'PBCONFFILE' diff --git a/redfish-client/tests/test_client.py b/redfish-client/tests/test_client.py index 7cd157d..428bb1d 100644 --- a/redfish-client/tests/test_client.py +++ b/redfish-client/tests/test_client.py @@ -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 import os import stat @@ -7,7 +14,7 @@ from docker import Client from path import Path -class DockerTest(): +class DockerTest(object): def __init__(self): self.cli = Client(base_url='unix://var/run/docker.sock') diff --git a/redfish/__init__.py b/redfish/__init__.py index 0a6657b..abe39c8 100644 --- a/redfish/__init__.py +++ b/redfish/__init__.py @@ -12,14 +12,19 @@ # License for the specific language governing permissions and limitations # 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 from redfish.main import * -#import redfish.types try: __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: pass else: diff --git a/redfish/config.py b/redfish/config.py index b4429ed..9f2b7f1 100644 --- a/redfish/config.py +++ b/redfish/config.py @@ -1,5 +1,11 @@ # 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 sys import os diff --git a/redfish/exception.py b/redfish/exception.py index d54feff..bb09b86 100644 --- a/redfish/exception.py +++ b/redfish/exception.py @@ -1,6 +1,13 @@ # -*- 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): diff --git a/redfish/main.py b/redfish/main.py index 98c0205..bf96712 100644 --- a/redfish/main.py +++ b/redfish/main.py @@ -1,3 +1,5 @@ +# coding=utf-8 +# # Copyright 2014 Hewlett-Packard Development Company, L.P. # # 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 """ +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 -from urlparse import urlparse +from urllib.parse import urlparse import requests -import config -import types -import mapping -import exception +from . import config +from . import types +from . import mapping +from . import exception """Function to wrap RedfishConnection""" @@ -196,13 +204,13 @@ class RedfishConnection(object): # Verify cert if self.connection_parameters.verify_cert is False: config.logger.info("Certificat is not checked, " + - "this is insecure and can allow" + - " a man in the middle attack") + "this is insecure and can allow" + + " 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.connection_parameters - ) + self.connection_parameters) #self.api_url = tortilla.wrap(self.connection_parameters.rooturl, # debug=TORTILLADEBUG) #self.root = self.api_url.get(verify=self.connection_parameters.verify_cert) diff --git a/redfish/mapping.py b/redfish/mapping.py index f999cd2..db116ab 100644 --- a/redfish/mapping.py +++ b/redfish/mapping.py @@ -1,4 +1,11 @@ # 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_version = None diff --git a/redfish/types.py b/redfish/types.py index babc5d0..8777398 100644 --- a/redfish/types.py +++ b/redfish/types.py @@ -1,14 +1,21 @@ # 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 re -from urlparse import urljoin +from urllib.parse import urljoin import requests import simplejson import tortilla -import config -import mapping -import exception +from . import config +from . import mapping +from . import exception # Global variable diff --git a/requirements.txt b/requirements.txt index fec375e..dcd8264 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,7 @@ Jinja2>=2.7.3 Sphinx>=1.2.3 docopt>=0.6.2 simplejson>=3.8.1 + +# Python3 compat +future>=0.15.2 +configparser>=3.3.0 diff --git a/setup.py b/setup.py index cc591e5..94994dd 100755 --- a/setup.py +++ b/setup.py @@ -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 # Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. @@ -19,7 +26,7 @@ import fileinput import re import pprint import distutils -import ConfigParser +import configparser import setuptools from setuptools import Distribution from setuptools.command.install import install @@ -42,13 +49,13 @@ class OnlyGetScriptPath(install): self.distribution.install_scripts = self.install_scripts -class DataFilesHelper(): +class DataFilesHelper(object): '''Class to help manage data files''' def __init__(self): '''Read setup.cfg and build the required data''' self.data = {} self.setupstruc = [] - config = ConfigParser.ConfigParser() + config = configparser.ConfigParser() config.read('setup.cfg') for datafile in config.options('data_files_helper'): src, dst = config.get('data_files_helper', datafile).split(',') @@ -65,7 +72,7 @@ class DataFilesHelper(): self.data['script'] = {'src': src, 'dst': 'bin', 'fdst': self.calculatedst(src, 'bin')} - except ConfigParser.NoOptionError: + except configparser.NoOptionError: pass pp = pprint.PrettyPrinter(indent=4) pp.pprint(self.data) From 7c33c819235c53cb23510387306648c7a1030f80 Mon Sep 17 00:00:00 2001 From: Uggla Date: Mon, 15 Feb 2016 11:14:17 +0100 Subject: [PATCH 2/5] Python3 requirements, remove configparser module. - configparser is a backported module for python2 and is a python 3 buildin module. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dcd8264..14b281f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,4 +11,4 @@ simplejson>=3.8.1 # Python3 compat future>=0.15.2 -configparser>=3.3.0 +configparser>=3.3.0; python_version < '3' From d09a63a4c69f724cf24f93a185f109c2d927dc90 Mon Sep 17 00:00:00 2001 From: Uggla Date: Mon, 15 Feb 2016 17:02:35 +0100 Subject: [PATCH 3/5] Review connection error handling due to python3 backports - Inclusion on future module might have changed some exception behaviors. So code changed following python2/3 tests. --- redfish/exception.py | 10 ---------- redfish/types.py | 23 +++++++++-------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/redfish/exception.py b/redfish/exception.py index bb09b86..84b67cf 100644 --- a/redfish/exception.py +++ b/redfish/exception.py @@ -39,16 +39,6 @@ class InvalidRedfishContentException(RedfishException): ' 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 :443\n' - - class AuthenticationFailureException(RedfishException): def __init__(self, message, **kwargs): super(AuthenticationFailureException, self).__init__(message, **kwargs) diff --git a/redfish/types.py b/redfish/types.py index 8777398..478ab53 100644 --- a/redfish/types.py +++ b/redfish/types.py @@ -13,6 +13,7 @@ from urllib.parse import urljoin import requests import simplejson import tortilla +import ssl from . import config from . import mapping from . import exception @@ -31,15 +32,17 @@ class Base(object): try: 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: - self.data = self.api_url.get(verify=connection_parameters.verify_cert, - headers={'x-auth-token': connection_parameters.auth_token} - ) - except requests.ConnectionError as e: + self.data = self.api_url.get( + verify=connection_parameters.verify_cert, + headers={ + 'x-auth-token': connection_parameters.auth_token}) + except (requests.ConnectionError, ssl.SSLError) as e: # Log and transmit the exception. 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) except simplejson.scanner.JSONDecodeError as e: # Log and transmit the exception. @@ -48,14 +51,6 @@ class Base(object): 'Ivalid content : Content does not appear to be a valid ' + \ 'Redfish json\n' raise exception.InvalidRedfishContentException(msg) - except TypeError as e: - # This happen connecting to a manager using non trusted - # SSL certificats. - # The exception is not what could be expected in such case but this - # is the one provided by Tortilla. - config.logger.info('Raise a RedfishException to upper level') - msg = 'Connection error\n' - raise exception.NonTrustedCertificatException(msg) config.logger.debug(self.data) def get_link_url(self, link_type): From 66cb53df4ec0c8df5a577c4018951767af814d87 Mon Sep 17 00:00:00 2001 From: Uggla Date: Sat, 5 Mar 2016 18:54:34 +0100 Subject: [PATCH 4/5] Add tests to validate python-redfish is working with python3 - Update setuptools within dockerfiles to support requirements.txt syntax. - Check that tests can be run with Python2 and 3. --- redfish-client/tests/Dockerfile.debian | 3 +++ redfish-client/tests/Dockerfile.fedora | 1 - redfish-client/tests/Dockerfile.fedorap3 | 11 +++++++++++ redfish-client/tests/Dockerfile.fedorapip | 3 +-- redfish-client/tests/Dockerfile.ubuntu | 3 +++ redfish-client/tests/test_client.py | 16 ++++++++++------ redfish/__init__.py | 3 ++- 7 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 redfish-client/tests/Dockerfile.fedorap3 diff --git a/redfish-client/tests/Dockerfile.debian b/redfish-client/tests/Dockerfile.debian index bb09658..e5c01fc 100644 --- a/redfish-client/tests/Dockerfile.debian +++ b/redfish-client/tests/Dockerfile.debian @@ -6,6 +6,9 @@ apt-get install -y python-pip 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 +# 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* && \ pip install -r requirements.txt && \ python setup.py install diff --git a/redfish-client/tests/Dockerfile.fedora b/redfish-client/tests/Dockerfile.fedora index 4770d9f..b28b8dd 100644 --- a/redfish-client/tests/Dockerfile.fedora +++ b/redfish-client/tests/Dockerfile.fedora @@ -1,6 +1,5 @@ FROM fedora:23 RUN dnf install -y python-pip && \ -dnf install -y git && \ dnf install -y tar COPY python-redfish.src.tar.gz /python-redfish.src.tar.gz RUN mkdir /var/log/python-redfish diff --git a/redfish-client/tests/Dockerfile.fedorap3 b/redfish-client/tests/Dockerfile.fedorap3 new file mode 100644 index 0000000..f2fbc89 --- /dev/null +++ b/redfish-client/tests/Dockerfile.fedorap3 @@ -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"] + diff --git a/redfish-client/tests/Dockerfile.fedorapip b/redfish-client/tests/Dockerfile.fedorapip index dfb0cad..4d29b63 100644 --- a/redfish-client/tests/Dockerfile.fedorapip +++ b/redfish-client/tests/Dockerfile.fedorapip @@ -1,6 +1,5 @@ FROM fedora:23 -RUN dnf install -y python-pip && \ -dnf install -y git +RUN dnf install -y python-pip RUN mkdir /var/log/python-redfish RUN pip install python-redfish CMD ["/bin/bash"] diff --git a/redfish-client/tests/Dockerfile.ubuntu b/redfish-client/tests/Dockerfile.ubuntu index c77091c..1b9e542 100644 --- a/redfish-client/tests/Dockerfile.ubuntu +++ b/redfish-client/tests/Dockerfile.ubuntu @@ -6,6 +6,9 @@ apt-get install -y python-pip 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 +# 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* && \ pip install -r requirements.txt && \ python setup.py install diff --git a/redfish-client/tests/test_client.py b/redfish-client/tests/test_client.py index 428bb1d..1f41752 100644 --- a/redfish-client/tests/test_client.py +++ b/redfish-client/tests/test_client.py @@ -37,7 +37,7 @@ class DockerTest(object): self.cli.wait(container=container.get('Id')) response = self.cli.logs(container=container.get('Id'), stdout=True) - return(response) + return(response.decode('utf8')) def test_dockersocket(): @@ -56,7 +56,7 @@ def test_docker(): def test_sources(): 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.copy('redfish-client/tests/python-redfish.src.tar.gz') assert Path('redfish-client/tests/python-redfish.src.tar.gz').isfile() @@ -64,20 +64,23 @@ def test_sources(): def test_dockerbuild(): docker = DockerTest() + # Warning : Image tag is derived from file name, do not use uppercase !!! dockerfiles = ('redfish-client/tests/Dockerfile.ubuntu', 'redfish-client/tests/Dockerfile.debian', 'redfish-client/tests/Dockerfile.fedora', + 'redfish-client/tests/Dockerfile.fedorap3', 'redfish-client/tests/Dockerfile.fedorapip') for dockerfile in dockerfiles: print('Testing : {}'.format(dockerfile)) response = docker.build(dockerfile) - status = response.pop() + status = str(response.pop()) assert 'Successfully built' in status def test_install(): docker = DockerTest() - images = ('rfubuntu', 'rfdebian', 'rffedora', 'rffedorapip') + images = ('rfubuntu', 'rfdebian', + 'rffedora', 'rffedorap3', 'rffedorapip') for img in images: print('Testing : {}'.format(img)) response = docker.run(img, 'redfish-client config showall') @@ -87,10 +90,11 @@ def test_install(): def test_versionformat(): docker = DockerTest() - images = ('rfubuntu', 'rfdebian', 'rffedora', 'rffedorapip') + images = ('rfubuntu', 'rfdebian', + 'rffedora', 'rffedorap3', 'rffedorapip') for img in images: print('Testing : {}'.format(img)) response = docker.run(img, 'redfish-client --version') print(response) - assert (re.match('redfish-client \d+\.\d+', response)) + assert (re.match(r'redfish-client \d+\.\d+', response)) diff --git a/redfish/__init__.py b/redfish/__init__.py index abe39c8..2b57f55 100644 --- a/redfish/__init__.py +++ b/redfish/__init__.py @@ -25,7 +25,8 @@ from redfish.main import * try: __version__ = pbr.version.VersionInfo('redfish').release_string() 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 else: raise From 351547b0517484a8cb50d27dee8d7c5a1fa1ea25 Mon Sep 17 00:00:00 2001 From: Uggla Date: Mon, 15 Feb 2016 17:16:16 +0100 Subject: [PATCH 5/5] Update documentation - Add python3 release. - Add a FAQ. - Various minor updates. --- README.rst | 14 +++++++++++--- doc/source/faq.rst | 11 +++++++++++ doc/source/index.rst | 1 + doc/source/testing.rst | 4 ++++ 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 doc/source/faq.rst diff --git a/README.rst b/README.rst index 4b4cf50..cb69f58 100644 --- a/README.rst +++ b/README.rst @@ -9,10 +9,15 @@ NOTE:: DRAFT - WORK IN PROGRESS - The current Redfish specification revision is 1.0.0 - Note that the mockup - is still at version 0.99.0a and may not reflect what the standard provides + The current Redfish specification revision is 1.0.0 - Note that the mockup + is still at version 0.99.0a and may not reflect what the standard provides fully +Documentation +------------- + +The full documentation is available at +http://pythonhosted.org/python-redfish/installation.html Project Structure ------------------- @@ -35,7 +40,7 @@ for build and test automation:: 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 SSL verification requiring server certificates be installed. Parameters to 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 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 --------------- diff --git a/doc/source/faq.rst b/doc/source/faq.rst new file mode 100644 index 0000000..8e53b2a --- /dev/null +++ b/doc/source/faq.rst @@ -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 + diff --git a/doc/source/index.rst b/doc/source/index.rst index 15abfa7..2de689e 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -18,6 +18,7 @@ Contents: testing classesdoc contributing + faq help Indices and tables diff --git a/doc/source/testing.rst b/doc/source/testing.rst index ac94b45..dd0d90c 100644 --- a/doc/source/testing.rst +++ b/doc/source/testing.rst @@ -15,6 +15,10 @@ refish-client tests #. Install docker using the `procedure `_. #. Ensure you can use docker with your current user. #. 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:: pip install -t test-requirements.txt