diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index c13db97..0000000 --- a/.coveragerc +++ /dev/null @@ -1,7 +0,0 @@ -[run] -branch = True -source = privsep -omit = privsep/tests/*,privsep/openstack/* - -[report] -ignore-errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index f79eca1..0000000 --- a/.gitignore +++ /dev/null @@ -1,56 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg -*.egg-info -dist -build -eggs -/.eggs/ -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -.tox -nosetests.xml -.testrepository - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog - -# Editors -*~ -.*.swp - -# reno build -releasenotes/build -/doc/source/reference/api/ diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 6787749..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/oslo.privsep.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 516ae6f..0000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 9b22871..0000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover -t ./ ./oslo_privsep $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 5477886..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,17 +0,0 @@ -If you would like to contribute to the development of OpenStack, you must -follow the steps in this page: - - http://docs.openstack.org/infra/manual/developers.html - -If you already have a good understanding of how the system works and your -OpenStack accounts are set up, you can skip to the development workflow -section of this documentation to learn how changes to OpenStack should be -submitted for review via the Gerrit tool: - - http://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/oslo.privsep diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 9ab9670..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -oslo.privsep Style Commandments -====================================================== - -Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a..0000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - diff --git a/README b/README new file mode 100644 index 0000000..8fcd2b2 --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +For ongoing work on maintaining OpenStack packages in the Debian +distribution, please see the Debian OpenStack packaging team at +https://wiki.debian.org/OpenStack/. + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/README.rst b/README.rst deleted file mode 100644 index 265225d..0000000 --- a/README.rst +++ /dev/null @@ -1,38 +0,0 @@ -======================== -Team and repository tags -======================== - -.. image:: http://governance.openstack.org/badges/oslo.privsep.svg - :target: http://governance.openstack.org/reference/tags/index.html - -.. Change things from this point on - -============ -oslo.privsep -============ - -.. image:: https://img.shields.io/pypi/v/oslo.privsep.svg - :target: https://pypi.python.org/pypi/oslo.privsep/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/oslo.privsep.svg - :target: https://pypi.python.org/pypi/oslo.privsep/ - :alt: Downloads - -OpenStack library for privilege separation - -This library helps applications perform actions which require more or -less privileges than they were started with in a safe, easy to code -and easy to use manner. For more information on why this is generally -a good idea please read over the `principle of least privilege`_ and -the `specification`_ which created this library. - -* Free software: Apache license -* Documentation: https://docs.openstack.org/oslo.privsep/latest/ -* Source: https://git.openstack.org/cgit/openstack/oslo.privsep -* Bugs: https://bugs.launchpad.net/oslo.privsep - -.. _principle of least privilege: https://en.wikipedia.org/wiki/\ - Principle_of_least_privilege -.. _specification: https://specs.openstack.org/openstack/\ - oslo-specs/specs/liberty/privsep.html diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index 15cd6cb..0000000 --- a/babel.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[python: **.py] - diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index d2ab198..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - #'sphinx.ext.intersphinx', - 'openstackdocstheme' -] - -# openstackdocstheme options -repository_name = 'openstack/oslo.privsep' -bug_project = 'oslo.privsep' -bug_tag = '' -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'oslo.privsep' -copyright = u'2014, OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -html_theme = 'openstackdocs' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/contributor/contributing.rst b/doc/source/contributor/contributing.rst deleted file mode 100644 index ed5290b..0000000 --- a/doc/source/contributor/contributing.rst +++ /dev/null @@ -1,5 +0,0 @@ -============== - Contributing -============== - -.. include:: ../../../CONTRIBUTING.rst diff --git a/doc/source/contributor/history.rst b/doc/source/contributor/history.rst deleted file mode 100644 index f69be70..0000000 --- a/doc/source/contributor/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../../ChangeLog diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst deleted file mode 100644 index 7a81b77..0000000 --- a/doc/source/contributor/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -=================== - Contributor Guide -=================== - -.. toctree:: - :maxdepth: 2 - - contributing - history diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index e152772..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -============== - oslo.privsep -============== - -OpenStack library for privilege separation - -Contents -======== - -.. toctree:: - :maxdepth: 2 - - install/index - user/index - contributor/index - reference/index - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/install/index.rst b/doc/source/install/index.rst deleted file mode 100644 index 4bb4dbe..0000000 --- a/doc/source/install/index.rst +++ /dev/null @@ -1,7 +0,0 @@ -============== - Installation -============== - -At the command line:: - - $ pip install oslo.privsep diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst deleted file mode 100644 index 7247d67..0000000 --- a/doc/source/reference/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -===== - API -===== - -.. toctree:: - :maxdepth: 2 - - api/autoindex diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst deleted file mode 100644 index b0d166e..0000000 --- a/doc/source/user/index.rst +++ /dev/null @@ -1,7 +0,0 @@ -======= - Usage -======= - -To use oslo.privsep in a project:: - - import oslo_privsep diff --git a/oslo_privsep/__init__.py b/oslo_privsep/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_privsep/_i18n.py b/oslo_privsep/_i18n.py deleted file mode 100644 index 2c14c85..0000000 --- a/oslo_privsep/_i18n.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""oslo.i18n integration module. - -See https://docs.openstack.org/oslo.i18n/latest/user/index.html - -""" - -import oslo_i18n - - -_translators = oslo_i18n.TranslatorFactory(domain='oslo_privsep') - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# The contextual translation function using the name "_C" -_C = _translators.contextual_form - -# The plural translation function using the name "_P" -_P = _translators.plural_form diff --git a/oslo_privsep/capabilities.py b/oslo_privsep/capabilities.py deleted file mode 100644 index 9a97b42..0000000 --- a/oslo_privsep/capabilities.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2015 Rackspace Hosting -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import platform - -import cffi - -# Expand as necessary -CAP_CHOWN = 0 -CAP_DAC_OVERRIDE = 1 -CAP_FOWNER = 3 -CAP_KILL = 5 -CAP_SETPCAP = 8 -CAP_NET_BIND_SERVICE = 10 -CAP_NET_BROADCAST = 11 -CAP_NET_ADMIN = 12 -CAP_NET_RAW = 13 -CAP_SYS_ADMIN = 21 - -# Convenience dicts for human readable values -CAPS_BYNAME = {} -CAPS_BYVALUE = {} -for k, v in globals().copy().items(): - if k.startswith('CAP_'): - CAPS_BYNAME[k] = v - CAPS_BYVALUE[v] = k - -CDEF = ''' -/* Edited highlights from `echo '#include ' | gcc -E -` */ - -#define _LINUX_CAPABILITY_VERSION_2 0x20071026 -#define _LINUX_CAPABILITY_U32S_2 2 - -typedef unsigned int __u32; - -typedef struct __user_cap_header_struct { - __u32 version; - int pid; -} *cap_user_header_t; - -typedef struct __user_cap_data_struct { - __u32 effective; - __u32 permitted; - __u32 inheritable; -} *cap_user_data_t; - -int capset(cap_user_header_t header, const cap_user_data_t data); -int capget(cap_user_header_t header, cap_user_data_t data); - - -/* Edited highlights from `echo '#include ' | gcc -E -` */ - -#define PR_GET_KEEPCAPS 7 -#define PR_SET_KEEPCAPS 8 - -int prctl (int __option, ...); -''' - -ffi = cffi.FFI() -crt = ffi.dlopen(None) -ffi.cdef(CDEF) - - -if platform.system() == 'Linux': - # mock.patching crt.* directly seems to upset cffi. Use an - # indirection point here for easier testing. - _prctl = crt.prctl - _capget = crt.capget - _capset = crt.capset -else: - _prctl = None - _capget = None - _capset = None - - -def set_keepcaps(enable): - """Set/unset thread's "keep capabilities" flag - see prctl(2)""" - ret = _prctl(crt.PR_SET_KEEPCAPS, - ffi.cast('unsigned long', bool(enable))) - if ret != 0: - errno = ffi.errno - raise OSError(errno, os.strerror(errno)) - - -def drop_all_caps_except(effective, permitted, inheritable): - """Set (effective, permitted, inheritable) to provided list of caps""" - eff = _caps_to_mask(effective) - prm = _caps_to_mask(permitted) - inh = _caps_to_mask(inheritable) - - header = ffi.new('cap_user_header_t', - {'version': crt._LINUX_CAPABILITY_VERSION_2, - 'pid': 0}) - data = ffi.new('struct __user_cap_data_struct[2]') - data[0].effective = eff & 0xffffffff - data[1].effective = eff >> 32 - data[0].permitted = prm & 0xffffffff - data[1].permitted = prm >> 32 - data[0].inheritable = inh & 0xffffffff - data[1].inheritable = inh >> 32 - - ret = _capset(header, data) - if ret != 0: - errno = ffi.errno - raise OSError(errno, os.strerror(errno)) - - -def _mask_to_caps(mask): - """Convert bitmask to list of set bit offsets""" - return [i for i in range(64) if (1 << i) & mask] - - -def _caps_to_mask(caps): - """Convert list of bit offsets to bitmask""" - mask = 0 - for cap in caps: - mask |= 1 << cap - return mask - - -def get_caps(): - """Return (effective, permitted, inheritable) as lists of caps""" - header = ffi.new('cap_user_header_t', - {'version': crt._LINUX_CAPABILITY_VERSION_2, - 'pid': 0}) - data = ffi.new('struct __user_cap_data_struct[2]') - ret = _capget(header, data) - if ret != 0: - errno = ffi.errno - raise OSError(errno, os.strerror(errno)) - - return ( - _mask_to_caps(data[0].effective | - (data[1].effective << 32)), - _mask_to_caps(data[0].permitted | - (data[1].permitted << 32)), - _mask_to_caps(data[0].inheritable | - (data[1].inheritable << 32)), - ) diff --git a/oslo_privsep/comm.py b/oslo_privsep/comm.py deleted file mode 100644 index e3e7d9e..0000000 --- a/oslo_privsep/comm.py +++ /dev/null @@ -1,193 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Serialization/Deserialization for privsep. - -The wire format is a stream of msgpack objects encoding primitive -python datatypes. Msgpack 'raw' is assumed to be a valid utf8 string -(msgpack 2.0 'bin' type is used for bytes). Python lists are -converted to tuples during serialization/deserialization. -""" - -import logging -import socket -import threading - -import msgpack -import six - -from oslo_privsep._i18n import _ - - -LOG = logging.getLogger(__name__) - - -try: - import greenlet - - def _get_thread_ident(): - # This returns something sensible, even if the current thread - # isn't a greenthread - return id(greenlet.getcurrent()) - -except ImportError: - def _get_thread_ident(): - return threading.current_thread().ident - - -class Serializer(object): - def __init__(self, writesock): - self.writesock = writesock - - def send(self, msg): - buf = msgpack.packb(msg, use_bin_type=True) - self.writesock.sendall(buf) - - def close(self): - # Hilarious. `socket._socketobject.close()` doesn't actually - # call `self._sock.close()`. Oh well, we really wanted a half - # close anyway. - self.writesock.shutdown(socket.SHUT_WR) - - -class Deserializer(six.Iterator): - def __init__(self, readsock): - self.readsock = readsock - self.unpacker = msgpack.Unpacker(use_list=False, encoding='utf-8') - - def __iter__(self): - return self - - def __next__(self): - while True: - try: - return next(self.unpacker) - except StopIteration: - try: - buf = self.readsock.recv(4096) - if not buf: - raise - self.unpacker.feed(buf) - except socket.timeout: - pass - - -class Future(object): - """A very simple object to track the return of a function call""" - - def __init__(self, lock): - self.condvar = threading.Condition(lock) - self.error = None - self.data = None - - def set_result(self, data): - """Must already be holding lock used in constructor""" - self.data = data - self.condvar.notify() - - def set_exception(self, exc): - """Must already be holding lock used in constructor""" - self.error = exc - self.condvar.notify() - - def result(self): - """Must already be holding lock used in constructor""" - self.condvar.wait() - if self.error is not None: - raise self.error - return self.data - - -class ClientChannel(object): - def __init__(self, sock): - self.writer = Serializer(sock) - self.lock = threading.Lock() - self.reader_thread = threading.Thread( - name='privsep_reader', - target=self._reader_main, - args=(Deserializer(sock),), - ) - self.reader_thread.daemon = True - self.outstanding_msgs = {} - - self.reader_thread.start() - - def _reader_main(self, reader): - """This thread owns and demuxes the read channel""" - for msg in reader: - msgid, data = msg - if msgid is None: - self.out_of_band(data) - else: - with self.lock: - assert msgid in self.outstanding_msgs - self.outstanding_msgs[msgid].set_result(data) - - # EOF. Perhaps the privileged process exited? - # Send an IOError to any oustanding waiting readers. Assuming - # the write direction is also closed, any new writes should - # get an immediate similar error. - LOG.debug('EOF on privsep read channel') - - exc = IOError(_('Premature eof waiting for privileged process')) - with self.lock: - for mbox in self.outstanding_msgs.values(): - mbox.set_exception(exc) - - def out_of_band(self, msg): - """Received OOB message. Subclasses might want to override this.""" - pass - - def send_recv(self, msg): - myid = _get_thread_ident() - future = Future(self.lock) - - with self.lock: - assert myid not in self.outstanding_msgs - self.outstanding_msgs[myid] = future - try: - self.writer.send((myid, msg)) - - reply = future.result() - finally: - del self.outstanding_msgs[myid] - - return reply - - def close(self): - with self.lock: - self.writer.close() - - self.reader_thread.join() - - -class ServerChannel(six.Iterator): - """Server-side twin to ClientChannel""" - - def __init__(self, sock): - self.rlock = threading.Lock() - self.reader_iter = iter(Deserializer(sock)) - self.wlock = threading.Lock() - self.writer = Serializer(sock) - - def __iter__(self): - return self - - def __next__(self): - with self.rlock: - return next(self.reader_iter) - - def send(self, msg): - with self.wlock: - self.writer.send(msg) diff --git a/oslo_privsep/daemon.py b/oslo_privsep/daemon.py deleted file mode 100644 index 38e7cb9..0000000 --- a/oslo_privsep/daemon.py +++ /dev/null @@ -1,518 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -'''Privilege separation ("privsep") daemon. - -To ease transition this supports 2 alternative methods of starting the -daemon, all resulting in a helper process running with elevated -privileges and open socket(s) to the original process: - -1. Start via fork() - - Assumes process currently has all required privileges and is about - to drop them (perhaps by setuid to an unprivileged user). If the - the initial environment is secure and `PrivContext.start(Method.FORK)` - is called early in `main()`, then this is the most secure and - simplest. In particular, if the initial process is already running - as non-root (but with sufficient capabilities, via eg suitable - systemd service files), then no part needs to involve uid=0 or - sudo. - -2. Start via sudo/rootwrap - - This starts the privsep helper on first use via sudo and rootwrap, - and communicates via a temporary Unix socket passed on the command - line. The communication channel is briefly exposed in the - filesystem, but is protected with file permissions and connecting - to it only grants access to the unprivileged process. Requires a - suitable entry in sudoers or rootwrap.conf filters. - -The privsep daemon exits when the communication channel is closed, -(which usually occurs when the unprivileged process exits). - -''' - -import enum -import errno -import io -import logging as pylogging -import os -import platform -import socket -import subprocess -import sys -import tempfile -import threading - -if platform.system() == 'Linux': - import fcntl - import grp - import pwd - -import eventlet -from oslo_config import cfg -from oslo_log import log as logging -from oslo_utils import importutils - -from oslo_privsep._i18n import _ -from oslo_privsep import capabilities -from oslo_privsep import comm - - -LOG = logging.getLogger(__name__) - - -@enum.unique -class StdioFd(enum.IntEnum): - # NOTE(gus): We can't use sys.std*.fileno() here. sys.std* - # objects may be random file-like objects that may not match the - # true system std* fds - and indeed may not even have a file - # descriptor at all (eg: test fixtures that monkey patch - # fixtures.StringStream onto sys.stdout). Below we always want - # the _real_ well-known 0,1,2 Unix fds during os.dup2 - # manipulation. - STDIN = 0 - STDOUT = 1 - STDERR = 2 - - -@enum.unique -class Message(enum.IntEnum): - """Types of messages sent across the communication channel""" - PING = 1 - PONG = 2 - CALL = 3 - RET = 4 - ERR = 5 - LOG = 6 - - -class FailedToDropPrivileges(Exception): - pass - - -class ProtocolError(Exception): - pass - - -def set_cloexec(fd): - flags = fcntl.fcntl(fd, fcntl.F_GETFD) - if (flags & fcntl.FD_CLOEXEC) == 0: - flags |= fcntl.FD_CLOEXEC - fcntl.fcntl(fd, fcntl.F_SETFD, flags) - - -def setuid(user_id_or_name): - try: - new_uid = int(user_id_or_name) - except (TypeError, ValueError): - new_uid = pwd.getpwnam(user_id_or_name).pw_uid - if new_uid != 0: - try: - os.setuid(new_uid) - except OSError: - msg = _('Failed to set uid %s') % new_uid - LOG.critical(msg) - raise FailedToDropPrivileges(msg) - - -def setgid(group_id_or_name): - try: - new_gid = int(group_id_or_name) - except (TypeError, ValueError): - new_gid = grp.getgrnam(group_id_or_name).gr_gid - if new_gid != 0: - try: - os.setgid(new_gid) - except OSError: - msg = _('Failed to set gid %s') % new_gid - LOG.critical(msg) - raise FailedToDropPrivileges(msg) - - -class PrivsepLogHandler(pylogging.Handler): - def __init__(self, channel, processName=None): - super(PrivsepLogHandler, self).__init__() - self.channel = channel - self.processName = processName - - def emit(self, record): - # Vaguely based on pylogging.handlers.SocketHandler.makePickle - - if self.processName: - record.processName = self.processName - - data = dict(record.__dict__) - - if record.exc_info: - if not record.exc_text: - fmt = self.formatter or pylogging.Formatter() - data['exc_text'] = fmt.formatException(record.exc_info) - data['exc_info'] = None # drop traceback in favor of exc_text - - # serialise msg now so we can drop (potentially unserialisable) args - data['msg'] = record.getMessage() - data['args'] = () - - self.channel.send((None, (Message.LOG, data))) - - -class _ClientChannel(comm.ClientChannel): - """Our protocol, layered on the basic primitives in comm.ClientChannel""" - - def __init__(self, sock): - super(_ClientChannel, self).__init__(sock) - self.exchange_ping() - - def exchange_ping(self): - try: - # exchange "ready" messages - reply = self.send_recv((Message.PING.value,)) - success = reply[0] == Message.PONG - except Exception as e: - LOG.exception('Error while sending initial PING to privsep: %s', e) - success = False - if not success: - msg = _('Privsep daemon failed to start') - LOG.critical(msg) - raise FailedToDropPrivileges(msg) - - def remote_call(self, name, args, kwargs): - result = self.send_recv((Message.CALL.value, name, args, kwargs)) - if result[0] == Message.RET: - # (RET, return value) - return result[1] - elif result[0] == Message.ERR: - # (ERR, exc_type, args) - # - # TODO(gus): see what can be done to preserve traceback - # (without leaking local values) - exc_type = importutils.import_class(result[1]) - raise exc_type(*result[2]) - else: - raise ProtocolError(_('Unexpected response: %r') % result) - - def out_of_band(self, msg): - if msg[0] == Message.LOG: - # (LOG, LogRecord __dict__) - record = pylogging.makeLogRecord(msg[1]) - if LOG.isEnabledFor(record.levelno): - LOG.logger.handle(record) - else: - LOG.warning('Ignoring unexpected OOB message from privileged ' - 'process: %r', msg) - - -def fdopen(fd, *args, **kwargs): - # NOTE(gus): We can't just use os.fdopen() here and allow the - # regular (optional) monkey_patching to do its thing. Turns out - # that regular file objects (as returned by os.fdopen) on python2 - # are broken in lots of ways regarding blocking behaviour. We - # *need* the newer io.* objects on py2 (doesn't matter on py3, - # since the old file code has been replaced with io.*) - if eventlet.patcher.is_monkey_patched('socket'): - return eventlet.greenio.GreenPipe(fd, *args, **kwargs) - else: - return io.open(fd, *args, **kwargs) - - -def _fd_logger(level=logging.WARN): - """Helper that returns a file object that is asynchronously logged""" - read_fd, write_fd = os.pipe() - read_end = fdopen(read_fd, 'r', 1) - write_end = fdopen(write_fd, 'w', 1) - - def logger(f): - for line in f: - LOG.log(level, 'privsep log: %s', line.rstrip()) - t = threading.Thread( - name='fd_logger', - target=logger, args=(read_end,) - ) - t.daemon = True - t.start() - - return write_end - - -def replace_logging(handler, log_root=None): - if log_root is None: - log_root = logging.getLogger(None).logger # root logger - for h in log_root.handlers: - log_root.removeHandler(h) - log_root.addHandler(handler) - - -class ForkingClientChannel(_ClientChannel): - def __init__(self, context): - """Start privsep daemon using fork() - - Assumes we already have required privileges. - """ - - sock_a, sock_b = socket.socketpair() - - for s in (sock_a, sock_b): - s.setblocking(True) - # Important that these sockets don't get leaked - set_cloexec(s) - - # Try to prevent any buffered output from being written by both - # parent and child. - for f in (sys.stdout, sys.stderr): - f.flush() - - if os.fork() == 0: - # child - - channel = comm.ServerChannel(sock_b) - sock_a.close() - - # Replace root logger early (to capture any errors during setup) - replace_logging(PrivsepLogHandler(channel, - processName=str(context))) - - Daemon(channel, context=context).run() - LOG.debug('privsep daemon exiting') - os._exit(0) - - # parent - - sock_b.close() - super(ForkingClientChannel, self).__init__(sock_a) - - -class RootwrapClientChannel(_ClientChannel): - def __init__(self, context): - """Start privsep daemon using exec() - - Uses sudo/rootwrap to gain privileges. - """ - - listen_sock = socket.socket(socket.AF_UNIX) - - # Note we listen() on the unprivileged side, and connect to it - # from the privileged process. This means there is no exposed - # attack point on the privileged side. - - # NB: Permissions on sockets are not checked on some (BSD) Unices - # so create socket in a private directory for safety. Privsep - # daemon will (initially) be running as root, so will still be - # able to connect to sock path. - tmpdir = tempfile.mkdtemp() # NB: created with 0700 perms - - try: - sockpath = os.path.join(tmpdir, 'privsep.sock') - listen_sock.bind(sockpath) - listen_sock.listen(1) - - cmd = context.helper_command(sockpath) - LOG.info('Running privsep helper: %s', cmd) - proc = subprocess.Popen(cmd, shell=False, stderr=_fd_logger()) - if proc.wait() != 0: - msg = ('privsep helper command exited non-zero (%s)' % - proc.returncode) - LOG.critical(msg) - raise FailedToDropPrivileges(msg) - LOG.info('Spawned new privsep daemon via rootwrap') - - sock, _addr = listen_sock.accept() - LOG.debug('Accepted privsep connection to %s', sockpath) - - finally: - # Don't need listen_sock anymore, so clean up. - listen_sock.close() - try: - os.unlink(sockpath) - except OSError as e: - if e.errno != errno.ENOENT: - raise - os.rmdir(tmpdir) - - super(RootwrapClientChannel, self).__init__(sock) - - -class Daemon(object): - """NB: This doesn't fork() - do that yourself before calling run()""" - - def __init__(self, channel, context): - self.channel = channel - self.context = context - self.user = context.conf.user - self.group = context.conf.group - self.caps = set(context.conf.capabilities) - - def run(self): - """Run request loop. Sets up environment, then calls loop()""" - os.chdir("/") - os.umask(0) - self._drop_privs() - self._close_stdio() - - self.loop() - - def _close_stdio(self): - with open(os.devnull, 'w+') as devnull: - os.dup2(devnull.fileno(), StdioFd.STDIN) - os.dup2(devnull.fileno(), StdioFd.STDOUT) - # stderr is left untouched - - def _drop_privs(self): - try: - # Keep current capabilities across setuid away from root. - capabilities.set_keepcaps(True) - - if self.group is not None: - try: - os.setgroups([]) - except OSError: - msg = _('Failed to remove supplemental groups') - LOG.critical(msg) - raise FailedToDropPrivileges(msg) - - if self.user is not None: - setuid(self.user) - - if self.group is not None: - setgid(self.group) - - finally: - capabilities.set_keepcaps(False) - - LOG.info('privsep process running with uid/gid: %(uid)s/%(gid)s', - {'uid': os.getuid(), 'gid': os.getgid()}) - - capabilities.drop_all_caps_except(self.caps, self.caps, []) - - def fmt_caps(capset): - if not capset: - return 'none' - fc = [capabilities.CAPS_BYVALUE.get(c, str(c)) - for c in capset] - fc.sort() - return '|'.join(fc) - - eff, prm, inh = capabilities.get_caps() - LOG.info( - 'privsep process running with capabilities ' - '(eff/prm/inh): %(eff)s/%(prm)s/%(inh)s', - { - 'eff': fmt_caps(eff), - 'prm': fmt_caps(prm), - 'inh': fmt_caps(inh), - }) - - def _process_cmd(self, cmd, *args): - if cmd == Message.PING: - return (Message.PONG.value,) - - elif cmd == Message.CALL: - name, f_args, f_kwargs = args - func = importutils.import_class(name) - - if not self.context.is_entrypoint(func): - msg = _('Invalid privsep function: %s not exported') % name - raise NameError(msg) - - ret = func(*f_args, **f_kwargs) - return (Message.RET.value, ret) - - raise ProtocolError(_('Unknown privsep cmd: %s') % cmd) - - def loop(self): - """Main body of daemon request loop""" - LOG.info('privsep daemon running as pid %s', os.getpid()) - - # We *are* this context now - any calls through it should be - # executed locally. - self.context.set_client_mode(False) - - for msgid, msg in self.channel: - LOG.debug('privsep: request[%(msgid)s]: %(req)s', - {'msgid': msgid, 'req': msg}) - try: - reply = self._process_cmd(*msg) - except Exception as e: - LOG.debug( - 'privsep: Exception during request[%(msgid)s]: %(err)s', - {'msgid': msgid, 'err': e}, exc_info=True) - cls = e.__class__ - cls_name = '%s.%s' % (cls.__module__, cls.__name__) - reply = (Message.ERR.value, cls_name, e.args) - - try: - LOG.debug('privsep: reply[%(msgid)s]: %(reply)s', - {'msgid': msgid, 'reply': reply}) - self.channel.send((msgid, reply)) - except IOError as e: - if e.errno == errno.EPIPE: - # Write stream closed, exit loop - break - raise - - LOG.debug('Socket closed, shutting down privsep daemon') - - -def helper_main(): - """Start privileged process, serving requests over a Unix socket.""" - - cfg.CONF.register_cli_opts([ - cfg.StrOpt('privsep_context', required=True), - cfg.StrOpt('privsep_sock_path', required=True), - ]) - - logging.register_options(cfg.CONF) - - cfg.CONF(args=sys.argv[1:], project='privsep') - logging.setup(cfg.CONF, 'privsep') # note replace_logging call below - - context = importutils.import_class(cfg.CONF.privsep_context) - from oslo_privsep import priv_context # Avoid circular import - if not isinstance(context, priv_context.PrivContext): - LOG.fatal('--privsep_context must be the (python) name of a ' - 'PrivContext object') - - sock = socket.socket(socket.AF_UNIX) - sock.connect(cfg.CONF.privsep_sock_path) - set_cloexec(sock) - channel = comm.ServerChannel(sock) - - # Channel is set up, so fork off daemon "in the background" and exit - if os.fork() != 0: - # parent - return - - # child - - # Note we don't move into a new process group/session like a - # regular daemon might, since we _want_ to remain associated with - # the originating (unprivileged) process. - - # Channel is set up now, so move to in-band logging - replace_logging(PrivsepLogHandler(channel)) - - LOG.info('privsep daemon starting') - - try: - Daemon(channel, context).run() - except Exception as e: - LOG.exception(e) - sys.exit(str(e)) - - LOG.debug('privsep daemon exiting') - sys.exit(0) - - -if __name__ == '__main__': - helper_main() diff --git a/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep-log-warning.po b/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep-log-warning.po deleted file mode 100644 index ce07bf5..0000000 --- a/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep-log-warning.po +++ /dev/null @@ -1,18 +0,0 @@ -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.privsep 1.5.1.dev2\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 13:52+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2015-11-13 04:56+0000\n" -"Last-Translator: Andreas Jaeger \n" -"Language-Team: German\n" -"Language: de\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "privsep daemon already running" -msgstr "Der Privsep Dämon läuft bereits." diff --git a/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po b/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po deleted file mode 100644 index c1bc4d2..0000000 --- a/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po +++ /dev/null @@ -1,53 +0,0 @@ -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.privsep 1.7.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-10 16:43+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-09 01:20+0000\n" -"Last-Translator: Andreas Jaeger \n" -"Language-Team: German\n" -"Language: de\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "Failed to remove supplemental groups" -msgstr "Fehler beim Entfernen zusätzlicher Gruppen" - -#, python-format -msgid "Failed to set gid %s" -msgstr "Fehler beim Festlegen von GID %s" - -#, python-format -msgid "Failed to set uid %s" -msgstr "Fehler beim Festlegen von Benutzer-ID %s" - -msgid "Group that the privsep daemon should run as." -msgstr "Gruppe als die der Privsep Dämon laufen soll." - -#, python-format -msgid "Invalid privsep function: %s not exported" -msgstr "Invalide Privsep Funktion: %s ist nicht exportiert." - -msgid "List of Linux capabilities retained by the privsep daemon." -msgstr "Liste von Linux Capabilities, die der Privsep Dämon behält." - -msgid "Premature eof waiting for privileged process" -msgstr "Vorzeitiges Dateiende beim Warten auf den priviligierten Prozeß" - -msgid "Privsep daemon failed to start" -msgstr "Der Privsep Dämon konnte nicht gestartet werden." - -#, python-format -msgid "Unexpected response: %r" -msgstr "Unerwartete Antwort: %r" - -#, python-format -msgid "Unknown privsep cmd: %s" -msgstr "Unbekanntes Privsep Kommando: %s" - -msgid "User that the privsep daemon should run as." -msgstr "User als der der Privsep Dämon laufen soll." diff --git a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-error.po b/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-error.po deleted file mode 100644 index f5f0647..0000000 --- a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-error.po +++ /dev/null @@ -1,26 +0,0 @@ -# Andi Chandler , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.privsep 1.7.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-10 16:43+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-09 11:12+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "--privsep_context must be the (python) name of a PrivContext object" -msgstr "--privsep_context must be the (python) name of a PrivContext object" - -#, python-format -msgid "Error while sending initial PING to privsep: %s" -msgstr "Error while sending initial PING to privsep: %s" - -#, python-format -msgid "privsep helper command exited non-zero (%s)" -msgstr "privsep helper command exited non-zero (%s)" diff --git a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-info.po b/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-info.po deleted file mode 100644 index fbf7e9a..0000000 --- a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-info.po +++ /dev/null @@ -1,41 +0,0 @@ -# Andi Chandler , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.privsep 1.7.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-10 16:43+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-09 11:13+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -#, python-format -msgid "Running privsep helper: %s" -msgstr "Running privsep helper: %s" - -msgid "Spawned new privsep daemon via rootwrap" -msgstr "Spawned new privsep daemon via rootwrap" - -#, python-format -msgid "privsep daemon running as pid %s" -msgstr "privsep daemon running as pid %s" - -msgid "privsep daemon starting" -msgstr "privsep daemon starting" - -#, python-format -msgid "" -"privsep process running with capabilities (eff/prm/inh): %(eff)s/%(prm)s/" -"%(inh)s" -msgstr "" -"privsep process running with capabilities (eff/prm/inh): %(eff)s/%(prm)s/" -"%(inh)s" - -#, python-format -msgid "privsep process running with uid/gid: %(uid)s/%(gid)s" -msgstr "privsep process running with uid/gid: %(uid)s/%(gid)s" diff --git a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-warning.po b/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-warning.po deleted file mode 100644 index 74d79b3..0000000 --- a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-warning.po +++ /dev/null @@ -1,18 +0,0 @@ -# Andi Chandler , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.privsep 1.7.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-10 16:43+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-09 11:13+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "privsep daemon already running" -msgstr "privsep daemon already running" diff --git a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po b/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po deleted file mode 100644 index 2475bf3..0000000 --- a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po +++ /dev/null @@ -1,66 +0,0 @@ -# Andi Chandler , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.privsep 1.7.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-10 16:43+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-09 11:12+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "" -"Command to invoke to start the privsep daemon if not using the \"fork\" " -"method. If not specified, a default is generated using \"sudo privsep-helper" -"\" and arguments designed to recreate the current configuration. This " -"command must accept suitable --privsep_context and --privsep_sock_path " -"arguments." -msgstr "" -"Command to invoke to start the privsep daemon if not using the \"fork\" " -"method. If not specified, a default is generated using \"sudo privsep-helper" -"\" and arguments designed to recreate the current configuration. This " -"command must accept suitable --privsep_context and --privsep_sock_path " -"arguments." - -msgid "Failed to remove supplemental groups" -msgstr "Failed to remove supplemental groups" - -#, python-format -msgid "Failed to set gid %s" -msgstr "Failed to set gid %s" - -#, python-format -msgid "Failed to set uid %s" -msgstr "Failed to set uid %s" - -msgid "Group that the privsep daemon should run as." -msgstr "Group that the privsep daemon should run as." - -#, python-format -msgid "Invalid privsep function: %s not exported" -msgstr "Invalid privsep function: %s not exported" - -msgid "List of Linux capabilities retained by the privsep daemon." -msgstr "List of Linux capabilities retained by the privsep daemon." - -msgid "Premature eof waiting for privileged process" -msgstr "Premature EOF waiting for privileged process" - -msgid "Privsep daemon failed to start" -msgstr "Privsep daemon failed to start" - -#, python-format -msgid "Unexpected response: %r" -msgstr "Unexpected response: %r" - -#, python-format -msgid "Unknown privsep cmd: %s" -msgstr "Unknown privsep cmd: %s" - -msgid "User that the privsep daemon should run as." -msgstr "User that the privsep daemon should run as." diff --git a/oslo_privsep/priv_context.py b/oslo_privsep/priv_context.py deleted file mode 100644 index 98b5df3..0000000 --- a/oslo_privsep/priv_context.py +++ /dev/null @@ -1,226 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import enum -import functools -import logging -import shlex -import sys - -from oslo_config import cfg -from oslo_config import types -from oslo_utils import importutils - -from oslo_privsep._i18n import _ -from oslo_privsep import capabilities -from oslo_privsep import daemon - - -LOG = logging.getLogger(__name__) - - -def CapNameOrInt(value): - value = str(value).strip() - try: - return capabilities.CAPS_BYNAME[value] - except KeyError: - return int(value) - - -OPTS = [ - cfg.StrOpt('user', - help=_('User that the privsep daemon should run as.')), - cfg.StrOpt('group', - help=_('Group that the privsep daemon should run as.')), - cfg.Opt('capabilities', - type=types.List(CapNameOrInt), default=[], - help=_('List of Linux capabilities retained by the privsep ' - 'daemon.')), - cfg.StrOpt('helper_command', - help=_('Command to invoke to start the privsep daemon if ' - 'not using the "fork" method. ' - 'If not specified, a default is generated using ' - '"sudo privsep-helper" and arguments designed to ' - 'recreate the current configuration. ' - 'This command must accept suitable --privsep_context ' - 'and --privsep_sock_path arguments.')), -] - -_ENTRYPOINT_ATTR = 'privsep_entrypoint' -_HELPER_COMMAND_PREFIX = ['sudo'] - - -@enum.unique -class Method(enum.Enum): - FORK = 1 - ROOTWRAP = 2 - - -def init(root_helper=None): - """Initialise oslo.privsep library. - - This function should be called at the top of main(), after the - command line is parsed, oslo.config is initialised and logging is - set up, but before calling any privileged entrypoint, changing - user id, forking, or anything else "odd". - - :param root_helper: List of command and arguments to prefix - privsep-helper with, in order to run helper as root. Note, - ignored if context's helper_command config option is set. - """ - - if root_helper: - global _HELPER_COMMAND_PREFIX - _HELPER_COMMAND_PREFIX = root_helper - - -class PrivContext(object): - def __init__(self, prefix, cfg_section='privsep', pypath=None, - capabilities=None): - - # Note that capabilities=[] means retaining no capabilities - # and leaves even uid=0 with no powers except being able to - # read/write to the filesystem as uid=0. This might be what - # you want, but probably isn't. - # - # There is intentionally no way to say "I want all the - # capabilities." - if capabilities is None: - raise ValueError('capabilities is a required parameter') - - self.pypath = pypath - self.prefix = prefix - self.cfg_section = cfg_section - - # NOTE(claudiub): oslo.privsep is not currently supported on Windows, - # as it uses Linux-specific functionality (os.fork, socker.AF_UNIX). - # The client_mode should be set to False on Windows. - self.client_mode = sys.platform != 'win32' - self.channel = None - - cfg.CONF.register_opts(OPTS, group=cfg_section) - cfg.CONF.set_default('capabilities', group=cfg_section, - default=capabilities) - - @property - def conf(self): - """Return the oslo.config section object as lazily as possible.""" - # Need to avoid looking this up before oslo_config has been - # properly initialized. - return cfg.CONF[self.cfg_section] - - def __repr__(self): - return 'PrivContext(cfg_section=%s)' % self.cfg_section - - def helper_command(self, sockpath): - # We need to be able to reconstruct the context object in the new - # python process we'll get after rootwrap/sudo. This means we - # need to construct the context object and store it somewhere - # globally accessible, and then use that python name to find it - # again in the new python interpreter. Yes, it's all a bit - # clumsy, and none of it is required when using the fork-based - # alternative above. - # These asserts here are just attempts to catch errors earlier. - # TODO(gus): Consider replacing with setuptools entry_points. - assert self.pypath is not None, ( - 'helper_command requires priv_context ' - 'pypath to be specified') - assert importutils.import_class(self.pypath) is self, ( - 'helper_command requires priv_context pypath ' - 'for context object') - - # Note order is important here. Deployments will (hopefully) - # have the exact arguments in sudoers/rootwrap configs and - # reordering args will break configs! - - if self.conf.helper_command: - cmd = shlex.split(self.conf.helper_command) - else: - cmd = _HELPER_COMMAND_PREFIX + ['privsep-helper'] - - try: - for cfg_file in cfg.CONF.config_file: - cmd.extend(['--config-file', cfg_file]) - except cfg.NoSuchOptError: - pass - - try: - if cfg.CONF.config_dir is not None: - for cfg_dir in cfg.CONF.config_dir: - cmd.extend(['--config-dir', cfg_dir]) - except cfg.NoSuchOptError: - pass - - cmd.extend( - ['--privsep_context', self.pypath, - '--privsep_sock_path', sockpath]) - - return cmd - - def set_client_mode(self, enabled): - if enabled and sys.platform == 'win32': - raise RuntimeError( - "Enabling the client_mode is not currently " - "supported on Windows.") - self.client_mode = enabled - - def entrypoint(self, func): - """This is intended to be used as a decorator.""" - - assert func.__module__.startswith(self.prefix), ( - '%r entrypoints must be below "%s"' % (self, self.prefix)) - - # Right now, we only track a single context in - # _ENTRYPOINT_ATTR. This could easily be expanded into a set, - # but that will increase the memory overhead. Revisit if/when - # someone has a need to associate the same entrypoint with - # multiple contexts. - assert getattr(func, _ENTRYPOINT_ATTR, None) is None, ( - '%r is already associated with another PrivContext' % func) - - f = functools.partial(self._wrap, func) - setattr(f, _ENTRYPOINT_ATTR, self) - return f - - def is_entrypoint(self, func): - return getattr(func, _ENTRYPOINT_ATTR, None) is self - - def _wrap(self, func, *args, **kwargs): - if self.client_mode: - name = '%s.%s' % (func.__module__, func.__name__) - if self.channel is None: - self.start() - return self.channel.remote_call(name, args, kwargs) - else: - return func(*args, **kwargs) - - def start(self, method=Method.ROOTWRAP): - if self.channel is not None: - LOG.warning('privsep daemon already running') - return - - if method is Method.ROOTWRAP: - channel = daemon.RootwrapClientChannel(context=self) - elif method is Method.FORK: - channel = daemon.ForkingClientChannel(context=self) - else: - raise ValueError('Unknown method: %s' % method) - - self.channel = channel - - def stop(self): - if self.channel is not None: - self.channel.close() - self.channel = None diff --git a/oslo_privsep/tests/__init__.py b/oslo_privsep/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_privsep/tests/fixture.py b/oslo_privsep/tests/fixture.py deleted file mode 100644 index f5d810a..0000000 --- a/oslo_privsep/tests/fixture.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import fixtures -import logging -import os -import sys - -from oslo_config import fixture as cfg_fixture - -from oslo_privsep import priv_context - -LOG = logging.getLogger(__name__) - - -class UnprivilegedPrivsepFixture(fixtures.Fixture): - def __init__(self, context): - self.context = context - - def setUp(self): - super(UnprivilegedPrivsepFixture, self).setUp() - - self.conf = self.useFixture(cfg_fixture.Config()).conf - self.conf.set_override('capabilities', [], - group=self.context.cfg_section) - for k in ('user', 'group'): - self.conf.set_override( - k, None, group=self.context.cfg_section) - - orig_pid = os.getpid() - try: - self.context.start(method=priv_context.Method.FORK) - except Exception as e: - # py3 unittest/testtools/something catches fatal - # exceptions from child processes and tries to treat them - # like regular non-fatal test failures. Here we attempt - # to undo that. - if os.getpid() == orig_pid: - raise - LOG.exception(e) - sys.exit(1) - - self.addCleanup(self.context.stop) diff --git a/oslo_privsep/tests/test_capabilities.py b/oslo_privsep/tests/test_capabilities.py deleted file mode 100644 index af9ae14..0000000 --- a/oslo_privsep/tests/test_capabilities.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from oslotest import base - -from oslo_privsep import capabilities - - -class TestCapabilities(base.BaseTestCase): - - @mock.patch('oslo_privsep.capabilities._prctl') - def test_set_keepcaps_error(self, mock_prctl): - mock_prctl.return_value = -1 - self.assertRaises(OSError, capabilities.set_keepcaps, True) - - @mock.patch('oslo_privsep.capabilities._prctl') - def test_set_keepcaps(self, mock_prctl): - mock_prctl.return_value = 0 - capabilities.set_keepcaps(True) - - # Disappointingly, ffi.cast(type, 1) != ffi.cast(type, 1) - # so can't just use assert_called_once_with :-( - self.assertEqual(1, mock_prctl.call_count) - self.assertItemsEqual( - [8, 1], # [PR_SET_KEEPCAPS, true] - [int(x) for x in mock_prctl.call_args[0]]) - - @mock.patch('oslo_privsep.capabilities._capset') - def test_drop_all_caps_except_error(self, mock_capset): - mock_capset.return_value = -1 - self.assertRaises( - OSError, capabilities.drop_all_caps_except, [0], [0], [0]) - - @mock.patch('oslo_privsep.capabilities._capset') - def test_drop_all_caps_except(self, mock_capset): - mock_capset.return_value = 0 - - # Somewhat arbitrary bit patterns to exercise _caps_to_mask - capabilities.drop_all_caps_except( - (17, 24, 49), (8, 10, 35, 56), (24, 31, 40)) - - self.assertEqual(1, mock_capset.call_count) - hdr, data = mock_capset.call_args[0] - self.assertEqual(0x20071026, # _LINUX_CAPABILITY_VERSION_2 - hdr.version) - self.assertEqual(0x01020000, data[0].effective) - self.assertEqual(0x00020000, data[1].effective) - self.assertEqual(0x00000500, data[0].permitted) - self.assertEqual(0x01000008, data[1].permitted) - self.assertEqual(0x81000000, data[0].inheritable) - self.assertEqual(0x00000100, data[1].inheritable) - - @mock.patch('oslo_privsep.capabilities._capget') - def test_get_caps_error(self, mock_capget): - mock_capget.return_value = -1 - self.assertRaises(OSError, capabilities.get_caps) - - @mock.patch('oslo_privsep.capabilities._capget') - def test_get_caps(self, mock_capget): - def impl(hdr, data): - # Somewhat arbitrary bit patterns to exercise _mask_to_caps - data[0].effective = 0x01020000 - data[1].effective = 0x00020000 - data[0].permitted = 0x00000500 - data[1].permitted = 0x01000008 - data[0].inheritable = 0x81000000 - data[1].inheritable = 0x00000100 - return 0 - mock_capget.side_effect = impl - - self.assertItemsEqual( - ([17, 24, 49], - [8, 10, 35, 56], - [24, 31, 40]), - capabilities.get_caps()) diff --git a/oslo_privsep/tests/test_comm.py b/oslo_privsep/tests/test_comm.py deleted file mode 100644 index 72f7aef..0000000 --- a/oslo_privsep/tests/test_comm.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from oslotest import base - -from oslo_privsep import comm - - -class BufSock(object): - def __init__(self): - self.readpos = 0 - self.buf = six.BytesIO() - - def recv(self, bufsize): - if self.buf.closed: - return b'' - self.buf.seek(self.readpos, 0) - data = self.buf.read(bufsize) - self.readpos += len(data) - return data - - def sendall(self, data): - self.buf.seek(0, 2) - self.buf.write(data) - - def shutdown(self, _flag): - self.buf.close() - - -class TestSerialization(base.BaseTestCase): - def setUp(self): - super(TestSerialization, self).setUp() - - sock = BufSock() - - self.input = comm.Serializer(sock) - self.output = iter(comm.Deserializer(sock)) - - def send(self, data): - self.input.send(data) - return next(self.output) - - def assertSendable(self, value): - self.assertEqual(value, self.send(value)) - - def test_none(self): - self.assertSendable(None) - - def test_bool(self): - self.assertSendable(True) - self.assertSendable(False) - - def test_int(self): - self.assertSendable(42) - self.assertSendable(-84) - - def test_bytes(self): - data = b'\x00\x01\x02\xfd\xfe\xff' - self.assertSendable(data) - - def test_unicode(self): - data = u'\u4e09\u9df9' - self.assertSendable(data) - - def test_tuple(self): - self.assertSendable((1, 'foo')) - - def test_list(self): - # NB! currently lists get converted to tuples by serialization. - self.assertEqual((1, 'foo'), self.send([1, 'foo'])) - - def test_dict(self): - self.assertSendable( - { - 'a': 'b', - 1: 2, - None: None, - (1, 2): (3, 4), - } - ) - - def test_badobj(self): - class UnknownClass(object): - pass - - obj = UnknownClass() - self.assertRaises(TypeError, self.send, obj) - - def test_eof(self): - self.input.close() - self.assertRaises(StopIteration, next, self.output) diff --git a/oslo_privsep/tests/test_daemon.py b/oslo_privsep/tests/test_daemon.py deleted file mode 100644 index ba8ed92..0000000 --- a/oslo_privsep/tests/test_daemon.py +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import fixtures -import functools -import logging as pylogging -import mock -import platform -import time - -from oslo_log import formatters -from oslo_log import log as logging -from oslotest import base -import testtools - -from oslo_privsep import capabilities -from oslo_privsep import daemon -from oslo_privsep.tests import testctx - - -LOG = logging.getLogger(__name__) - - -def undecorated(): - pass - - -class TestException(Exception): - pass - - -@testctx.context.entrypoint -def logme(level, msg, exc_info=False): - # We want to make sure we log everything from the priv side for - # the purposes of this test, so force loglevel. - LOG.logger.setLevel(logging.DEBUG) - if exc_info: - try: - raise TestException('with arg') - except TestException: - LOG.log(level, msg, exc_info=True) - else: - LOG.log(level, msg) - - -class LogRecorder(pylogging.Formatter): - def __init__(self, logs, *args, **kwargs): - super(LogRecorder, self).__init__(*args, **kwargs) - self.logs = logs - - def format(self, record): - self.logs.append(copy.deepcopy(record)) - return super(LogRecorder, self).format(record) - - -@testtools.skipIf(platform.system() != 'Linux', - 'works only on Linux platform.') -class LogTest(testctx.TestContextTestCase): - def setUp(self): - super(LogTest, self).setUp() - - def test_priv_loglevel(self): - logger = self.useFixture(fixtures.FakeLogger( - level=logging.INFO)) - - # These write to the log on the priv side - logme(logging.DEBUG, u'test@DEBUG') - logme(logging.WARN, u'test@WARN') - - time.sleep(0.1) # Hack to give logging thread a chance to run - - # logger.output is the resulting log on the unpriv side. - # This should have been filtered based on (unpriv) loglevel. - self.assertNotIn(u'test@DEBUG', logger.output) - self.assertIn(u'test@WARN', logger.output) - - def test_record_data(self): - logs = [] - - self.useFixture(fixtures.FakeLogger( - level=logging.INFO, format='dummy', - # fixtures.FakeLogger accepts only a formatter - # class/function, not an instance :( - formatter=functools.partial(LogRecorder, logs))) - - logme(logging.WARN, u'test with exc', exc_info=True) - - time.sleep(0.1) # Hack to give logging thread a chance to run - - self.assertEqual(1, len(logs)) - - record = logs[0] - self.assertIn(u'test with exc', record.getMessage()) - self.assertIsNone(record.exc_info) - self.assertIn(u'TestException: with arg', record.exc_text) - self.assertEqual('PrivContext(cfg_section=privsep)', - record.processName) - self.assertIn(u'test_daemon.py', record.exc_text) - self.assertEqual(logging.WARN, record.levelno) - self.assertEqual('logme', record.funcName) - - def test_format_record(self): - logs = [] - - self.useFixture(fixtures.FakeLogger( - level=logging.INFO, format='dummy', - # fixtures.FakeLogger accepts only a formatter - # class/function, not an instance :( - formatter=functools.partial(LogRecorder, logs))) - - logme(logging.WARN, u'test with exc', exc_info=True) - - time.sleep(0.1) # Hack to give logging thread a chance to run - - self.assertEqual(1, len(logs)) - - record = logs[0] - # Verify the log record can be formatted by ContextFormatter - fake_config = mock.Mock( - logging_default_format_string="NOCTXT: %(message)s") - formatter = formatters.ContextFormatter(config=fake_config) - formatter.format(record) - - -@testtools.skipIf(platform.system() != 'Linux', - 'works only on Linux platform.') -class DaemonTest(base.BaseTestCase): - - @mock.patch('os.setuid') - @mock.patch('os.setgid') - @mock.patch('os.setgroups') - @mock.patch('oslo_privsep.capabilities.set_keepcaps') - @mock.patch('oslo_privsep.capabilities.drop_all_caps_except') - def test_drop_privs(self, mock_dropcaps, mock_keepcaps, - mock_setgroups, mock_setgid, mock_setuid): - channel = mock.NonCallableMock() - context = mock.NonCallableMock() - context.conf.user = 42 - context.conf.group = 84 - context.conf.capabilities = [ - capabilities.CAP_SYS_ADMIN, capabilities.CAP_NET_ADMIN] - - d = daemon.Daemon(channel, context) - d._drop_privs() - - mock_setuid.assert_called_once_with(42) - mock_setgid.assert_called_once_with(84) - mock_setgroups.assert_called_once_with([]) - - self.assertItemsEqual( - [mock.call(True), mock.call(False)], - mock_keepcaps.mock_calls) - - mock_dropcaps.assert_called_once_with( - set((capabilities.CAP_SYS_ADMIN, capabilities.CAP_NET_ADMIN)), - set((capabilities.CAP_SYS_ADMIN, capabilities.CAP_NET_ADMIN)), - []) - - -@testtools.skipIf(platform.system() != 'Linux', - 'works only on Linux platform.') -class WithContextTest(testctx.TestContextTestCase): - - def test_unexported(self): - self.assertRaisesRegexp( - NameError, 'undecorated not exported', - testctx.context._wrap, undecorated) diff --git a/oslo_privsep/tests/test_priv_context.py b/oslo_privsep/tests/test_priv_context.py deleted file mode 100644 index 535e48f..0000000 --- a/oslo_privsep/tests/test_priv_context.py +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import logging -import os -import pipes -import platform -import sys - -import mock -import testtools - -from oslo_privsep import daemon -from oslo_privsep import priv_context -from oslo_privsep.tests import testctx - -LOG = logging.getLogger(__name__) - - -@testctx.context.entrypoint -def priv_getpid(): - return os.getpid() - - -@testctx.context.entrypoint -def add1(arg): - return arg + 1 - - -class CustomError(Exception): - def __init__(self, code, msg): - super(CustomError, self).__init__(code, msg) - self.code = code - self.msg = msg - - def __str__(self): - return 'Code %s: %s' % (self.code, self.msg) - - -@testctx.context.entrypoint -def fail(custom=False): - if custom: - raise CustomError(42, 'omg!') - else: - raise RuntimeError("I can't let you do that Dave") - - -@testtools.skipIf(platform.system() != 'Linux', - 'works only on Linux platform.') -class PrivContextTest(testctx.TestContextTestCase): - - @mock.patch.object(priv_context, 'sys') - def test_init_windows(self, mock_sys): - mock_sys.platform = 'win32' - - context = priv_context.PrivContext('test', capabilities=[]) - self.assertFalse(context.client_mode) - - @mock.patch.object(priv_context, 'sys') - def test_set_client_mode(self, mock_sys): - context = priv_context.PrivContext('test', capabilities=[]) - self.assertTrue(context.client_mode) - - context.set_client_mode(False) - self.assertFalse(context.client_mode) - - # client_mode should remain to False on win32. - mock_sys.platform = 'win32' - self.assertRaises(RuntimeError, context.set_client_mode, True) - - def test_helper_command(self): - self.privsep_conf.privsep.helper_command = 'foo --bar' - cmd = testctx.context.helper_command('/tmp/sockpath') - expected = [ - 'foo', '--bar', - '--privsep_context', testctx.context.pypath, - '--privsep_sock_path', '/tmp/sockpath', - ] - self.assertEqual(expected, cmd) - - def test_helper_command_default(self): - self.privsep_conf.config_file = ['/bar.conf'] - cmd = testctx.context.helper_command('/tmp/sockpath') - expected = [ - 'sudo', 'privsep-helper', - '--config-file', '/bar.conf', - # --config-dir arg should be skipped - '--privsep_context', testctx.context.pypath, - '--privsep_sock_path', '/tmp/sockpath', - ] - self.assertEqual(expected, cmd) - - def test_helper_command_default_dirtoo(self): - self.privsep_conf.config_file = ['/bar.conf', '/baz.conf'] - self.privsep_conf.config_dir = ['/foo.d'] - cmd = testctx.context.helper_command('/tmp/sockpath') - expected = [ - 'sudo', 'privsep-helper', - '--config-file', '/bar.conf', - '--config-file', '/baz.conf', - '--config-dir', '/foo.d', - '--privsep_context', testctx.context.pypath, - '--privsep_sock_path', '/tmp/sockpath', - ] - self.assertEqual(expected, cmd) - - def test_init_known_contexts(self): - self.assertEqual(testctx.context.helper_command('/sock')[:2], - ['sudo', 'privsep-helper']) - priv_context.init(root_helper=['sudo', 'rootwrap']) - self.assertEqual(testctx.context.helper_command('/sock')[:3], - ['sudo', 'rootwrap', 'privsep-helper']) - - -@testtools.skipIf(platform.system() != 'Linux', - 'works only on Linux platform.') -class SeparationTest(testctx.TestContextTestCase): - def test_getpid(self): - # Verify that priv_getpid() was executed in another process. - priv_pid = priv_getpid() - self.assertNotMyPid(priv_pid) - - def test_client_mode(self): - self.assertNotMyPid(priv_getpid()) - - self.addCleanup(testctx.context.set_client_mode, True) - - testctx.context.set_client_mode(False) - # priv_getpid() should now run locally (and return our pid) - self.assertEqual(os.getpid(), priv_getpid()) - - testctx.context.set_client_mode(True) - # priv_getpid() should now run remotely again - self.assertNotMyPid(priv_getpid()) - - -@testtools.skipIf(platform.system() != 'Linux', - 'works only on Linux platform.') -class RootwrapTest(testctx.TestContextTestCase): - def setUp(self): - super(RootwrapTest, self).setUp() - testctx.context.stop() - - # Generate a command that will run daemon.helper_main without - # requiring it to be properly installed. - cmd = [ - 'env', - 'PYTHON_PATH=%s' % os.path.pathsep.join(sys.path), - sys.executable, daemon.__file__, - ] - if LOG.isEnabledFor(logging.DEBUG): - cmd.append('--debug') - - self.privsep_conf.set_override( - 'helper_command', ' '.join(map(pipes.quote, cmd)), - group=testctx.context.cfg_section) - - testctx.context.start(method=priv_context.Method.ROOTWRAP) - - def test_getpid(self): - # Verify that priv_getpid() was executed in another process. - priv_pid = priv_getpid() - self.assertNotMyPid(priv_pid) - - -@testtools.skipIf(platform.system() != 'Linux', - 'works only on Linux platform.') -class SerializationTest(testctx.TestContextTestCase): - def test_basic_functionality(self): - self.assertEqual(43, add1(42)) - - def test_raises_standard(self): - self.assertRaisesRegexp( - RuntimeError, "I can't let you do that Dave", fail) - - def test_raises_custom(self): - exc = self.assertRaises(CustomError, fail, custom=True) - self.assertEqual(exc.code, 42) - self.assertEqual(exc.msg, 'omg!') diff --git a/oslo_privsep/tests/testctx.py b/oslo_privsep/tests/testctx.py deleted file mode 100644 index 0b19ced..0000000 --- a/oslo_privsep/tests/testctx.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2015 Rackspace Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -from oslotest import base - -from oslo_privsep import priv_context -import oslo_privsep.tests -from oslo_privsep.tests import fixture - - -context = priv_context.PrivContext( - # This context allows entrypoints anywhere below oslo_privsep.tests. - oslo_privsep.tests.__name__, - pypath=__name__ + '.context', - # This is one of the rare cases where we actually want zero powers: - capabilities=[], -) - - -class TestContextTestCase(base.BaseTestCase): - def setUp(self): - super(TestContextTestCase, self).setUp() - privsep_fixture = self.useFixture( - fixture.UnprivilegedPrivsepFixture(context)) - self.privsep_conf = privsep_fixture.conf - - def assertNotMyPid(self, pid): - # Verify that `pid` is some positive integer, that isn't our pid - self.assertIsInstance(pid, int) - self.assertTrue(pid > 0) - self.assertNotEqual(os.getpid(), pid) diff --git a/oslo_privsep/version.py b/oslo_privsep/version.py deleted file mode 100644 index 7a107c8..0000000 --- a/oslo_privsep/version.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import pbr.version - -version_info = pbr.version.VersionInfo('oslo.privsep') diff --git a/releasenotes/notes/add_reno-3b4ae0789e9c45b4.yaml b/releasenotes/notes/add_reno-3b4ae0789e9c45b4.yaml deleted file mode 100644 index 46a2da6..0000000 --- a/releasenotes/notes/add_reno-3b4ae0789e9c45b4.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -other: - - Switch to reno for managing release notes. \ No newline at end of file diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 627e707..0000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,282 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# openstackdocstheme options -repository_name = 'openstack/oslo.privsep' -bug_project = 'oslo.privsep' -bug_tag = '' -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'oslo.privsep Release Notes' -copyright = u'2016, oslo.privsep Developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -from oslo_privsep.version import version_info as oslo_privsep_version -# The full version, including alpha/beta/rc tags. -release = oslo_privsep_version.version_string_with_vcs() -# The short X.Y version. -version = oslo_privsep_version.canonical_version_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'oslo.privsepReleaseNotesDoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'oslo.privsepReleaseNotes.tex', - u'oslo.privsep Release Notes Documentation', - u'oslo.privsep Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'oslo.privsepReleaseNotes', - u'oslo.privsep Release Notes Documentation', - [u'oslo.privsep Developers'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'oslo.privsepReleaseNotes', - u'oslo.privsep Release Notes Documentation', - u'oslo.privsep Developers', 'oslo.privsepReleaseNotes', - 'OpenStack library for privilege separation.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index 28fa017..0000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -============================ - oslo.privsep Release Notes -============================ - - .. toctree:: - :maxdepth: 1 - - unreleased - ocata - newton diff --git a/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po deleted file mode 100644 index 20561d2..0000000 --- a/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,33 +0,0 @@ -# Gérald LONLAS , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.privsep Release Notes 1.14.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-10-23 20:38+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-10-22 06:04+0000\n" -"Last-Translator: Gérald LONLAS \n" -"Language-Team: French\n" -"Language: fr\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" - -msgid "1.13.0" -msgstr "1.13.0" - -msgid "Newton Series Release Notes" -msgstr "Note de release pour Newton" - -msgid "Other Notes" -msgstr "Autres notes" - -msgid "Switch to reno for managing release notes." -msgstr "Commence à utiliser reno pour la gestion des notes de release" - -msgid "Unreleased Release Notes" -msgstr "Note de release pour les changements non déployées" - -msgid "oslo.privsep Release Notes" -msgstr "Note de release pour oslo.privsep" diff --git a/releasenotes/source/newton.rst b/releasenotes/source/newton.rst deleted file mode 100644 index 7b7d735..0000000 --- a/releasenotes/source/newton.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================= - Newton Series Release Notes -============================= - -.. release-notes:: - :branch: origin/stable/newton diff --git a/releasenotes/source/ocata.rst b/releasenotes/source/ocata.rst deleted file mode 100644 index ebe62f4..0000000 --- a/releasenotes/source/ocata.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Ocata Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/ocata diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index 5860a46..0000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -========================== - Unreleased Release Notes -========================== - -.. release-notes:: diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 22b2b9d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -oslo.log>=3.22.0 # Apache-2.0 -oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0 -oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 -oslo.utils>=3.20.0 # Apache-2.0 -enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD -cffi # MIT -eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 # MIT -greenlet>=0.3.2 # MIT -msgpack-python>=0.4.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 2c55447..0000000 --- a/setup.cfg +++ /dev/null @@ -1,60 +0,0 @@ -[metadata] -name = oslo.privsep -summary = OpenStack library for privilege separation -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = https://docs.openstack.org/oslo.privsep/latest/ -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 - -[files] -packages = - oslo_privsep - -[pbr] -autodoc_index_modules = True -api_doc_dir = reference/api -autodoc_exclude_modules = - oslo_privsep.tests.* - oslo_privsep._* - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 -warning-is-error = 1 - -[entry_points] -console_scripts = - privsep-helper = oslo_privsep.daemon:helper_main - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = oslo.privsep/locale -domain = oslo_privsep - -[update_catalog] -domain = oslo_privsep -output_dir = oslo_privsep/locale -input_file = oslo_privsep/locale/oslo_privsep.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = oslo_privsep/locale/oslo_privsep.pot - -[wheel] -universal = true diff --git a/setup.py b/setup.py deleted file mode 100644 index 566d844..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 9752557..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 -mock>=2.0 # BSD -fixtures>=3.0.0 # Apache-2.0/BSD - -# These are needed for docs generation -openstackdocstheme>=1.11.0 # Apache-2.0 -sphinx>=1.6.2 # BSD -reno!=2.3.1,>=1.8.0 # Apache-2.0 diff --git a/tools/tox_install.sh b/tools/tox_install.sh deleted file mode 100755 index e61b63a..0000000 --- a/tools/tox_install.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should remove the version pin in -# the constraints file before applying it for from-source installation. - -CONSTRAINTS_FILE="$1" -shift 1 - -set -e - -# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get -# published to logs.openstack.org for easy debugging. -localfile="$VIRTUAL_ENV/log/upper-constraints.txt" - -if [[ "$CONSTRAINTS_FILE" != http* ]]; then - CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE" -fi -# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep -curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile" - -pip install -c"$localfile" openstack-requirements - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints "$localfile" -- "$CLIENT_NAME" - -pip install -c"$localfile" -U "$@" -exit $? diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 1e35d59..0000000 --- a/tox.ini +++ /dev/null @@ -1,44 +0,0 @@ -[tox] -minversion = 2.0 -envlist = py35,py27,pypy,pep8 - -[testenv] -setenv = - VIRTUAL_ENV={envdir} - BRANCH_NAME=master - CLIENT_NAME=oslo.privsep -install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} -whitelist_externals = - /bin/sh -deps = -r{toxinidir}/test-requirements.txt -commands = python setup.py testr --slowest --testr-args='{posargs}' - -[testenv:pep8] -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -commands = python setup.py build_sphinx - -[testenv:cover] -commands = python setup.py testr --coverage --testr-args='{posargs}' - -[flake8] -# E123, E125 skipped as they are invalid PEP-8. -# [H106] Don’t put vim configuration in source files -# [H203] Use assertIs(Not)None to check for None - -show-source = True -ignore = E123,E125 -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build -enable-extensions = H106,H203 - -[hacking] -import_exceptions = - oslo_privsep._i18n - -[testenv:releasenotes] -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html