Merge tag '1.10.0' into debian/liberty
oslo.concurrency 1.10.0 release
This commit is contained in:
10
README.rst
10
README.rst
@@ -2,7 +2,15 @@
|
|||||||
oslo.concurrency
|
oslo.concurrency
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Oslo concurrency library has utilities for safely running multi-thread,
|
.. image:: https://pypip.in/version/oslo.concurrency/badge.svg
|
||||||
|
:target: https://pypi.python.org/pypi/oslo.concurrency/
|
||||||
|
:alt: Latest Version
|
||||||
|
|
||||||
|
.. image:: https://pypip.in/download/oslo.concurrency/badge.svg?period=month
|
||||||
|
:target: https://pypi.python.org/pypi/oslo.concurrency/
|
||||||
|
:alt: Downloads
|
||||||
|
|
||||||
|
The oslo.concurrency library has utilities for safely running multi-thread,
|
||||||
multi-process applications using locking mechanisms and for running
|
multi-process applications using locking mechanisms and for running
|
||||||
external processes.
|
external processes.
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
.. oslo.concurrency documentation master file, created by
|
============================================
|
||||||
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
|
Welcome to oslo.concurrency's documentation!
|
||||||
You can adapt this file completely to your liking, but it should at least
|
============================================
|
||||||
contain the root `toctree` directive.
|
|
||||||
|
|
||||||
==================
|
The `oslo`_ concurrency library has utilities for safely running multi-thread,
|
||||||
oslo.concurrency
|
multi-process applications using locking mechanisms and for running
|
||||||
==================
|
external processes.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
readme
|
|
||||||
installation
|
installation
|
||||||
usage
|
usage
|
||||||
contributing
|
contributing
|
||||||
@@ -30,3 +28,5 @@ Indices and tables
|
|||||||
* :ref:`genindex`
|
* :ref:`genindex`
|
||||||
* :ref:`modindex`
|
* :ref:`modindex`
|
||||||
* :ref:`search`
|
* :ref:`search`
|
||||||
|
|
||||||
|
.. _oslo: https://wiki.openstack.org/wiki/Oslo
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
.. include:: ../../README.rst
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
# The list of modules to copy from oslo-incubator.git
|
# The list of modules to copy from oslo-incubator.git
|
||||||
module = fileutils
|
module = fileutils
|
||||||
script = tools/run_cross_tests.sh
|
|
||||||
|
|
||||||
# The base module to hold the copy of openstack.common
|
# The base module to hold the copy of openstack.common
|
||||||
base=oslo.concurrency
|
base=oslo_concurrency
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Translations template for oslo.concurrency.
|
||||||
|
# Copyright (C) 2015 ORGANIZATION
|
||||||
|
# This file is distributed under the same license as the oslo.concurrency
|
||||||
|
# project.
|
||||||
|
#
|
||||||
|
# Translators:
|
||||||
|
# Andi Chandler <andi@gowling.com>, 2014-2015
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: oslo.concurrency\n"
|
||||||
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
|
"POT-Creation-Date: 2015-05-28 06:05+0000\n"
|
||||||
|
"PO-Revision-Date: 2015-03-24 01:20+0000\n"
|
||||||
|
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
||||||
|
"Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/"
|
||||||
|
"osloconcurrency/language/en_GB/)\n"
|
||||||
|
"Language: en_GB\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Generated-By: Babel 1.3\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Could not close the acquired file handle `%s`"
|
||||||
|
msgstr "Could not close the acquired file handle `%s`"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Could not unlock the acquired lock `%s`"
|
||||||
|
msgstr "Could not unlock the acquired lock `%s`"
|
||||||
@@ -21,14 +21,10 @@ msgstr ""
|
|||||||
"Generated-By: Babel 1.3\n"
|
"Generated-By: Babel 1.3\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: oslo/concurrency/lockutils.py:84
|
|
||||||
#: oslo/concurrency/openstack/common/lockutils.py:82
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Created lock path: %s"
|
msgid "Created lock path: %s"
|
||||||
msgstr "Created lock path: %s"
|
msgstr "Created lock path: %s"
|
||||||
|
|
||||||
#: oslo/concurrency/lockutils.py:201
|
|
||||||
#: oslo/concurrency/openstack/common/lockutils.py:251
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Failed to remove file %(file)s"
|
msgid "Failed to remove file %(file)s"
|
||||||
msgstr "Failed to remove file %(file)s"
|
msgstr "Failed to remove file %(file)s"
|
||||||
|
|||||||
@@ -1,79 +1,25 @@
|
|||||||
# English (United Kingdom) translations for oslo.concurrency.
|
# English (United Kingdom) translations for oslo.concurrency.
|
||||||
# Copyright (C) 2014 ORGANIZATION
|
# Copyright (C) 2015 ORGANIZATION
|
||||||
# This file is distributed under the same license as the oslo.concurrency
|
# This file is distributed under the same license as the oslo.concurrency
|
||||||
# project.
|
# project.
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# Andi Chandler <andi@gowling.com>, 2014
|
# Andi Chandler <andi@gowling.com>, 2014-2015
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: oslo.concurrency\n"
|
"Project-Id-Version: oslo.concurrency\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2014-10-29 06:10+0000\n"
|
"POT-Creation-Date: 2015-05-28 06:05+0000\n"
|
||||||
"PO-Revision-Date: 2014-10-28 20:48+0000\n"
|
"PO-Revision-Date: 2015-03-24 01:19+0000\n"
|
||||||
"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
|
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
||||||
"Language-Team: English (United Kingdom) "
|
"Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/"
|
||||||
"(http://www.transifex.com/projects/p/osloconcurrency/language/en_GB/)\n"
|
"osloconcurrency/language/en_GB/)\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 1.3\n"
|
"Generated-By: Babel 1.3\n"
|
||||||
|
|
||||||
#: oslo/concurrency/lockutils.py:120
|
|
||||||
#, python-format
|
|
||||||
msgid "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
|
||||||
msgstr "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
|
||||||
|
|
||||||
#: oslo/concurrency/lockutils.py:134
|
|
||||||
msgid "Unable to release an unacquired lock"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: oslo/concurrency/lockutils.py:385
|
|
||||||
msgid ""
|
|
||||||
"Calling lockutils directly is no longer supported. Please use the "
|
|
||||||
"lockutils-wrapper console script instead."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:69
|
|
||||||
msgid "Unexpected error while running command."
|
|
||||||
msgstr "Unexpected error while running command."
|
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:72
|
|
||||||
#, python-format
|
|
||||||
msgid ""
|
|
||||||
"%(description)s\n"
|
|
||||||
"Command: %(cmd)s\n"
|
|
||||||
"Exit code: %(exit_code)s\n"
|
|
||||||
"Stdout: %(stdout)r\n"
|
|
||||||
"Stderr: %(stderr)r"
|
|
||||||
msgstr ""
|
|
||||||
"%(description)s\n"
|
|
||||||
"Command: %(cmd)s\n"
|
|
||||||
"Exit code: %(exit_code)s\n"
|
|
||||||
"Stdout: %(stdout)r\n"
|
|
||||||
"Stderr: %(stderr)r"
|
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:171
|
|
||||||
#, python-format
|
|
||||||
msgid "Got unknown keyword args: %r"
|
|
||||||
msgstr "Got unknown keyword args: %r"
|
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:174
|
|
||||||
#, python-format
|
|
||||||
msgid "Got invalid arg log_errors: %r"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:180
|
|
||||||
msgid "Command requested root, but did not specify a root helper."
|
|
||||||
msgstr "Command requested root, but did not specify a root helper."
|
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:191
|
|
||||||
#, python-format
|
|
||||||
msgid "Running cmd (subprocess): %s"
|
|
||||||
msgstr "Running cmd (subprocess): %s"
|
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:233
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"%(desc)r\n"
|
"%(desc)r\n"
|
||||||
@@ -82,30 +28,78 @@ msgid ""
|
|||||||
"stdout: %(stdout)r\n"
|
"stdout: %(stdout)r\n"
|
||||||
"stderr: %(stderr)r"
|
"stderr: %(stderr)r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"%(desc)r\n"
|
||||||
|
"command: %(cmd)r\n"
|
||||||
|
"exit code: %(code)r\n"
|
||||||
|
"stdout: %(stdout)r\n"
|
||||||
|
"stderr: %(stderr)r"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"%(description)s\n"
|
||||||
|
"Command: %(cmd)s\n"
|
||||||
|
"Exit code: %(exit_code)s\n"
|
||||||
|
"Stdout: %(stdout)r\n"
|
||||||
|
"Stderr: %(stderr)r"
|
||||||
|
msgstr ""
|
||||||
|
"%(description)s\n"
|
||||||
|
"Command: %(cmd)s\n"
|
||||||
|
"Exit code: %(exit_code)s\n"
|
||||||
|
"Stdout: %(stdout)r\n"
|
||||||
|
"Stderr: %(stderr)r"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "%r failed. Not Retrying."
|
||||||
|
msgstr "%r failed. Not Retrying."
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "%r failed. Retrying."
|
||||||
|
msgstr "%r failed. Retrying."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Calling lockutils directly is no longer supported. Please use the lockutils-"
|
||||||
|
"wrapper console script instead."
|
||||||
|
msgstr ""
|
||||||
|
"Calling lockutils directly is no longer supported. Please use the lockutils-"
|
||||||
|
"wrapper console script instead."
|
||||||
|
|
||||||
|
msgid "Command requested root, but did not specify a root helper."
|
||||||
|
msgstr "Command requested root, but did not specify a root helper."
|
||||||
|
|
||||||
|
msgid "Environment not supported over SSH"
|
||||||
|
msgstr "Environment not supported over SSH"
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:242
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Got an OSError\n"
|
"Got an OSError\n"
|
||||||
"command: %(cmd)r\n"
|
"command: %(cmd)r\n"
|
||||||
"errno: %(errno)r"
|
"errno: %(errno)r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Got an OSError\n"
|
||||||
|
"command: %(cmd)r\n"
|
||||||
|
"errno: %(errno)r"
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:248
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%r failed. Not Retrying."
|
msgid "Got invalid arg log_errors: %r"
|
||||||
msgstr ""
|
msgstr "Got invalid arg log_errors: %r"
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:252
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%r failed. Retrying."
|
msgid "Got unknown keyword args: %r"
|
||||||
msgstr "%r failed. Retrying."
|
msgstr "Got unknown keyword args: %r"
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:299
|
#, python-format
|
||||||
msgid "Environment not supported over SSH"
|
msgid "Running cmd (subprocess): %s"
|
||||||
msgstr "Environment not supported over SSH"
|
msgstr "Running cmd (subprocess): %s"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||||
|
msgstr "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||||
|
|
||||||
|
msgid "Unable to release an unacquired lock"
|
||||||
|
msgstr "Unable to release an unacquired lock"
|
||||||
|
|
||||||
|
msgid "Unexpected error while running command."
|
||||||
|
msgstr "Unexpected error while running command."
|
||||||
|
|
||||||
#: oslo/concurrency/processutils.py:303
|
|
||||||
msgid "process_input not supported over SSH"
|
msgid "process_input not supported over SSH"
|
||||||
msgstr "process_input not supported over SSH"
|
msgstr "process_input not supported over SSH"
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: oslo.concurrency\n"
|
"Project-Id-Version: oslo.concurrency\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2015-03-09 06:08+0000\n"
|
"POT-Creation-Date: 2015-05-28 06:05+0000\n"
|
||||||
"PO-Revision-Date: 2015-03-08 16:34+0000\n"
|
"PO-Revision-Date: 2015-03-08 16:34+0000\n"
|
||||||
"Last-Translator: Maxime COQUEREL <max.coquerel@gmail.com>\n"
|
"Last-Translator: Maxime COQUEREL <max.coquerel@gmail.com>\n"
|
||||||
"Language-Team: French (http://www.transifex.com/projects/p/osloconcurrency/"
|
"Language-Team: French (http://www.transifex.com/projects/p/osloconcurrency/"
|
||||||
@@ -21,12 +21,10 @@ msgstr ""
|
|||||||
"Generated-By: Babel 1.3\n"
|
"Generated-By: Babel 1.3\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
|
||||||
#: oslo_concurrency/lockutils.py:217
|
|
||||||
#, python-format
|
|
||||||
msgid "Could not unlock the acquired lock `%s`"
|
|
||||||
msgstr "Impossible de libérer le verrou acquis %s"
|
|
||||||
|
|
||||||
#: oslo_concurrency/lockutils.py:223
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Could not close the acquired file handle `%s`"
|
msgid "Could not close the acquired file handle `%s`"
|
||||||
msgstr "Impossible de libérer le descripteur de fichier %s"
|
msgstr "Impossible de libérer le descripteur de fichier %s"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Could not unlock the acquired lock `%s`"
|
||||||
|
msgstr "Impossible de libérer le verrou acquis %s"
|
||||||
|
|||||||
@@ -21,12 +21,10 @@ msgstr ""
|
|||||||
"Generated-By: Babel 1.3\n"
|
"Generated-By: Babel 1.3\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
|
|
||||||
#: oslo_concurrency/lockutils.py:181
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Created lock path: %s"
|
msgid "Created lock path: %s"
|
||||||
msgstr "Chemin de verrou créé %s"
|
msgstr "Chemin de verrou créé %s"
|
||||||
|
|
||||||
#: oslo_concurrency/lockutils.py:332
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Failed to remove file %(file)s"
|
msgid "Failed to remove file %(file)s"
|
||||||
msgstr "Échec lors de la suppression du fichier %(file)s"
|
msgstr "Échec lors de la suppression du fichier %(file)s"
|
||||||
|
|||||||
@@ -9,75 +9,17 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: oslo.concurrency\n"
|
"Project-Id-Version: oslo.concurrency\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2015-03-09 06:08+0000\n"
|
"POT-Creation-Date: 2015-05-28 06:05+0000\n"
|
||||||
"PO-Revision-Date: 2015-03-08 16:41+0000\n"
|
"PO-Revision-Date: 2015-03-08 16:41+0000\n"
|
||||||
"Last-Translator: Maxime COQUEREL <max.coquerel@gmail.com>\n"
|
"Last-Translator: Maxime COQUEREL <max.coquerel@gmail.com>\n"
|
||||||
"Language-Team: French "
|
"Language-Team: French (http://www.transifex.com/projects/p/osloconcurrency/"
|
||||||
"(http://www.transifex.com/projects/p/osloconcurrency/language/fr/)\n"
|
"language/fr/)\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 1.3\n"
|
"Generated-By: Babel 1.3\n"
|
||||||
|
|
||||||
#: oslo_concurrency/lockutils.py:111
|
|
||||||
#, python-format
|
|
||||||
msgid "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
|
||||||
msgstr ""
|
|
||||||
"Impossible d'acquérir le verrou sur `%(filename)s` à cause de "
|
|
||||||
"%(exception)s"
|
|
||||||
|
|
||||||
#: oslo_concurrency/lockutils.py:208
|
|
||||||
msgid "Unable to release an unacquired lock"
|
|
||||||
msgstr "Impossible de libérer le verrou acquis %s"
|
|
||||||
|
|
||||||
#: oslo_concurrency/lockutils.py:671
|
|
||||||
msgid ""
|
|
||||||
"Calling lockutils directly is no longer supported. Please use the "
|
|
||||||
"lockutils-wrapper console script instead."
|
|
||||||
msgstr ""
|
|
||||||
"Lockutils appelant directement n'est plus pris en charge. Merci "
|
|
||||||
"d'utiliser le script de la console lockutils -wrapper à la place."
|
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:69
|
|
||||||
msgid "Unexpected error while running command."
|
|
||||||
msgstr "Erreur inattendue lors de l’exécution de la commande."
|
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:72
|
|
||||||
#, python-format
|
|
||||||
msgid ""
|
|
||||||
"%(description)s\n"
|
|
||||||
"Command: %(cmd)s\n"
|
|
||||||
"Exit code: %(exit_code)s\n"
|
|
||||||
"Stdout: %(stdout)r\n"
|
|
||||||
"Stderr: %(stderr)r"
|
|
||||||
msgstr ""
|
|
||||||
"%(description)s\n"
|
|
||||||
"Commande: %(cmd)s\n"
|
|
||||||
"Code de sortie: %(exit_code)s\n"
|
|
||||||
"Stdout: %(stdout)r\n"
|
|
||||||
"Stderr: %(stderr)r"
|
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:174
|
|
||||||
#, python-format
|
|
||||||
msgid "Got unknown keyword args: %r"
|
|
||||||
msgstr "Ags, mot clé inconnu: %r"
|
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:177
|
|
||||||
#, python-format
|
|
||||||
msgid "Got invalid arg log_errors: %r"
|
|
||||||
msgstr "Argument reçu non valide log_errors: %r"
|
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:183
|
|
||||||
msgid "Command requested root, but did not specify a root helper."
|
|
||||||
msgstr "La commande exigeait root, mais n'indiquait pas comment obtenir root."
|
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:199
|
|
||||||
#, python-format
|
|
||||||
msgid "Running cmd (subprocess): %s"
|
|
||||||
msgstr "Exécution de la commande (sous-processus): %s"
|
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:242
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"%(desc)r\n"
|
"%(desc)r\n"
|
||||||
@@ -92,7 +34,41 @@ msgstr ""
|
|||||||
"stdout: %(stdout)r\n"
|
"stdout: %(stdout)r\n"
|
||||||
"stderr: %(stderr)r"
|
"stderr: %(stderr)r"
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:251
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"%(description)s\n"
|
||||||
|
"Command: %(cmd)s\n"
|
||||||
|
"Exit code: %(exit_code)s\n"
|
||||||
|
"Stdout: %(stdout)r\n"
|
||||||
|
"Stderr: %(stderr)r"
|
||||||
|
msgstr ""
|
||||||
|
"%(description)s\n"
|
||||||
|
"Commande: %(cmd)s\n"
|
||||||
|
"Code de sortie: %(exit_code)s\n"
|
||||||
|
"Stdout: %(stdout)r\n"
|
||||||
|
"Stderr: %(stderr)r"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "%r failed. Not Retrying."
|
||||||
|
msgstr "Echec de %r. Nouvelle tentative."
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "%r failed. Retrying."
|
||||||
|
msgstr "Echec de %r. Nouvelle tentative."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Calling lockutils directly is no longer supported. Please use the lockutils-"
|
||||||
|
"wrapper console script instead."
|
||||||
|
msgstr ""
|
||||||
|
"Lockutils appelant directement n'est plus pris en charge. Merci d'utiliser "
|
||||||
|
"le script de la console lockutils -wrapper à la place."
|
||||||
|
|
||||||
|
msgid "Command requested root, but did not specify a root helper."
|
||||||
|
msgstr "La commande exigeait root, mais n'indiquait pas comment obtenir root."
|
||||||
|
|
||||||
|
msgid "Environment not supported over SSH"
|
||||||
|
msgstr "Environnement non prise en charge sur SSH"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Got an OSError\n"
|
"Got an OSError\n"
|
||||||
@@ -103,21 +79,28 @@ msgstr ""
|
|||||||
"commande: %(cmd)r\n"
|
"commande: %(cmd)r\n"
|
||||||
"errno: %(errno)r"
|
"errno: %(errno)r"
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:257
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%r failed. Not Retrying."
|
msgid "Got invalid arg log_errors: %r"
|
||||||
msgstr "Echec de %r. Nouvelle tentative."
|
msgstr "Argument reçu non valide log_errors: %r"
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:261
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%r failed. Retrying."
|
msgid "Got unknown keyword args: %r"
|
||||||
msgstr "Echec de %r. Nouvelle tentative."
|
msgstr "Ags, mot clé inconnu: %r"
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:308
|
#, python-format
|
||||||
msgid "Environment not supported over SSH"
|
msgid "Running cmd (subprocess): %s"
|
||||||
msgstr "Environnement non prise en charge sur SSH"
|
msgstr "Exécution de la commande (sous-processus): %s"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||||
|
msgstr ""
|
||||||
|
"Impossible d'acquérir le verrou sur `%(filename)s` à cause de %(exception)s"
|
||||||
|
|
||||||
|
msgid "Unable to release an unacquired lock"
|
||||||
|
msgstr "Impossible de libérer le verrou acquis %s"
|
||||||
|
|
||||||
|
msgid "Unexpected error while running command."
|
||||||
|
msgstr "Erreur inattendue lors de l’exécution de la commande."
|
||||||
|
|
||||||
#: oslo_concurrency/processutils.py:312
|
|
||||||
msgid "process_input not supported over SSH"
|
msgid "process_input not supported over SSH"
|
||||||
msgstr "process_input non pris en charge sur SSH"
|
msgstr "process_input non pris en charge sur SSH"
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import contextlib
|
|||||||
import errno
|
import errno
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import stat
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
@@ -24,15 +25,17 @@ from oslo_utils import excutils
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
_FILE_CACHE = {}
|
_FILE_CACHE = {}
|
||||||
|
DEFAULT_MODE = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO
|
||||||
|
|
||||||
|
|
||||||
def ensure_tree(path):
|
def ensure_tree(path, mode=DEFAULT_MODE):
|
||||||
"""Create a directory (and any ancestor directories required)
|
"""Create a directory (and any ancestor directories required)
|
||||||
|
|
||||||
:param path: Directory to create
|
:param path: Directory to create
|
||||||
|
:param mode: Directory creation permissions
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
os.makedirs(path)
|
os.makedirs(path, mode)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
if exc.errno == errno.EEXIST:
|
if exc.errno == errno.EEXIST:
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
@@ -58,7 +61,7 @@ def read_cached_file(filename, force_reload=False):
|
|||||||
cache_info = _FILE_CACHE.setdefault(filename, {})
|
cache_info = _FILE_CACHE.setdefault(filename, {})
|
||||||
|
|
||||||
if not cache_info or mtime > cache_info.get('mtime', 0):
|
if not cache_info or mtime > cache_info.get('mtime', 0):
|
||||||
LOG.debug("Reloading cached file %s" % filename)
|
LOG.debug("Reloading cached file %s", filename)
|
||||||
with open(filename) as fap:
|
with open(filename) as fap:
|
||||||
cache_info['data'] = fap.read()
|
cache_info['data'] = fap.read()
|
||||||
cache_info['mtime'] = mtime
|
cache_info['mtime'] = mtime
|
||||||
|
|||||||
@@ -144,6 +144,9 @@ def execute(*cmd, **kwargs):
|
|||||||
last attempt, and LOG_ALL_ERRORS requires
|
last attempt, and LOG_ALL_ERRORS requires
|
||||||
logging on each occurence of an error.
|
logging on each occurence of an error.
|
||||||
:type log_errors: integer.
|
:type log_errors: integer.
|
||||||
|
:param binary: On Python 3, return stdout and stderr as bytes if
|
||||||
|
binary is True, as Unicode otherwise.
|
||||||
|
:type binary: boolean
|
||||||
:returns: (stdout, stderr) from process execution
|
:returns: (stdout, stderr) from process execution
|
||||||
:raises: :class:`UnknownArgumentError` on
|
:raises: :class:`UnknownArgumentError` on
|
||||||
receiving unknown arguments
|
receiving unknown arguments
|
||||||
@@ -163,6 +166,7 @@ def execute(*cmd, **kwargs):
|
|||||||
shell = kwargs.pop('shell', False)
|
shell = kwargs.pop('shell', False)
|
||||||
loglevel = kwargs.pop('loglevel', logging.DEBUG)
|
loglevel = kwargs.pop('loglevel', logging.DEBUG)
|
||||||
log_errors = kwargs.pop('log_errors', None)
|
log_errors = kwargs.pop('log_errors', None)
|
||||||
|
binary = kwargs.pop('binary', False)
|
||||||
|
|
||||||
if isinstance(check_exit_code, bool):
|
if isinstance(check_exit_code, bool):
|
||||||
ignore_exit_code = not check_exit_code
|
ignore_exit_code = not check_exit_code
|
||||||
@@ -225,13 +229,24 @@ def execute(*cmd, **kwargs):
|
|||||||
(sanitized_cmd, _returncode, end_time))
|
(sanitized_cmd, _returncode, end_time))
|
||||||
if not ignore_exit_code and _returncode not in check_exit_code:
|
if not ignore_exit_code and _returncode not in check_exit_code:
|
||||||
(stdout, stderr) = result
|
(stdout, stderr) = result
|
||||||
|
if six.PY3:
|
||||||
|
stdout = os.fsdecode(stdout)
|
||||||
|
stderr = os.fsdecode(stderr)
|
||||||
sanitized_stdout = strutils.mask_password(stdout)
|
sanitized_stdout = strutils.mask_password(stdout)
|
||||||
sanitized_stderr = strutils.mask_password(stderr)
|
sanitized_stderr = strutils.mask_password(stderr)
|
||||||
raise ProcessExecutionError(exit_code=_returncode,
|
raise ProcessExecutionError(exit_code=_returncode,
|
||||||
stdout=sanitized_stdout,
|
stdout=sanitized_stdout,
|
||||||
stderr=sanitized_stderr,
|
stderr=sanitized_stderr,
|
||||||
cmd=sanitized_cmd)
|
cmd=sanitized_cmd)
|
||||||
return result
|
if six.PY3 and not binary and result is not None:
|
||||||
|
(stdout, stderr) = result
|
||||||
|
# Decode from the locale using using the surrogateescape error
|
||||||
|
# handler (decoding cannot fail)
|
||||||
|
stdout = os.fsdecode(stdout)
|
||||||
|
stderr = os.fsdecode(stderr)
|
||||||
|
return (stdout, stderr)
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
|
||||||
except (ProcessExecutionError, OSError) as err:
|
except (ProcessExecutionError, OSError) as err:
|
||||||
# if we want to always log the errors or if this is
|
# if we want to always log the errors or if this is
|
||||||
@@ -301,7 +316,8 @@ def trycmd(*args, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
def ssh_execute(ssh, cmd, process_input=None,
|
def ssh_execute(ssh, cmd, process_input=None,
|
||||||
addl_env=None, check_exit_code=True):
|
addl_env=None, check_exit_code=True,
|
||||||
|
binary=False):
|
||||||
sanitized_cmd = strutils.mask_password(cmd)
|
sanitized_cmd = strutils.mask_password(cmd)
|
||||||
LOG.debug('Running cmd (SSH): %s', sanitized_cmd)
|
LOG.debug('Running cmd (SSH): %s', sanitized_cmd)
|
||||||
if addl_env:
|
if addl_env:
|
||||||
@@ -317,24 +333,46 @@ def ssh_execute(ssh, cmd, process_input=None,
|
|||||||
# NOTE(justinsb): This seems suspicious...
|
# NOTE(justinsb): This seems suspicious...
|
||||||
# ...other SSH clients have buffering issues with this approach
|
# ...other SSH clients have buffering issues with this approach
|
||||||
stdout = stdout_stream.read()
|
stdout = stdout_stream.read()
|
||||||
sanitized_stdout = strutils.mask_password(stdout)
|
|
||||||
stderr = stderr_stream.read()
|
stderr = stderr_stream.read()
|
||||||
sanitized_stderr = strutils.mask_password(stderr)
|
|
||||||
|
|
||||||
stdin_stream.close()
|
stdin_stream.close()
|
||||||
|
|
||||||
exit_status = channel.recv_exit_status()
|
exit_status = channel.recv_exit_status()
|
||||||
|
|
||||||
|
if six.PY3:
|
||||||
|
# Decode from the locale using using the surrogateescape error handler
|
||||||
|
# (decoding cannot fail). Decode even if binary is True because
|
||||||
|
# mask_password() requires Unicode on Python 3
|
||||||
|
stdout = os.fsdecode(stdout)
|
||||||
|
stderr = os.fsdecode(stderr)
|
||||||
|
stdout = strutils.mask_password(stdout)
|
||||||
|
stderr = strutils.mask_password(stderr)
|
||||||
|
|
||||||
# exit_status == -1 if no exit code was returned
|
# exit_status == -1 if no exit code was returned
|
||||||
if exit_status != -1:
|
if exit_status != -1:
|
||||||
LOG.debug('Result was %s' % exit_status)
|
LOG.debug('Result was %s' % exit_status)
|
||||||
if check_exit_code and exit_status != 0:
|
if check_exit_code and exit_status != 0:
|
||||||
raise ProcessExecutionError(exit_code=exit_status,
|
raise ProcessExecutionError(exit_code=exit_status,
|
||||||
stdout=sanitized_stdout,
|
stdout=stdout,
|
||||||
stderr=sanitized_stderr,
|
stderr=stderr,
|
||||||
cmd=sanitized_cmd)
|
cmd=sanitized_cmd)
|
||||||
|
|
||||||
return (sanitized_stdout, sanitized_stderr)
|
if binary:
|
||||||
|
if six.PY2:
|
||||||
|
# On Python 2, stdout is a bytes string if mask_password() failed
|
||||||
|
# to decode it, or an Unicode string otherwise. Encode to the
|
||||||
|
# default encoding (ASCII) because mask_password() decodes from
|
||||||
|
# the same encoding.
|
||||||
|
if isinstance(stdout, unicode):
|
||||||
|
stdout = stdout.encode()
|
||||||
|
if isinstance(stderr, unicode):
|
||||||
|
stderr = stderr.encode()
|
||||||
|
else:
|
||||||
|
# fsencode() is the reverse operation of fsdecode()
|
||||||
|
stdout = os.fsencode(stdout)
|
||||||
|
stderr = os.fsencode(stderr)
|
||||||
|
|
||||||
|
return (stdout, stderr)
|
||||||
|
|
||||||
|
|
||||||
def get_worker_count():
|
def get_worker_count():
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import logging
|
|||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import fixtures
|
import fixtures
|
||||||
@@ -29,6 +30,8 @@ import six
|
|||||||
|
|
||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
from oslotest import mockpatch
|
from oslotest import mockpatch
|
||||||
|
|
||||||
|
|
||||||
PROCESS_EXECUTION_ERROR_LOGGING_TEST = """#!/bin/bash
|
PROCESS_EXECUTION_ERROR_LOGGING_TEST = """#!/bin/bash
|
||||||
exit 41"""
|
exit 41"""
|
||||||
|
|
||||||
@@ -40,6 +43,9 @@ echo onstdout --password='"secret"'
|
|||||||
echo onstderr --password='"secret"' 1>&2
|
echo onstderr --password='"secret"' 1>&2
|
||||||
exit 38"""
|
exit 38"""
|
||||||
|
|
||||||
|
# This byte sequence is undecodable from most encoding
|
||||||
|
UNDECODABLE_BYTES = b'[a\x80\xe9\xff]'
|
||||||
|
|
||||||
|
|
||||||
class UtilsTest(test_base.BaseTestCase):
|
class UtilsTest(test_base.BaseTestCase):
|
||||||
# NOTE(jkoelker) Moar tests from nova need to be ported. But they
|
# NOTE(jkoelker) Moar tests from nova need to be ported. But they
|
||||||
@@ -173,7 +179,7 @@ exit 1
|
|||||||
out, err = processutils.execute('/usr/bin/env',
|
out, err = processutils.execute('/usr/bin/env',
|
||||||
'sh', '-c', 'pwd',
|
'sh', '-c', 'pwd',
|
||||||
cwd=tmpdir)
|
cwd=tmpdir)
|
||||||
self.assertIn(six.b(tmpdir), out)
|
self.assertIn(tmpdir, out)
|
||||||
|
|
||||||
def test_check_exit_code_list(self):
|
def test_check_exit_code_list(self):
|
||||||
processutils.execute('/usr/bin/env', 'sh', '-c', 'exit 101',
|
processutils.execute('/usr/bin/env', 'sh', '-c', 'exit 101',
|
||||||
@@ -301,6 +307,19 @@ grep foo
|
|||||||
env_vars = {'SUPER_UNIQUE_VAR': 'The answer is 42'}
|
env_vars = {'SUPER_UNIQUE_VAR': 'The answer is 42'}
|
||||||
|
|
||||||
out, err = processutils.execute('/usr/bin/env', env_variables=env_vars)
|
out, err = processutils.execute('/usr/bin/env', env_variables=env_vars)
|
||||||
|
self.assertIsInstance(out, str)
|
||||||
|
self.assertIsInstance(err, str)
|
||||||
|
|
||||||
|
self.assertIn('SUPER_UNIQUE_VAR=The answer is 42', out)
|
||||||
|
|
||||||
|
def test_binary(self):
|
||||||
|
env_vars = {'SUPER_UNIQUE_VAR': 'The answer is 42'}
|
||||||
|
|
||||||
|
out, err = processutils.execute('/usr/bin/env',
|
||||||
|
env_variables=env_vars,
|
||||||
|
binary=True)
|
||||||
|
self.assertIsInstance(out, bytes)
|
||||||
|
self.assertIsInstance(err, bytes)
|
||||||
|
|
||||||
self.assertIn(b'SUPER_UNIQUE_VAR=The answer is 42', out)
|
self.assertIn(b'SUPER_UNIQUE_VAR=The answer is 42', out)
|
||||||
|
|
||||||
@@ -321,6 +340,8 @@ grep foo
|
|||||||
'something')
|
'something')
|
||||||
|
|
||||||
self.assertEqual(38, err.exit_code)
|
self.assertEqual(38, err.exit_code)
|
||||||
|
self.assertIsInstance(err.stdout, six.text_type)
|
||||||
|
self.assertIsInstance(err.stderr, six.text_type)
|
||||||
self.assertIn('onstdout --password="***"', err.stdout)
|
self.assertIn('onstdout --password="***"', err.stdout)
|
||||||
self.assertIn('onstderr --password="***"', err.stderr)
|
self.assertIn('onstderr --password="***"', err.stderr)
|
||||||
self.assertEqual(err.cmd, ' '.join([tmpfilename,
|
self.assertEqual(err.cmd, ' '.join([tmpfilename,
|
||||||
@@ -328,6 +349,72 @@ grep foo
|
|||||||
'something']))
|
'something']))
|
||||||
self.assertNotIn('secret', str(err))
|
self.assertNotIn('secret', str(err))
|
||||||
|
|
||||||
|
def execute_undecodable_bytes(self, out_bytes, err_bytes,
|
||||||
|
exitcode=0, binary=False):
|
||||||
|
if six.PY3:
|
||||||
|
code = ';'.join(('import sys',
|
||||||
|
'sys.stdout.buffer.write(%a)' % out_bytes,
|
||||||
|
'sys.stdout.flush()',
|
||||||
|
'sys.stderr.buffer.write(%a)' % err_bytes,
|
||||||
|
'sys.stderr.flush()',
|
||||||
|
'sys.exit(%s)' % exitcode))
|
||||||
|
else:
|
||||||
|
code = ';'.join(('import sys',
|
||||||
|
'sys.stdout.write(%r)' % out_bytes,
|
||||||
|
'sys.stdout.flush()',
|
||||||
|
'sys.stderr.write(%r)' % err_bytes,
|
||||||
|
'sys.stderr.flush()',
|
||||||
|
'sys.exit(%s)' % exitcode))
|
||||||
|
|
||||||
|
return processutils.execute(sys.executable, '-c', code, binary=binary)
|
||||||
|
|
||||||
|
def check_undecodable_bytes(self, binary):
|
||||||
|
out_bytes = b'out: ' + UNDECODABLE_BYTES
|
||||||
|
err_bytes = b'err: ' + UNDECODABLE_BYTES
|
||||||
|
out, err = self.execute_undecodable_bytes(out_bytes, err_bytes,
|
||||||
|
binary=binary)
|
||||||
|
if six.PY3 and not binary:
|
||||||
|
self.assertEqual(out, os.fsdecode(out_bytes))
|
||||||
|
self.assertEqual(err, os.fsdecode(err_bytes))
|
||||||
|
else:
|
||||||
|
self.assertEqual(out, out_bytes)
|
||||||
|
self.assertEqual(err, err_bytes)
|
||||||
|
|
||||||
|
def test_undecodable_bytes(self):
|
||||||
|
self.check_undecodable_bytes(False)
|
||||||
|
|
||||||
|
def test_binary_undecodable_bytes(self):
|
||||||
|
self.check_undecodable_bytes(True)
|
||||||
|
|
||||||
|
def check_undecodable_bytes_error(self, binary):
|
||||||
|
out_bytes = b'out: password="secret1" ' + UNDECODABLE_BYTES
|
||||||
|
err_bytes = b'err: password="secret2" ' + UNDECODABLE_BYTES
|
||||||
|
exc = self.assertRaises(processutils.ProcessExecutionError,
|
||||||
|
self.execute_undecodable_bytes,
|
||||||
|
out_bytes, err_bytes, exitcode=1,
|
||||||
|
binary=binary)
|
||||||
|
|
||||||
|
out = exc.stdout
|
||||||
|
err = exc.stderr
|
||||||
|
out_bytes = b'out: password="***" ' + UNDECODABLE_BYTES
|
||||||
|
err_bytes = b'err: password="***" ' + UNDECODABLE_BYTES
|
||||||
|
if six.PY3:
|
||||||
|
# On Python 3, stdout and stderr attributes of
|
||||||
|
# ProcessExecutionError must always be Unicode
|
||||||
|
self.assertEqual(out, os.fsdecode(out_bytes))
|
||||||
|
self.assertEqual(err, os.fsdecode(err_bytes))
|
||||||
|
else:
|
||||||
|
# On Python 2, stdout and stderr attributes of
|
||||||
|
# ProcessExecutionError must always be bytes
|
||||||
|
self.assertEqual(out, out_bytes)
|
||||||
|
self.assertEqual(err, err_bytes)
|
||||||
|
|
||||||
|
def test_undecodable_bytes_error(self):
|
||||||
|
self.check_undecodable_bytes_error(False)
|
||||||
|
|
||||||
|
def test_binary_undecodable_bytes_error(self):
|
||||||
|
self.check_undecodable_bytes_error(True)
|
||||||
|
|
||||||
|
|
||||||
class ProcessExecutionErrorLoggingTest(test_base.BaseTestCase):
|
class ProcessExecutionErrorLoggingTest(test_base.BaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -433,21 +520,23 @@ class FakeSshChannel(object):
|
|||||||
return self.rc
|
return self.rc
|
||||||
|
|
||||||
|
|
||||||
class FakeSshStream(six.StringIO):
|
class FakeSshStream(six.BytesIO):
|
||||||
def setup_channel(self, rc):
|
def setup_channel(self, rc):
|
||||||
self.channel = FakeSshChannel(rc)
|
self.channel = FakeSshChannel(rc)
|
||||||
|
|
||||||
|
|
||||||
class FakeSshConnection(object):
|
class FakeSshConnection(object):
|
||||||
def __init__(self, rc):
|
def __init__(self, rc, out=b'stdout', err=b'stderr'):
|
||||||
self.rc = rc
|
self.rc = rc
|
||||||
|
self.out = out
|
||||||
|
self.err = err
|
||||||
|
|
||||||
def exec_command(self, cmd):
|
def exec_command(self, cmd):
|
||||||
stdout = FakeSshStream('stdout')
|
stdout = FakeSshStream(self.out)
|
||||||
stdout.setup_channel(self.rc)
|
stdout.setup_channel(self.rc)
|
||||||
return (six.StringIO(),
|
return (six.BytesIO(),
|
||||||
stdout,
|
stdout,
|
||||||
six.StringIO('stderr'))
|
six.BytesIO(self.err))
|
||||||
|
|
||||||
|
|
||||||
class SshExecuteTestCase(test_base.BaseTestCase):
|
class SshExecuteTestCase(test_base.BaseTestCase):
|
||||||
@@ -462,9 +551,70 @@ class SshExecuteTestCase(test_base.BaseTestCase):
|
|||||||
None, 'ls', process_input='important')
|
None, 'ls', process_input='important')
|
||||||
|
|
||||||
def test_works(self):
|
def test_works(self):
|
||||||
o, e = processutils.ssh_execute(FakeSshConnection(0), 'ls')
|
out, err = processutils.ssh_execute(FakeSshConnection(0), 'ls')
|
||||||
self.assertEqual('stdout', o)
|
self.assertEqual('stdout', out)
|
||||||
self.assertEqual('stderr', e)
|
self.assertEqual('stderr', err)
|
||||||
|
self.assertIsInstance(out, six.text_type)
|
||||||
|
self.assertIsInstance(err, six.text_type)
|
||||||
|
|
||||||
|
def test_binary(self):
|
||||||
|
o, e = processutils.ssh_execute(FakeSshConnection(0), 'ls',
|
||||||
|
binary=True)
|
||||||
|
self.assertEqual(b'stdout', o)
|
||||||
|
self.assertEqual(b'stderr', e)
|
||||||
|
self.assertIsInstance(o, bytes)
|
||||||
|
self.assertIsInstance(e, bytes)
|
||||||
|
|
||||||
|
def check_undecodable_bytes(self, binary):
|
||||||
|
out_bytes = b'out: ' + UNDECODABLE_BYTES
|
||||||
|
err_bytes = b'err: ' + UNDECODABLE_BYTES
|
||||||
|
conn = FakeSshConnection(0, out=out_bytes, err=err_bytes)
|
||||||
|
|
||||||
|
out, err = processutils.ssh_execute(conn, 'ls', binary=binary)
|
||||||
|
if six.PY3 and not binary:
|
||||||
|
self.assertEqual(out, os.fsdecode(out_bytes))
|
||||||
|
self.assertEqual(err, os.fsdecode(err_bytes))
|
||||||
|
else:
|
||||||
|
self.assertEqual(out, out_bytes)
|
||||||
|
self.assertEqual(err, err_bytes)
|
||||||
|
|
||||||
|
def test_undecodable_bytes(self):
|
||||||
|
self.check_undecodable_bytes(False)
|
||||||
|
|
||||||
|
def test_binary_undecodable_bytes(self):
|
||||||
|
self.check_undecodable_bytes(True)
|
||||||
|
|
||||||
|
def check_undecodable_bytes_error(self, binary):
|
||||||
|
out_bytes = b'out: password="secret1" ' + UNDECODABLE_BYTES
|
||||||
|
err_bytes = b'err: password="secret2" ' + UNDECODABLE_BYTES
|
||||||
|
conn = FakeSshConnection(1, out=out_bytes, err=err_bytes)
|
||||||
|
|
||||||
|
out_bytes = b'out: password="***" ' + UNDECODABLE_BYTES
|
||||||
|
err_bytes = b'err: password="***" ' + UNDECODABLE_BYTES
|
||||||
|
|
||||||
|
exc = self.assertRaises(processutils.ProcessExecutionError,
|
||||||
|
processutils.ssh_execute,
|
||||||
|
conn, 'ls',
|
||||||
|
binary=binary, check_exit_code=True)
|
||||||
|
|
||||||
|
out = exc.stdout
|
||||||
|
err = exc.stderr
|
||||||
|
if six.PY3:
|
||||||
|
# On Python 3, stdout and stderr attributes of
|
||||||
|
# ProcessExecutionError must always be Unicode
|
||||||
|
self.assertEqual(out, os.fsdecode(out_bytes))
|
||||||
|
self.assertEqual(err, os.fsdecode(err_bytes))
|
||||||
|
else:
|
||||||
|
# On Python 2, stdout and stderr attributes of
|
||||||
|
# ProcessExecutionError must always be bytes
|
||||||
|
self.assertEqual(out, out_bytes)
|
||||||
|
self.assertEqual(err, err_bytes)
|
||||||
|
|
||||||
|
def test_undecodable_bytes_error(self):
|
||||||
|
self.check_undecodable_bytes_error(False)
|
||||||
|
|
||||||
|
def test_binary_undecodable_bytes_error(self):
|
||||||
|
self.check_undecodable_bytes_error(True)
|
||||||
|
|
||||||
def test_fails(self):
|
def test_fails(self):
|
||||||
self.assertRaises(processutils.ProcessExecutionError,
|
self.assertRaises(processutils.ProcessExecutionError,
|
||||||
@@ -472,13 +622,13 @@ class SshExecuteTestCase(test_base.BaseTestCase):
|
|||||||
|
|
||||||
def _test_compromising_ssh(self, rc, check):
|
def _test_compromising_ssh(self, rc, check):
|
||||||
fixture = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG))
|
fixture = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG))
|
||||||
fake_stdin = six.StringIO()
|
fake_stdin = six.BytesIO()
|
||||||
|
|
||||||
fake_stdout = mock.Mock()
|
fake_stdout = mock.Mock()
|
||||||
fake_stdout.channel.recv_exit_status.return_value = rc
|
fake_stdout.channel.recv_exit_status.return_value = rc
|
||||||
fake_stdout.read.return_value = 'password="secret"'
|
fake_stdout.read.return_value = b'password="secret"'
|
||||||
|
|
||||||
fake_stderr = six.StringIO('password="foobar"')
|
fake_stderr = six.BytesIO(b'password="foobar"')
|
||||||
|
|
||||||
command = 'ls --password="bar"'
|
command = 'ls --password="bar"'
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
# of appearance. Changing the order has an impact on the overall integration
|
# of appearance. Changing the order has an impact on the overall integration
|
||||||
# process, which may cause wedges in the gate later.
|
# process, which may cause wedges in the gate later.
|
||||||
|
|
||||||
pbr>=0.6,!=0.7,<1.0
|
pbr>=0.11,<2.0
|
||||||
Babel>=1.3
|
Babel>=1.3
|
||||||
iso8601>=0.1.9
|
iso8601>=0.1.9
|
||||||
fixtures>=0.3.14
|
oslo.config>=1.11.0 # Apache-2.0
|
||||||
oslo.config>=1.9.0 # Apache-2.0
|
oslo.i18n>=1.5.0 # Apache-2.0
|
||||||
oslo.i18n>=1.3.0 # Apache-2.0
|
oslo.utils>=1.4.0 # Apache-2.0
|
||||||
oslo.utils>=1.2.0 # Apache-2.0
|
|
||||||
posix_ipc
|
posix_ipc
|
||||||
six>=1.9.0
|
six>=1.9.0
|
||||||
retrying>=1.2.3,!=1.3.0 # Apache-2.0
|
retrying>=1.2.3,!=1.3.0 # Apache-2.0
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = oslo.concurrency
|
name = oslo.concurrency
|
||||||
summary = oslo.concurrency library
|
summary = Oslo Concurrency library
|
||||||
description-file =
|
description-file =
|
||||||
README.rst
|
README.rst
|
||||||
author = OpenStack
|
author = OpenStack
|
||||||
@@ -17,7 +17,7 @@ classifier =
|
|||||||
Programming Language :: Python :: 2.7
|
Programming Language :: Python :: 2.7
|
||||||
Programming Language :: Python :: 2.6
|
Programming Language :: Python :: 2.6
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
Programming Language :: Python :: 3.3
|
Programming Language :: Python :: 3.4
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
packages =
|
packages =
|
||||||
|
|||||||
@@ -3,12 +3,13 @@
|
|||||||
# process, which may cause wedges in the gate later.
|
# process, which may cause wedges in the gate later.
|
||||||
|
|
||||||
hacking>=0.10.0,<0.11
|
hacking>=0.10.0,<0.11
|
||||||
oslotest>=1.2.0 # Apache-2.0
|
oslotest>=1.5.1 # Apache-2.0
|
||||||
coverage>=3.6
|
coverage>=3.6
|
||||||
futures>=2.1.6
|
futures>=3.0
|
||||||
|
fixtures>=0.3.14
|
||||||
|
|
||||||
# These are needed for docs generation
|
# These are needed for docs generation
|
||||||
oslosphinx>=2.2.0 # Apache-2.0
|
oslosphinx>=2.5.0 # Apache-2.0
|
||||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
||||||
|
|
||||||
eventlet>=0.16.1
|
eventlet>=0.17.3
|
||||||
|
|||||||
@@ -295,17 +295,22 @@ grep foo
|
|||||||
env_vars = {'SUPER_UNIQUE_VAR': 'The answer is 42'}
|
env_vars = {'SUPER_UNIQUE_VAR': 'The answer is 42'}
|
||||||
|
|
||||||
out, err = processutils.execute('/usr/bin/env', env_variables=env_vars)
|
out, err = processutils.execute('/usr/bin/env', env_variables=env_vars)
|
||||||
|
self.assertEqual(type(out), str)
|
||||||
|
self.assertEqual(type(err), str)
|
||||||
|
|
||||||
self.assertIn(b'SUPER_UNIQUE_VAR=The answer is 42', out)
|
self.assertIn('SUPER_UNIQUE_VAR=The answer is 42', out)
|
||||||
|
|
||||||
def test_as_root(self):
|
def test_as_root(self):
|
||||||
out, err = processutils.execute('a', 'b', 'c', run_as_root=True,
|
# For the following two tests: processutils.execute() does not
|
||||||
root_helper='echo')
|
# prepend the root_helper if we are already running with root privs,
|
||||||
|
# so add it as the first argument to be certain.
|
||||||
|
out, err = processutils.execute('echo', 'a', 'b', 'c',
|
||||||
|
run_as_root=True, root_helper='echo')
|
||||||
|
|
||||||
self.assertIn('a b c', six.text_type(out))
|
self.assertIn('a b c', six.text_type(out))
|
||||||
|
|
||||||
def test_as_root_via_shell(self):
|
def test_as_root_via_shell(self):
|
||||||
out, err = processutils.execute('a b c', run_as_root=True,
|
out, err = processutils.execute('echo a b c', run_as_root=True,
|
||||||
root_helper='echo', shell=True)
|
root_helper='echo', shell=True)
|
||||||
|
|
||||||
self.assertIn('a b c', six.text_type(out))
|
self.assertIn('a b c', six.text_type(out))
|
||||||
@@ -327,6 +332,8 @@ grep foo
|
|||||||
'something')
|
'something')
|
||||||
|
|
||||||
self.assertEqual(38, err.exit_code)
|
self.assertEqual(38, err.exit_code)
|
||||||
|
self.assertEqual(type(err.stdout), six.text_type)
|
||||||
|
self.assertEqual(type(err.stderr), six.text_type)
|
||||||
self.assertIn('onstdout --password="***"', err.stdout)
|
self.assertIn('onstdout --password="***"', err.stdout)
|
||||||
self.assertIn('onstderr --password="***"', err.stderr)
|
self.assertIn('onstderr --password="***"', err.stderr)
|
||||||
self.assertEqual(err.cmd, ' '.join([tmpfilename,
|
self.assertEqual(err.cmd, ' '.join([tmpfilename,
|
||||||
@@ -439,7 +446,7 @@ class FakeSshChannel(object):
|
|||||||
return self.rc
|
return self.rc
|
||||||
|
|
||||||
|
|
||||||
class FakeSshStream(six.StringIO):
|
class FakeSshStream(six.BytesIO):
|
||||||
def setup_channel(self, rc):
|
def setup_channel(self, rc):
|
||||||
self.channel = FakeSshChannel(rc)
|
self.channel = FakeSshChannel(rc)
|
||||||
|
|
||||||
@@ -449,11 +456,11 @@ class FakeSshConnection(object):
|
|||||||
self.rc = rc
|
self.rc = rc
|
||||||
|
|
||||||
def exec_command(self, cmd):
|
def exec_command(self, cmd):
|
||||||
stdout = FakeSshStream('stdout')
|
stdout = FakeSshStream(b'stdout')
|
||||||
stdout.setup_channel(self.rc)
|
stdout.setup_channel(self.rc)
|
||||||
return (six.StringIO(),
|
return (six.BytesIO(),
|
||||||
stdout,
|
stdout,
|
||||||
six.StringIO('stderr'))
|
six.BytesIO(b'stderr'))
|
||||||
|
|
||||||
|
|
||||||
class SshExecuteTestCase(test_base.BaseTestCase):
|
class SshExecuteTestCase(test_base.BaseTestCase):
|
||||||
@@ -471,6 +478,8 @@ class SshExecuteTestCase(test_base.BaseTestCase):
|
|||||||
o, e = processutils.ssh_execute(FakeSshConnection(0), 'ls')
|
o, e = processutils.ssh_execute(FakeSshConnection(0), 'ls')
|
||||||
self.assertEqual('stdout', o)
|
self.assertEqual('stdout', o)
|
||||||
self.assertEqual('stderr', e)
|
self.assertEqual('stderr', e)
|
||||||
|
self.assertEqual(type(o), six.text_type)
|
||||||
|
self.assertEqual(type(e), six.text_type)
|
||||||
|
|
||||||
def test_fails(self):
|
def test_fails(self):
|
||||||
self.assertRaises(processutils.ProcessExecutionError,
|
self.assertRaises(processutils.ProcessExecutionError,
|
||||||
@@ -478,13 +487,13 @@ class SshExecuteTestCase(test_base.BaseTestCase):
|
|||||||
|
|
||||||
def _test_compromising_ssh(self, rc, check):
|
def _test_compromising_ssh(self, rc, check):
|
||||||
fixture = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG))
|
fixture = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG))
|
||||||
fake_stdin = six.StringIO()
|
fake_stdin = six.BytesIO()
|
||||||
|
|
||||||
fake_stdout = mock.Mock()
|
fake_stdout = mock.Mock()
|
||||||
fake_stdout.channel.recv_exit_status.return_value = rc
|
fake_stdout.channel.recv_exit_status.return_value = rc
|
||||||
fake_stdout.read.return_value = 'password="secret"'
|
fake_stdout.read.return_value = b'password="secret"'
|
||||||
|
|
||||||
fake_stderr = six.StringIO('password="foobar"')
|
fake_stderr = six.BytesIO(b'password="foobar"')
|
||||||
|
|
||||||
command = 'ls --password="bar"'
|
command = 'ls --password="bar"'
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Run cross-project tests
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
#
|
|
||||||
# run_cross_tests.sh project_dir venv
|
|
||||||
|
|
||||||
# Fail the build if any command fails
|
|
||||||
set -e
|
|
||||||
|
|
||||||
project_dir="$1"
|
|
||||||
venv="$2"
|
|
||||||
|
|
||||||
if [ -z "$project_dir" -o -z "$venv" ]
|
|
||||||
then
|
|
||||||
cat - <<EOF
|
|
||||||
ERROR: Missing argument(s)
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
$0 PROJECT_DIR VIRTUAL_ENV
|
|
||||||
|
|
||||||
Example, run the python 2.7 tests for python-neutronclient:
|
|
||||||
|
|
||||||
$0 /opt/stack/python-neutronclient py27
|
|
||||||
|
|
||||||
EOF
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set up the virtualenv without running the tests
|
|
||||||
(cd $project_dir && tox --notest -e $venv)
|
|
||||||
|
|
||||||
tox_envbin=$project_dir/.tox/$venv/bin
|
|
||||||
|
|
||||||
our_name=$(python setup.py --name)
|
|
||||||
|
|
||||||
# Replace the pip-installed package with the version in our source
|
|
||||||
# tree. Look to see if we are already installed before trying to
|
|
||||||
# uninstall ourselves, to avoid failures from packages that do not use us
|
|
||||||
# yet.
|
|
||||||
if $tox_envbin/pip freeze | grep -q $our_name
|
|
||||||
then
|
|
||||||
$tox_envbin/pip uninstall -y $our_name
|
|
||||||
fi
|
|
||||||
$tox_envbin/pip install -U .
|
|
||||||
|
|
||||||
# Run the tests
|
|
||||||
(cd $project_dir && tox -e $venv)
|
|
||||||
result=$?
|
|
||||||
|
|
||||||
|
|
||||||
# The below checks are modified from
|
|
||||||
# openstack-infra/config/modules/jenkins/files/slave_scripts/run-unittests.sh.
|
|
||||||
|
|
||||||
# They expect to be run in the project being tested.
|
|
||||||
cd $project_dir
|
|
||||||
|
|
||||||
echo "Begin pip freeze output from test virtualenv:"
|
|
||||||
echo "======================================================================"
|
|
||||||
.tox/$venv/bin/pip freeze
|
|
||||||
echo "======================================================================"
|
|
||||||
|
|
||||||
# We only want to run the next check if the tool is installed, so look
|
|
||||||
# for it before continuing.
|
|
||||||
if [ -f /usr/local/jenkins/slave_scripts/subunit2html.py -a -d ".testrepository" ] ; then
|
|
||||||
if [ -f ".testrepository/0.2" ] ; then
|
|
||||||
cp .testrepository/0.2 ./subunit_log.txt
|
|
||||||
elif [ -f ".testrepository/0" ] ; then
|
|
||||||
.tox/$venv/bin/subunit-1to2 < .testrepository/0 > ./subunit_log.txt
|
|
||||||
fi
|
|
||||||
.tox/$venv/bin/python /usr/local/jenkins/slave_scripts/subunit2html.py ./subunit_log.txt testr_results.html
|
|
||||||
gzip -9 ./subunit_log.txt
|
|
||||||
gzip -9 ./testr_results.html
|
|
||||||
|
|
||||||
export PYTHON=.tox/$venv/bin/python
|
|
||||||
set -e
|
|
||||||
rancount=$(.tox/$venv/bin/testr last | sed -ne 's/Ran \([0-9]\+\).*tests in.*/\1/p')
|
|
||||||
if [ "$rancount" -eq "0" ] ; then
|
|
||||||
echo
|
|
||||||
echo "Zero tests were run. At least one test should have been run."
|
|
||||||
echo "Failing this test as a result"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If we make it this far, report status based on the tests that were
|
|
||||||
# run.
|
|
||||||
exit $result
|
|
||||||
4
tox.ini
4
tox.ini
@@ -19,10 +19,6 @@ commands =
|
|||||||
lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
||||||
env TEST_EVENTLET=1 lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
env TEST_EVENTLET=1 lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
||||||
|
|
||||||
[testenv:py33]
|
|
||||||
commands =
|
|
||||||
lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
|
||||||
|
|
||||||
[testenv:py34]
|
[testenv:py34]
|
||||||
commands =
|
commands =
|
||||||
lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
||||||
|
|||||||
Reference in New Issue
Block a user