From 1b34b559bba7fc45c454507b6b3e5c39f7c26086 Mon Sep 17 00:00:00 2001 From: Ronald Bradford Date: Fri, 25 Mar 2016 11:50:18 -0400 Subject: [PATCH] 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". http://lists.openstack.org/pipermail/openstack-dev/2016-March/090409.html See I78a16ad052072feba7670aaea144216875ddc0d1 for kite project removal. Change-Id: I0461da5039e2357f19a86de3922b86dfabb79b05 Depends-On: If9c42d2cec35b68c4de85b750c8540d86322f3e3 --- CONTRIBUTING.rst | 16 - HACKING.rst | 4 - LICENSE | 175 ------ MANIFEST.in | 6 - README.rst | 19 +- babel.cfg | 1 - doc/source/conf.py | 75 --- doc/source/contributing.rst | 1 - doc/source/index.rst | 24 - doc/source/installation.rst | 12 - doc/source/readme.rst | 1 - doc/source/usage.rst | 7 - kiteclient/__init__.py | 19 - kiteclient/cli/__init__.py | 0 kiteclient/cli/v1.py | 159 ------ kiteclient/common/__init__.py | 0 kiteclient/common/meta_data.py | 43 -- kiteclient/common/resource.py | 57 -- kiteclient/common/utils.py | 21 - kiteclient/openstack/__init__.py | 0 kiteclient/openstack/common/__init__.py | 0 kiteclient/openstack/common/_i18n.py | 45 -- .../openstack/common/crypto/__init__.py | 0 kiteclient/openstack/common/crypto/utils.py | 197 ------- kiteclient/openstack/common/gettextutils.py | 498 ------------------ kiteclient/openstack/common/importutils.py | 73 --- kiteclient/openstack/common/jsonutils.py | 186 ------- kiteclient/openstack/common/strutils.py | 239 --------- kiteclient/openstack/common/timeutils.py | 210 -------- kiteclient/tests/__init__.py | 0 kiteclient/tests/base.py | 48 -- kiteclient/tests/test_kiteclient.py | 26 - kiteclient/tests/v1/__init__.py | 0 kiteclient/tests/v1/test_esek.py | 86 --- kiteclient/tests/v1/test_group.py | 81 --- kiteclient/tests/v1/test_key.py | 86 --- kiteclient/tests/v1/test_ticket.py | 108 ---- kiteclient/tests/v1/utils.py | 69 --- kiteclient/v1/__init__.py | 24 - kiteclient/v1/esek.py | 57 -- kiteclient/v1/group.py | 109 ---- kiteclient/v1/key.py | 77 --- kiteclient/v1/ticket.py | 109 ---- openstack-common.conf | 8 - requirements.txt | 8 - scripts/basic.py | 43 -- scripts/demo-client/client.py | 84 --- scripts/demo-client/main.py | 93 ---- scripts/demo-client/transport.py | 44 -- scripts/group.py | 38 -- setup.cfg | 55 -- setup.py | 30 -- test-requirements.txt | 14 - tox.ini | 32 -- 54 files changed, 6 insertions(+), 3411 deletions(-) delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE delete mode 100644 MANIFEST.in delete mode 100644 babel.cfg delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/contributing.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/installation.rst delete mode 100644 doc/source/readme.rst delete mode 100644 doc/source/usage.rst delete mode 100644 kiteclient/__init__.py delete mode 100644 kiteclient/cli/__init__.py delete mode 100644 kiteclient/cli/v1.py delete mode 100644 kiteclient/common/__init__.py delete mode 100644 kiteclient/common/meta_data.py delete mode 100644 kiteclient/common/resource.py delete mode 100644 kiteclient/common/utils.py delete mode 100644 kiteclient/openstack/__init__.py delete mode 100644 kiteclient/openstack/common/__init__.py delete mode 100644 kiteclient/openstack/common/_i18n.py delete mode 100644 kiteclient/openstack/common/crypto/__init__.py delete mode 100644 kiteclient/openstack/common/crypto/utils.py delete mode 100644 kiteclient/openstack/common/gettextutils.py delete mode 100644 kiteclient/openstack/common/importutils.py delete mode 100644 kiteclient/openstack/common/jsonutils.py delete mode 100644 kiteclient/openstack/common/strutils.py delete mode 100644 kiteclient/openstack/common/timeutils.py delete mode 100644 kiteclient/tests/__init__.py delete mode 100644 kiteclient/tests/base.py delete mode 100644 kiteclient/tests/test_kiteclient.py delete mode 100644 kiteclient/tests/v1/__init__.py delete mode 100644 kiteclient/tests/v1/test_esek.py delete mode 100644 kiteclient/tests/v1/test_group.py delete mode 100644 kiteclient/tests/v1/test_key.py delete mode 100644 kiteclient/tests/v1/test_ticket.py delete mode 100644 kiteclient/tests/v1/utils.py delete mode 100644 kiteclient/v1/__init__.py delete mode 100644 kiteclient/v1/esek.py delete mode 100644 kiteclient/v1/group.py delete mode 100644 kiteclient/v1/key.py delete mode 100644 kiteclient/v1/ticket.py delete mode 100644 openstack-common.conf delete mode 100644 requirements.txt delete mode 100644 scripts/basic.py delete mode 100644 scripts/demo-client/client.py delete mode 100644 scripts/demo-client/main.py delete mode 100644 scripts/demo-client/transport.py delete mode 100644 scripts/group.py delete mode 100644 setup.cfg delete mode 100755 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tox.ini diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index f188726..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,16 +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 - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - - http://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/python-kiteclient \ No newline at end of file diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 7b0f78d..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -python-kiteclient Style Commandments -=============================================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 67db858..0000000 --- a/LICENSE +++ /dev/null @@ -1,175 +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/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 90f8a7a..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include AUTHORS -include ChangeLog -exclude .gitignore -exclude .gitreview - -global-exclude *.pyc \ No newline at end of file diff --git a/README.rst b/README.rst index 75d457f..b0f418c 100644 --- a/README.rst +++ b/README.rst @@ -1,15 +1,8 @@ -=============================== -python-kiteclient -=============================== +This project is no longer maintained. -A client library for interacting with the Kite secure message service. +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". -* Free software: Apache license -* Documentation: http://docs.openstack.org/developer/python-kiteclient -* Source: http://git.openstack.org/cgit/openstack/python-kiteclient -* Bugs: http://bugs.launchpad.net/python-kiteclient - -Features --------- - -* TODO +http://lists.openstack.org/pipermail/openstack-dev/2016-March/090409.html diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index efceab8..0000000 --- a/babel.cfg +++ /dev/null @@ -1 +0,0 @@ -[python: **.py] diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index 386608b..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,75 +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', - 'oslosphinx' -] - -# 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'python-kiteclient' -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 = '_theme' -# 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/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 8cb3146..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../CONTRIBUTING.rst \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index c546b34..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. python-kiteclient documentation master file, created by - sphinx-quickstart on Tue Jul 9 22:26:36 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to python-kiteclient's documentation! -======================================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - readme - installation - usage - contributing - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index 0e59c2e..0000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,12 +0,0 @@ -============ -Installation -============ - -At the command line:: - - $ pip install python-kiteclient - -Or, if you have virtualenvwrapper installed:: - - $ mkvirtualenv python-kiteclient - $ pip install python-kiteclient \ No newline at end of file diff --git a/doc/source/readme.rst b/doc/source/readme.rst deleted file mode 100644 index a6210d3..0000000 --- a/doc/source/readme.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../README.rst diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index 5de5b88..0000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,7 +0,0 @@ -======== -Usage -======== - -To use python-kiteclient in a project:: - - import kiteclient \ No newline at end of file diff --git a/kiteclient/__init__.py b/kiteclient/__init__.py deleted file mode 100644 index f2b0dc0..0000000 --- a/kiteclient/__init__.py +++ /dev/null @@ -1,19 +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 pbr.version - - -__version__ = pbr.version.VersionInfo( - 'kiteclient').version_string() diff --git a/kiteclient/cli/__init__.py b/kiteclient/cli/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kiteclient/cli/v1.py b/kiteclient/cli/v1.py deleted file mode 100644 index cfab022..0000000 --- a/kiteclient/cli/v1.py +++ /dev/null @@ -1,159 +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. - -"KDS Client" - -import logging -import os - -from cliff import command -from cliff import show -from keystoneclient.auth.identity import v2 as v2_auth -from keystoneclient.auth import token_endpoint -from keystoneclient import session -from openstackclient.common import utils - -from kiteclient import v1 - -LOG = logging.getLogger(__name__) - -DEFAULT_KDS_API_VERSION = '1' -API_VERSION_OPTION = 'os_kds_api_version' -API_NAME = 'kds' -API_VERSIONS = { - '1': 'kiteclient.cli.v1.Client' -} - - -def make_client(instance): - client_class = utils.get_client_class(API_NAME, - instance._api_version[API_NAME], - API_VERSIONS) - LOG.debug('instantiating KDS client: %s' % client_class) - - s = session.Session.construct({'verify': instance._verify, - 'cacert': instance._cacert, - 'insecure': instance._insecure}) - - if instance._url: - s.auth = token_endpoint.Token(instance._url, instance._token) - else: - s.auth = v2_auth.Password(instance._auth_url, - instance._username, - instance._password, - tenant_id=instance._project_id, - tenant_name=instance._project_name) - - return client_class(s) - - -def build_option_parser(parser): - parser.add_argument( - '--os-kds-api-version', - metavar='', - default=os.getenv('OS_KDS_API_VERSION', DEFAULT_KDS_API_VERSION), - help='KDS API version, default=%s (Env: OS_KDS_API_VERSION)' % - DEFAULT_KDS_API_VERSION) - return parser - - -class Client(object): - - log = logging.getLogger(__name__ + '.Client') - - def __init__(self, sess): - self.session = sess - - def set_key(self, name, key_data): - if key_data: - key = v1.Key(name, key_data, self.session) - else: - key = v1.Key.generate(name, self.session) - - return key.key_name, key.generation, key.b64_key - - def create_group(self, name): - # TODO(tkelsey): implement this when KDS group work is done. - self.log.warn("create_group not implemented") - raise NotImplementedError - - def delete_group(self, name): - # TODO(tkelsey): implement this when KDS group work is done. - self.log.warn("delete_group not implemented") - raise NotImplementedError - - -class KeySet(show.ShowOne): - """Set a messaging symmetric key in the KDS.""" - - log = logging.getLogger(__name__ + '.KeySet') - columns = ('Name', 'Generation', 'Key') - - def get_parser(self, prog_name): - parser = super(KeySet, self).get_parser(prog_name) - parser.add_argument('name', - metavar='', - help='Name of host') - parser.add_argument('key', - nargs='?', - metavar='', - help='Base64 key to set') - return parser - - def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - - kds_client = self.app.client_manager.kds - data = kds_client.set_key(parsed_args.name, parsed_args.key) - - return self.columns, data - - -class GroupCreate(show.ShowOne): - """Create a Group in the KDS.""" - - log = logging.getLogger(__name__ + '.GroupCreate') - columns = ('Name',) - - def get_parser(self, prog_name): - parser = super(GroupCreate, self).get_parser(prog_name) - parser.add_argument('name', - metavar='', - help='Name of the Group to create') - return parser - - def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - - kds_client = self.app.client_manager.kds - data = kds_client.create_group(parsed_args.name) - - return self.columns, (data, ) - - -class GroupDelete(command.Command): - """Delete a Group from the KDS.""" - - log = logging.getLogger(__name__ + '.GroupDelete') - - def get_parser(self, prog_name): - parser = super(GroupDelete, self).get_parser(prog_name) - parser.add_argument('name', - metavar='', - help='Name of the Group to delete') - return parser - - def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - - kds_client = self.app.client_manager.kds - kds_client.delete_group(parsed_args.name) \ No newline at end of file diff --git a/kiteclient/common/__init__.py b/kiteclient/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kiteclient/common/meta_data.py b/kiteclient/common/meta_data.py deleted file mode 100644 index bf3bf43..0000000 --- a/kiteclient/common/meta_data.py +++ /dev/null @@ -1,43 +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. - -import base64 -import struct - -from Crypto import Random -import six - -from kiteclient.openstack.common import jsonutils -from kiteclient.openstack.common import timeutils - - -class Metadata(object): - - def __init__(self, source, destination, timestamp=None, nonce=None): - self.source = source - self.destination = destination - self.timestamp = timestamp or timeutils.utcnow() - self.nonce = nonce or self.gen_nonce() - - @classmethod - def gen_nonce(cls): - return struct.unpack('Q', Random.new().read(8))[0] - - def get_data(self): - return {'source': self.source, - 'destination': self.destination, - 'timestamp': timeutils.strtime(self.timestamp), - 'nonce': self.nonce} - - def encode(self): - data = self.get_data() - return base64.b64encode(six.b(jsonutils.dumps(data))) diff --git a/kiteclient/common/resource.py b/kiteclient/common/resource.py deleted file mode 100644 index d76a7e1..0000000 --- a/kiteclient/common/resource.py +++ /dev/null @@ -1,57 +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. - -from kiteclient.common import utils - - -class Resource(object): - - base_path = None - - @classmethod - def _http_request(cls, session, method, path=None, **kwargs): - headers = kwargs.setdefault('headers', {}) - headers['Accept'] = 'application/json' - - endpoint_filter = kwargs.setdefault('endpoint_filter', {}) - endpoint_filter.setdefault('service_type', 'kds') - - if path: - path = utils.urljoin(cls.base_path, path) - else: - path = cls.base_path - - return session.request(path, method, **kwargs) - - @classmethod - def _http_get(cls, session, *args, **kwargs): - return cls._http_request(session, 'GET', *args, **kwargs) - - @classmethod - def _http_post(cls, session, *args, **kwargs): - return cls._http_request(session, 'POST', *args, **kwargs) - - @classmethod - def _http_put(cls, session, *args, **kwargs): - return cls._http_request(session, 'PUT', *args, **kwargs) - - @classmethod - def _http_patch(cls, session, *args, **kwargs): - return cls._http_request(session, 'PATCH', *args, **kwargs) - - @classmethod - def _http_delete(cls, session, *args, **kwargs): - return cls._http_request(session, 'DELETE', *args, **kwargs) - - @classmethod - def _http_head(cls, session, *args, **kwargs): - return cls._http_request(session, 'HEAD', *args, **kwargs) diff --git a/kiteclient/common/utils.py b/kiteclient/common/utils.py deleted file mode 100644 index 26f1fa1..0000000 --- a/kiteclient/common/utils.py +++ /dev/null @@ -1,21 +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. - - -def urljoin(*args): - """A custom version of urljoin that simply joins strings into a path. - - The real urljoin takes into account web semantics like when joining a url - like /path this should be joined to http://host/path as it is an anchored - link. We generally won't care about that in client. - """ - return '/'.join(str(a).strip('/') for a in args) diff --git a/kiteclient/openstack/__init__.py b/kiteclient/openstack/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kiteclient/openstack/common/__init__.py b/kiteclient/openstack/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kiteclient/openstack/common/_i18n.py b/kiteclient/openstack/common/_i18n.py deleted file mode 100644 index 211c930..0000000 --- a/kiteclient/openstack/common/_i18n.py +++ /dev/null @@ -1,45 +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 http://docs.openstack.org/developer/oslo.i18n/usage.html - -""" - -try: - import oslo_i18n - - # NOTE(dhellmann): This reference to o-s-l-o will be replaced by the - # application name when this module is synced into the separate - # repository. It is OK to have more than one translation function - # using the same domain, since there will still only be one message - # catalog. - _translators = oslo_i18n.TranslatorFactory(domain='kiteclient') - - # The primary translation function using the well-known name "_" - _ = _translators.primary - - # Translators for log levels. - # - # The abbreviated names are meant to reflect the usual use of a short - # name like '_'. The "L" is for "log" and the other letter comes from - # the level. - _LI = _translators.log_info - _LW = _translators.log_warning - _LE = _translators.log_error - _LC = _translators.log_critical -except ImportError: - # NOTE(dims): Support for cases where a project wants to use - # code from oslo-incubator, but is not ready to be internationalized - # (like tempest) - _ = _LI = _LW = _LE = _LC = lambda x: x diff --git a/kiteclient/openstack/common/crypto/__init__.py b/kiteclient/openstack/common/crypto/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kiteclient/openstack/common/crypto/utils.py b/kiteclient/openstack/common/crypto/utils.py deleted file mode 100644 index 2d42c17..0000000 --- a/kiteclient/openstack/common/crypto/utils.py +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright 2013 Red Hat, 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. - -######################################################################## -# -# THIS MODULE IS DEPRECATED -# -# Please refer to -# https://etherpad.openstack.org/p/kilo-kiteclient-library-proposals for -# the discussion leading to this deprecation. -# -# We recommend checking out Barbican or the cryptography.py project -# (https://pypi.python.org/pypi/cryptography) instead of this module. -# -######################################################################## - -import base64 - -from Crypto.Hash import HMAC -from Crypto import Random -from oslo_utils import importutils -import six - -from kiteclient.openstack.common._i18n import _ - -bchr = six.int2byte - - -class CryptoutilsException(Exception): - """Generic Exception for Crypto utilities.""" - - message = _("An unknown error occurred in crypto utils.") - - -class CipherBlockLengthTooBig(CryptoutilsException): - """The block size is too big.""" - - def __init__(self, requested, permitted): - msg = _("Block size of %(given)d is too big, max = %(maximum)d") - message = msg % {'given': requested, 'maximum': permitted} - super(CryptoutilsException, self).__init__(message) - - -class HKDFOutputLengthTooLong(CryptoutilsException): - """The amount of Key Material asked is too much.""" - - def __init__(self, requested, permitted): - msg = _("Length of %(given)d is too long, max = %(maximum)d") - message = msg % {'given': requested, 'maximum': permitted} - super(CryptoutilsException, self).__init__(message) - - -class HKDF(object): - """An HMAC-based Key Derivation Function implementation (RFC5869) - - This class creates an object that allows to use HKDF to derive keys. - """ - - def __init__(self, hashtype='SHA256'): - self.hashfn = importutils.import_module('Crypto.Hash.' + hashtype) - self.max_okm_length = 255 * self.hashfn.digest_size - - def extract(self, ikm, salt=None): - """An extract function that can be used to derive a robust key given - weak Input Key Material (IKM) which could be a password. - Returns a pseudorandom key (of HashLen octets) - - :param ikm: input keying material (ex a password) - :param salt: optional salt value (a non-secret random value) - """ - if salt is None: - salt = b'\x00' * self.hashfn.digest_size - - return HMAC.new(salt, ikm, self.hashfn).digest() - - def expand(self, prk, info, length): - """An expand function that will return arbitrary length output that can - be used as keys. - Returns a buffer usable as key material. - - :param prk: a pseudorandom key of at least HashLen octets - :param info: optional string (can be a zero-length string) - :param length: length of output keying material (<= 255 * HashLen) - """ - if length > self.max_okm_length: - raise HKDFOutputLengthTooLong(length, self.max_okm_length) - - N = (length + self.hashfn.digest_size - 1) // self.hashfn.digest_size - - okm = b"" - tmp = b"" - for block in range(1, N + 1): - tmp = HMAC.new(prk, tmp + info + bchr(block), self.hashfn).digest() - okm += tmp - - return okm[:length] - - -MAX_CB_SIZE = 256 - - -class SymmetricCrypto(object): - """Symmetric Key Crypto object. - - This class creates a Symmetric Key Crypto object that can be used - to encrypt, decrypt, or sign arbitrary data. - - :param enctype: Encryption Cipher name (default: AES) - :param hashtype: Hash/HMAC type name (default: SHA256) - """ - - def __init__(self, enctype='AES', hashtype='SHA256'): - self.cipher = importutils.import_module('Crypto.Cipher.' + enctype) - self.hashfn = importutils.import_module('Crypto.Hash.' + hashtype) - - def new_key(self, size): - return Random.new().read(size) - - def encrypt(self, key, msg, b64encode=True): - """Encrypt the provided msg and returns the cyphertext optionally - base64 encoded. - - Uses AES-128-CBC with a Random IV by default. - - The plaintext is padded to reach blocksize length. - The last byte of the block is the length of the padding. - The length of the padding does not include the length byte itself. - - :param key: The Encryption key. - :param msg: the plain text. - - :returns enc: a block of encrypted data. - """ - iv = Random.new().read(self.cipher.block_size) - cipher = self.cipher.new(key, self.cipher.MODE_CBC, iv) - - # CBC mode requires a fixed block size. Append padding and length of - # padding. - if self.cipher.block_size > MAX_CB_SIZE: - raise CipherBlockLengthTooBig(self.cipher.block_size, MAX_CB_SIZE) - r = len(msg) % self.cipher.block_size - padlen = self.cipher.block_size - r - 1 - msg += b'\x00' * padlen - msg += bchr(padlen) - - enc = iv + cipher.encrypt(msg) - if b64encode: - enc = base64.b64encode(enc) - return enc - - def decrypt(self, key, msg, b64decode=True): - """Decrypts the provided ciphertext, optionally base64 encoded, and - returns the plaintext message, after padding is removed. - - Uses AES-128-CBC with an IV by default. - - :param key: The Encryption key. - :param msg: the ciphetext, the first block is the IV - - :returns plain: the plaintext message. - """ - if b64decode: - msg = base64.b64decode(msg) - iv = msg[:self.cipher.block_size] - cipher = self.cipher.new(key, self.cipher.MODE_CBC, iv) - - padded = cipher.decrypt(msg[self.cipher.block_size:]) - l = ord(padded[-1:]) + 1 - plain = padded[:-l] - return plain - - def sign(self, key, msg, b64encode=True): - """Signs a message string and returns a base64 encoded signature. - - Uses HMAC-SHA-256 by default. - - :param key: The Signing key. - :param msg: the message to sign. - - :returns out: a base64 encoded signature. - """ - h = HMAC.new(key, msg, self.hashfn) - out = h.digest() - if b64encode: - out = base64.b64encode(out) - return out diff --git a/kiteclient/openstack/common/gettextutils.py b/kiteclient/openstack/common/gettextutils.py deleted file mode 100644 index 4c88c10..0000000 --- a/kiteclient/openstack/common/gettextutils.py +++ /dev/null @@ -1,498 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# 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. - -""" -gettext for openstack-common modules. - -Usual usage in an openstack.common module: - - from kiteclient.openstack.common.gettextutils import _ -""" - -import copy -import functools -import gettext -import locale -from logging import handlers -import os - -from babel import localedata -import six - -_AVAILABLE_LANGUAGES = {} - -# FIXME(dhellmann): Remove this when moving to oslo.i18n. -USE_LAZY = False - - -class TranslatorFactory(object): - """Create translator functions - """ - - def __init__(self, domain, lazy=False, localedir=None): - """Establish a set of translation functions for the domain. - - :param domain: Name of translation domain, - specifying a message catalog. - :type domain: str - :param lazy: Delays translation until a message is emitted. - Defaults to False. - :type lazy: Boolean - :param localedir: Directory with translation catalogs. - :type localedir: str - """ - self.domain = domain - self.lazy = lazy - if localedir is None: - localedir = os.environ.get(domain.upper() + '_LOCALEDIR') - self.localedir = localedir - - def _make_translation_func(self, domain=None): - """Return a new translation function ready for use. - - Takes into account whether or not lazy translation is being - done. - - The domain can be specified to override the default from the - factory, but the localedir from the factory is always used - because we assume the log-level translation catalogs are - installed in the same directory as the main application - catalog. - - """ - if domain is None: - domain = self.domain - if self.lazy: - return functools.partial(Message, domain=domain) - t = gettext.translation( - domain, - localedir=self.localedir, - fallback=True, - ) - if six.PY3: - return t.gettext - return t.ugettext - - @property - def primary(self): - "The default translation function." - return self._make_translation_func() - - def _make_log_translation_func(self, level): - return self._make_translation_func(self.domain + '-log-' + level) - - @property - def log_info(self): - "Translate info-level log messages." - return self._make_log_translation_func('info') - - @property - def log_warning(self): - "Translate warning-level log messages." - return self._make_log_translation_func('warning') - - @property - def log_error(self): - "Translate error-level log messages." - return self._make_log_translation_func('error') - - @property - def log_critical(self): - "Translate critical-level log messages." - return self._make_log_translation_func('critical') - - -# NOTE(dhellmann): When this module moves out of the incubator into -# oslo.i18n, these global variables can be moved to an integration -# module within each application. - -# Create the global translation functions. -_translators = TranslatorFactory('kiteclient') - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical - -# NOTE(dhellmann): End of globals that will move to the application's -# integration module. - - -def enable_lazy(): - """Convenience function for configuring _() to use lazy gettext - - Call this at the start of execution to enable the gettextutils._ - function to use lazy gettext functionality. This is useful if - your project is importing _ directly instead of using the - gettextutils.install() way of importing the _ function. - """ - # FIXME(dhellmann): This function will be removed in oslo.i18n, - # because the TranslatorFactory makes it superfluous. - global _, _LI, _LW, _LE, _LC, USE_LAZY - tf = TranslatorFactory('kiteclient', lazy=True) - _ = tf.primary - _LI = tf.log_info - _LW = tf.log_warning - _LE = tf.log_error - _LC = tf.log_critical - USE_LAZY = True - - -def install(domain, lazy=False): - """Install a _() function using the given translation domain. - - Given a translation domain, install a _() function using gettext's - install() function. - - The main difference from gettext.install() is that we allow - overriding the default localedir (e.g. /usr/share/locale) using - a translation-domain-specific environment variable (e.g. - NOVA_LOCALEDIR). - - :param domain: the translation domain - :param lazy: indicates whether or not to install the lazy _() function. - The lazy _() introduces a way to do deferred translation - of messages by installing a _ that builds Message objects, - instead of strings, which can then be lazily translated into - any available locale. - """ - if lazy: - from six import moves - tf = TranslatorFactory(domain, lazy=True) - moves.builtins.__dict__['_'] = tf.primary - else: - localedir = '%s_LOCALEDIR' % domain.upper() - if six.PY3: - gettext.install(domain, - localedir=os.environ.get(localedir)) - else: - gettext.install(domain, - localedir=os.environ.get(localedir), - unicode=True) - - -class Message(six.text_type): - """A Message object is a unicode object that can be translated. - - Translation of Message is done explicitly using the translate() method. - For all non-translation intents and purposes, a Message is simply unicode, - and can be treated as such. - """ - - def __new__(cls, msgid, msgtext=None, params=None, - domain='kiteclient', *args): - """Create a new Message object. - - In order for translation to work gettext requires a message ID, this - msgid will be used as the base unicode text. It is also possible - for the msgid and the base unicode text to be different by passing - the msgtext parameter. - """ - # If the base msgtext is not given, we use the default translation - # of the msgid (which is in English) just in case the system locale is - # not English, so that the base text will be in that locale by default. - if not msgtext: - msgtext = Message._translate_msgid(msgid, domain) - # We want to initialize the parent unicode with the actual object that - # would have been plain unicode if 'Message' was not enabled. - msg = super(Message, cls).__new__(cls, msgtext) - msg.msgid = msgid - msg.domain = domain - msg.params = params - return msg - - def translate(self, desired_locale=None): - """Translate this message to the desired locale. - - :param desired_locale: The desired locale to translate the message to, - if no locale is provided the message will be - translated to the system's default locale. - - :returns: the translated message in unicode - """ - - translated_message = Message._translate_msgid(self.msgid, - self.domain, - desired_locale) - if self.params is None: - # No need for more translation - return translated_message - - # This Message object may have been formatted with one or more - # Message objects as substitution arguments, given either as a single - # argument, part of a tuple, or as one or more values in a dictionary. - # When translating this Message we need to translate those Messages too - translated_params = _translate_args(self.params, desired_locale) - - translated_message = translated_message % translated_params - - return translated_message - - @staticmethod - def _translate_msgid(msgid, domain, desired_locale=None): - if not desired_locale: - system_locale = locale.getdefaultlocale() - # If the system locale is not available to the runtime use English - if not system_locale[0]: - desired_locale = 'en_US' - else: - desired_locale = system_locale[0] - - locale_dir = os.environ.get(domain.upper() + '_LOCALEDIR') - lang = gettext.translation(domain, - localedir=locale_dir, - languages=[desired_locale], - fallback=True) - if six.PY3: - translator = lang.gettext - else: - translator = lang.ugettext - - translated_message = translator(msgid) - return translated_message - - def __mod__(self, other): - # When we mod a Message we want the actual operation to be performed - # by the parent class (i.e. unicode()), the only thing we do here is - # save the original msgid and the parameters in case of a translation - params = self._sanitize_mod_params(other) - unicode_mod = super(Message, self).__mod__(params) - modded = Message(self.msgid, - msgtext=unicode_mod, - params=params, - domain=self.domain) - return modded - - def _sanitize_mod_params(self, other): - """Sanitize the object being modded with this Message. - - - Add support for modding 'None' so translation supports it - - Trim the modded object, which can be a large dictionary, to only - those keys that would actually be used in a translation - - Snapshot the object being modded, in case the message is - translated, it will be used as it was when the Message was created - """ - if other is None: - params = (other,) - elif isinstance(other, dict): - # Merge the dictionaries - # Copy each item in case one does not support deep copy. - params = {} - if isinstance(self.params, dict): - for key, val in self.params.items(): - params[key] = self._copy_param(val) - for key, val in other.items(): - params[key] = self._copy_param(val) - else: - params = self._copy_param(other) - return params - - def _copy_param(self, param): - try: - return copy.deepcopy(param) - except Exception: - # Fallback to casting to unicode this will handle the - # python code-like objects that can't be deep-copied - return six.text_type(param) - - def __add__(self, other): - msg = _('Message objects do not support addition.') - raise TypeError(msg) - - def __radd__(self, other): - return self.__add__(other) - - if six.PY2: - def __str__(self): - # NOTE(luisg): Logging in python 2.6 tries to str() log records, - # and it expects specifically a UnicodeError in order to proceed. - msg = _('Message objects do not support str() because they may ' - 'contain non-ascii characters. ' - 'Please use unicode() or translate() instead.') - raise UnicodeError(msg) - - -def get_available_languages(domain): - """Lists the available languages for the given translation domain. - - :param domain: the domain to get languages for - """ - if domain in _AVAILABLE_LANGUAGES: - return copy.copy(_AVAILABLE_LANGUAGES[domain]) - - localedir = '%s_LOCALEDIR' % domain.upper() - find = lambda x: gettext.find(domain, - localedir=os.environ.get(localedir), - languages=[x]) - - # NOTE(mrodden): en_US should always be available (and first in case - # order matters) since our in-line message strings are en_US - language_list = ['en_US'] - # NOTE(luisg): Babel <1.0 used a function called list(), which was - # renamed to locale_identifiers() in >=1.0, the requirements master list - # requires >=0.9.6, uncapped, so defensively work with both. We can remove - # this check when the master list updates to >=1.0, and update all projects - list_identifiers = (getattr(localedata, 'list', None) or - getattr(localedata, 'locale_identifiers')) - locale_identifiers = list_identifiers() - - for i in locale_identifiers: - if find(i) is not None: - language_list.append(i) - - # NOTE(luisg): Babel>=1.0,<1.3 has a bug where some OpenStack supported - # locales (e.g. 'zh_CN', and 'zh_TW') aren't supported even though they - # are perfectly legitimate locales: - # https://github.com/mitsuhiko/babel/issues/37 - # In Babel 1.3 they fixed the bug and they support these locales, but - # they are still not explicitly "listed" by locale_identifiers(). - # That is why we add the locales here explicitly if necessary so that - # they are listed as supported. - aliases = {'zh': 'zh_CN', - 'zh_Hant_HK': 'zh_HK', - 'zh_Hant': 'zh_TW', - 'fil': 'tl_PH'} - for (locale_, alias) in six.iteritems(aliases): - if locale_ in language_list and alias not in language_list: - language_list.append(alias) - - _AVAILABLE_LANGUAGES[domain] = language_list - return copy.copy(language_list) - - -def translate(obj, desired_locale=None): - """Gets the translated unicode representation of the given object. - - If the object is not translatable it is returned as-is. - If the locale is None the object is translated to the system locale. - - :param obj: the object to translate - :param desired_locale: the locale to translate the message to, if None the - default system locale will be used - :returns: the translated object in unicode, or the original object if - it could not be translated - """ - message = obj - if not isinstance(message, Message): - # If the object to translate is not already translatable, - # let's first get its unicode representation - message = six.text_type(obj) - if isinstance(message, Message): - # Even after unicoding() we still need to check if we are - # running with translatable unicode before translating - return message.translate(desired_locale) - return obj - - -def _translate_args(args, desired_locale=None): - """Translates all the translatable elements of the given arguments object. - - This method is used for translating the translatable values in method - arguments which include values of tuples or dictionaries. - If the object is not a tuple or a dictionary the object itself is - translated if it is translatable. - - If the locale is None the object is translated to the system locale. - - :param args: the args to translate - :param desired_locale: the locale to translate the args to, if None the - default system locale will be used - :returns: a new args object with the translated contents of the original - """ - if isinstance(args, tuple): - return tuple(translate(v, desired_locale) for v in args) - if isinstance(args, dict): - translated_dict = {} - for (k, v) in six.iteritems(args): - translated_v = translate(v, desired_locale) - translated_dict[k] = translated_v - return translated_dict - return translate(args, desired_locale) - - -class TranslationHandler(handlers.MemoryHandler): - """Handler that translates records before logging them. - - The TranslationHandler takes a locale and a target logging.Handler object - to forward LogRecord objects to after translating them. This handler - depends on Message objects being logged, instead of regular strings. - - The handler can be configured declaratively in the logging.conf as follows: - - [handlers] - keys = translatedlog, translator - - [handler_translatedlog] - class = handlers.WatchedFileHandler - args = ('/var/log/api-localized.log',) - formatter = context - - [handler_translator] - class = openstack.common.log.TranslationHandler - target = translatedlog - args = ('zh_CN',) - - If the specified locale is not available in the system, the handler will - log in the default locale. - """ - - def __init__(self, locale=None, target=None): - """Initialize a TranslationHandler - - :param locale: locale to use for translating messages - :param target: logging.Handler object to forward - LogRecord objects to after translation - """ - # NOTE(luisg): In order to allow this handler to be a wrapper for - # other handlers, such as a FileHandler, and still be able to - # configure it using logging.conf, this handler has to extend - # MemoryHandler because only the MemoryHandlers' logging.conf - # parsing is implemented such that it accepts a target handler. - handlers.MemoryHandler.__init__(self, capacity=0, target=target) - self.locale = locale - - def setFormatter(self, fmt): - self.target.setFormatter(fmt) - - def emit(self, record): - # We save the message from the original record to restore it - # after translation, so other handlers are not affected by this - original_msg = record.msg - original_args = record.args - - try: - self._translate_and_log_record(record) - finally: - record.msg = original_msg - record.args = original_args - - def _translate_and_log_record(self, record): - record.msg = translate(record.msg, self.locale) - - # In addition to translating the message, we also need to translate - # arguments that were passed to the log method that were not part - # of the main message e.g., log.info(_('Some message %s'), this_one)) - record.args = _translate_args(record.args, self.locale) - - self.target.emit(record) diff --git a/kiteclient/openstack/common/importutils.py b/kiteclient/openstack/common/importutils.py deleted file mode 100644 index 816c19c..0000000 --- a/kiteclient/openstack/common/importutils.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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 related utilities and helper functions. -""" - -import sys -import traceback - - -def import_class(import_str): - """Returns a class from a string including module and class.""" - mod_str, _sep, class_str = import_str.rpartition('.') - __import__(mod_str) - try: - return getattr(sys.modules[mod_str], class_str) - except AttributeError: - raise ImportError('Class %s cannot be found (%s)' % - (class_str, - traceback.format_exception(*sys.exc_info()))) - - -def import_object(import_str, *args, **kwargs): - """Import a class and return an instance of it.""" - return import_class(import_str)(*args, **kwargs) - - -def import_object_ns(name_space, import_str, *args, **kwargs): - """Tries to import object from default namespace. - - Imports a class and return an instance of it, first by trying - to find the class in a default namespace, then failing back to - a full path if not found in the default namespace. - """ - import_value = "%s.%s" % (name_space, import_str) - try: - return import_class(import_value)(*args, **kwargs) - except ImportError: - return import_class(import_str)(*args, **kwargs) - - -def import_module(import_str): - """Import a module.""" - __import__(import_str) - return sys.modules[import_str] - - -def import_versioned_module(version, submodule=None): - module = 'kiteclient.v%s' % version - if submodule: - module = '.'.join((module, submodule)) - return import_module(module) - - -def try_import(import_str, default=None): - """Try to import a module and if it fails return default.""" - try: - return import_module(import_str) - except ImportError: - return default diff --git a/kiteclient/openstack/common/jsonutils.py b/kiteclient/openstack/common/jsonutils.py deleted file mode 100644 index 713c1db..0000000 --- a/kiteclient/openstack/common/jsonutils.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# Copyright 2011 Justin Santa Barbara -# All Rights Reserved. -# -# 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. - -''' -JSON related utilities. - -This module provides a few things: - - 1) A handy function for getting an object down to something that can be - JSON serialized. See to_primitive(). - - 2) Wrappers around loads() and dumps(). The dumps() wrapper will - automatically use to_primitive() for you if needed. - - 3) This sets up anyjson to use the loads() and dumps() wrappers if anyjson - is available. -''' - - -import codecs -import datetime -import functools -import inspect -import itertools -import sys - -if sys.version_info < (2, 7): - # On Python <= 2.6, json module is not C boosted, so try to use - # simplejson module if available - try: - import simplejson as json - except ImportError: - import json -else: - import json - -import six -import six.moves.xmlrpc_client as xmlrpclib - -from kiteclient.openstack.common import gettextutils -from kiteclient.openstack.common import importutils -from kiteclient.openstack.common import strutils -from kiteclient.openstack.common import timeutils - -netaddr = importutils.try_import("netaddr") - -_nasty_type_tests = [inspect.ismodule, inspect.isclass, inspect.ismethod, - inspect.isfunction, inspect.isgeneratorfunction, - inspect.isgenerator, inspect.istraceback, inspect.isframe, - inspect.iscode, inspect.isbuiltin, inspect.isroutine, - inspect.isabstract] - -_simple_types = (six.string_types + six.integer_types - + (type(None), bool, float)) - - -def to_primitive(value, convert_instances=False, convert_datetime=True, - level=0, max_depth=3): - """Convert a complex object into primitives. - - Handy for JSON serialization. We can optionally handle instances, - but since this is a recursive function, we could have cyclical - data structures. - - To handle cyclical data structures we could track the actual objects - visited in a set, but not all objects are hashable. Instead we just - track the depth of the object inspections and don't go too deep. - - Therefore, convert_instances=True is lossy ... be aware. - - """ - # handle obvious types first - order of basic types determined by running - # full tests on nova project, resulting in the following counts: - # 572754 - # 460353 - # 379632 - # 274610 - # 199918 - # 114200 - # 51817 - # 26164 - # 6491 - # 283 - # 19 - if isinstance(value, _simple_types): - return value - - if isinstance(value, datetime.datetime): - if convert_datetime: - return timeutils.strtime(value) - else: - return value - - # value of itertools.count doesn't get caught by nasty_type_tests - # and results in infinite loop when list(value) is called. - if type(value) == itertools.count: - return six.text_type(value) - - # FIXME(vish): Workaround for LP bug 852095. Without this workaround, - # tests that raise an exception in a mocked method that - # has a @wrap_exception with a notifier will fail. If - # we up the dependency to 0.5.4 (when it is released) we - # can remove this workaround. - if getattr(value, '__module__', None) == 'mox': - return 'mock' - - if level > max_depth: - return '?' - - # The try block may not be necessary after the class check above, - # but just in case ... - try: - recursive = functools.partial(to_primitive, - convert_instances=convert_instances, - convert_datetime=convert_datetime, - level=level, - max_depth=max_depth) - if isinstance(value, dict): - return dict((k, recursive(v)) for k, v in six.iteritems(value)) - elif isinstance(value, (list, tuple)): - return [recursive(lv) for lv in value] - - # It's not clear why xmlrpclib created their own DateTime type, but - # for our purposes, make it a datetime type which is explicitly - # handled - if isinstance(value, xmlrpclib.DateTime): - value = datetime.datetime(*tuple(value.timetuple())[:6]) - - if convert_datetime and isinstance(value, datetime.datetime): - return timeutils.strtime(value) - elif isinstance(value, gettextutils.Message): - return value.data - elif hasattr(value, 'iteritems'): - return recursive(dict(value.iteritems()), level=level + 1) - elif hasattr(value, '__iter__'): - return recursive(list(value)) - elif convert_instances and hasattr(value, '__dict__'): - # Likely an instance of something. Watch for cycles. - # Ignore class member vars. - return recursive(value.__dict__, level=level + 1) - elif netaddr and isinstance(value, netaddr.IPAddress): - return six.text_type(value) - else: - if any(test(value) for test in _nasty_type_tests): - return six.text_type(value) - return value - except TypeError: - # Class objects are tricky since they may define something like - # __iter__ defined but it isn't callable as list(). - return six.text_type(value) - - -def dumps(value, default=to_primitive, **kwargs): - return json.dumps(value, default=default, **kwargs) - - -def loads(s, encoding='utf-8', **kwargs): - return json.loads(strutils.safe_decode(s, encoding), **kwargs) - - -def load(fp, encoding='utf-8', **kwargs): - return json.load(codecs.getreader(encoding)(fp), **kwargs) - - -try: - import anyjson -except ImportError: - pass -else: - anyjson._modules.append((__name__, 'dumps', TypeError, - 'loads', ValueError, 'load')) - anyjson.force_implementation(__name__) diff --git a/kiteclient/openstack/common/strutils.py b/kiteclient/openstack/common/strutils.py deleted file mode 100644 index 9422f81..0000000 --- a/kiteclient/openstack/common/strutils.py +++ /dev/null @@ -1,239 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -""" -System-level utilities and helper functions. -""" - -import math -import re -import sys -import unicodedata - -import six - -from kiteclient.openstack.common.gettextutils import _ - - -UNIT_PREFIX_EXPONENT = { - 'k': 1, - 'K': 1, - 'Ki': 1, - 'M': 2, - 'Mi': 2, - 'G': 3, - 'Gi': 3, - 'T': 4, - 'Ti': 4, -} -UNIT_SYSTEM_INFO = { - 'IEC': (1024, re.compile(r'(^[-+]?\d*\.?\d+)([KMGT]i?)?(b|bit|B)$')), - 'SI': (1000, re.compile(r'(^[-+]?\d*\.?\d+)([kMGT])?(b|bit|B)$')), -} - -TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes') -FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no') - -SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]") -SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+") - - -def int_from_bool_as_string(subject): - """Interpret a string as a boolean and return either 1 or 0. - - Any string value in: - - ('True', 'true', 'On', 'on', '1') - - is interpreted as a boolean True. - - Useful for JSON-decoded stuff and config file parsing - """ - return bool_from_string(subject) and 1 or 0 - - -def bool_from_string(subject, strict=False, default=False): - """Interpret a string as a boolean. - - A case-insensitive match is performed such that strings matching 't', - 'true', 'on', 'y', 'yes', or '1' are considered True and, when - `strict=False`, anything else returns the value specified by 'default'. - - Useful for JSON-decoded stuff and config file parsing. - - If `strict=True`, unrecognized values, including None, will raise a - ValueError which is useful when parsing values passed in from an API call. - Strings yielding False are 'f', 'false', 'off', 'n', 'no', or '0'. - """ - if not isinstance(subject, six.string_types): - subject = six.text_type(subject) - - lowered = subject.strip().lower() - - if lowered in TRUE_STRINGS: - return True - elif lowered in FALSE_STRINGS: - return False - elif strict: - acceptable = ', '.join( - "'%s'" % s for s in sorted(TRUE_STRINGS + FALSE_STRINGS)) - msg = _("Unrecognized value '%(val)s', acceptable values are:" - " %(acceptable)s") % {'val': subject, - 'acceptable': acceptable} - raise ValueError(msg) - else: - return default - - -def safe_decode(text, incoming=None, errors='strict'): - """Decodes incoming text/bytes string using `incoming` if they're not - already unicode. - - :param incoming: Text's current encoding - :param errors: Errors handling policy. See here for valid - values http://docs.python.org/2/library/codecs.html - :returns: text or a unicode `incoming` encoded - representation of it. - :raises TypeError: If text is not an instance of str - """ - if not isinstance(text, (six.string_types, six.binary_type)): - raise TypeError("%s can't be decoded" % type(text)) - - if isinstance(text, six.text_type): - return text - - if not incoming: - incoming = (sys.stdin.encoding or - sys.getdefaultencoding()) - - try: - return text.decode(incoming, errors) - except UnicodeDecodeError: - # Note(flaper87) If we get here, it means that - # sys.stdin.encoding / sys.getdefaultencoding - # didn't return a suitable encoding to decode - # text. This happens mostly when global LANG - # var is not set correctly and there's no - # default encoding. In this case, most likely - # python will use ASCII or ANSI encoders as - # default encodings but they won't be capable - # of decoding non-ASCII characters. - # - # Also, UTF-8 is being used since it's an ASCII - # extension. - return text.decode('utf-8', errors) - - -def safe_encode(text, incoming=None, - encoding='utf-8', errors='strict'): - """Encodes incoming text/bytes string using `encoding`. - - If incoming is not specified, text is expected to be encoded with - current python's default encoding. (`sys.getdefaultencoding`) - - :param incoming: Text's current encoding - :param encoding: Expected encoding for text (Default UTF-8) - :param errors: Errors handling policy. See here for valid - values http://docs.python.org/2/library/codecs.html - :returns: text or a bytestring `encoding` encoded - representation of it. - :raises TypeError: If text is not an instance of str - """ - if not isinstance(text, (six.string_types, six.binary_type)): - raise TypeError("%s can't be encoded" % type(text)) - - if not incoming: - incoming = (sys.stdin.encoding or - sys.getdefaultencoding()) - - if isinstance(text, six.text_type): - return text.encode(encoding, errors) - elif text and encoding != incoming: - # Decode text before encoding it with `encoding` - text = safe_decode(text, incoming, errors) - return text.encode(encoding, errors) - else: - return text - - -def string_to_bytes(text, unit_system='IEC', return_int=False): - """Converts a string into an float representation of bytes. - - The units supported for IEC :: - - Kb(it), Kib(it), Mb(it), Mib(it), Gb(it), Gib(it), Tb(it), Tib(it) - KB, KiB, MB, MiB, GB, GiB, TB, TiB - - The units supported for SI :: - - kb(it), Mb(it), Gb(it), Tb(it) - kB, MB, GB, TB - - Note that the SI unit system does not support capital letter 'K' - - :param text: String input for bytes size conversion. - :param unit_system: Unit system for byte size conversion. - :param return_int: If True, returns integer representation of text - in bytes. (default: decimal) - :returns: Numerical representation of text in bytes. - :raises ValueError: If text has an invalid value. - - """ - try: - base, reg_ex = UNIT_SYSTEM_INFO[unit_system] - except KeyError: - msg = _('Invalid unit system: "%s"') % unit_system - raise ValueError(msg) - match = reg_ex.match(text) - if match: - magnitude = float(match.group(1)) - unit_prefix = match.group(2) - if match.group(3) in ['b', 'bit']: - magnitude /= 8 - else: - msg = _('Invalid string format: %s') % text - raise ValueError(msg) - if not unit_prefix: - res = magnitude - else: - res = magnitude * pow(base, UNIT_PREFIX_EXPONENT[unit_prefix]) - if return_int: - return int(math.ceil(res)) - return res - - -def to_slug(value, incoming=None, errors="strict"): - """Normalize string. - - Convert to lowercase, remove non-word characters, and convert spaces - to hyphens. - - Inspired by Django's `slugify` filter. - - :param value: Text to slugify - :param incoming: Text's current encoding - :param errors: Errors handling policy. See here for valid - values http://docs.python.org/2/library/codecs.html - :returns: slugified unicode representation of `value` - :raises TypeError: If text is not an instance of str - """ - value = safe_decode(value, incoming, errors) - # NOTE(aababilov): no need to use safe_(encode|decode) here: - # encodings are always "ascii", error handling is always "ignore" - # and types are always known (first: unicode; second: str) - value = unicodedata.normalize("NFKD", value).encode( - "ascii", "ignore").decode("ascii") - value = SLUGIFY_STRIP_RE.sub("", value).strip().lower() - return SLUGIFY_HYPHENATE_RE.sub("-", value) diff --git a/kiteclient/openstack/common/timeutils.py b/kiteclient/openstack/common/timeutils.py deleted file mode 100644 index c48da95..0000000 --- a/kiteclient/openstack/common/timeutils.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright 2011 OpenStack Foundation. -# All Rights Reserved. -# -# 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. - -""" -Time related utilities and helper functions. -""" - -import calendar -import datetime -import time - -import iso8601 -import six - - -# ISO 8601 extended time format with microseconds -_ISO8601_TIME_FORMAT_SUBSECOND = '%Y-%m-%dT%H:%M:%S.%f' -_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' -PERFECT_TIME_FORMAT = _ISO8601_TIME_FORMAT_SUBSECOND - - -def isotime(at=None, subsecond=False): - """Stringify time in ISO 8601 format.""" - if not at: - at = utcnow() - st = at.strftime(_ISO8601_TIME_FORMAT - if not subsecond - else _ISO8601_TIME_FORMAT_SUBSECOND) - tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' - st += ('Z' if tz == 'UTC' else tz) - return st - - -def parse_isotime(timestr): - """Parse time from ISO 8601 format.""" - try: - return iso8601.parse_date(timestr) - except iso8601.ParseError as e: - raise ValueError(six.text_type(e)) - except TypeError as e: - raise ValueError(six.text_type(e)) - - -def strtime(at=None, fmt=PERFECT_TIME_FORMAT): - """Returns formatted utcnow.""" - if not at: - at = utcnow() - return at.strftime(fmt) - - -def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT): - """Turn a formatted time back into a datetime.""" - return datetime.datetime.strptime(timestr, fmt) - - -def normalize_time(timestamp): - """Normalize time in arbitrary timezone to UTC naive object.""" - offset = timestamp.utcoffset() - if offset is None: - return timestamp - return timestamp.replace(tzinfo=None) - offset - - -def is_older_than(before, seconds): - """Return True if before is older than seconds.""" - if isinstance(before, six.string_types): - before = parse_strtime(before).replace(tzinfo=None) - else: - before = before.replace(tzinfo=None) - - return utcnow() - before > datetime.timedelta(seconds=seconds) - - -def is_newer_than(after, seconds): - """Return True if after is newer than seconds.""" - if isinstance(after, six.string_types): - after = parse_strtime(after).replace(tzinfo=None) - else: - after = after.replace(tzinfo=None) - - return after - utcnow() > datetime.timedelta(seconds=seconds) - - -def utcnow_ts(): - """Timestamp version of our utcnow function.""" - if utcnow.override_time is None: - # NOTE(kgriffs): This is several times faster - # than going through calendar.timegm(...) - return int(time.time()) - - return calendar.timegm(utcnow().timetuple()) - - -def utcnow(): - """Overridable version of utils.utcnow.""" - if utcnow.override_time: - try: - return utcnow.override_time.pop(0) - except AttributeError: - return utcnow.override_time - return datetime.datetime.utcnow() - - -def iso8601_from_timestamp(timestamp): - """Returns an iso8601 formatted date from timestamp.""" - return isotime(datetime.datetime.utcfromtimestamp(timestamp)) - - -utcnow.override_time = None - - -def set_time_override(override_time=None): - """Overrides utils.utcnow. - - Make it return a constant time or a list thereof, one at a time. - - :param override_time: datetime instance or list thereof. If not - given, defaults to the current UTC time. - """ - utcnow.override_time = override_time or datetime.datetime.utcnow() - - -def advance_time_delta(timedelta): - """Advance overridden time using a datetime.timedelta.""" - assert utcnow.override_time is not None - try: - for dt in utcnow.override_time: - dt += timedelta - except TypeError: - utcnow.override_time += timedelta - - -def advance_time_seconds(seconds): - """Advance overridden time by seconds.""" - advance_time_delta(datetime.timedelta(0, seconds)) - - -def clear_time_override(): - """Remove the overridden time.""" - utcnow.override_time = None - - -def marshall_now(now=None): - """Make an rpc-safe datetime with microseconds. - - Note: tzinfo is stripped, but not required for relative times. - """ - if not now: - now = utcnow() - return dict(day=now.day, month=now.month, year=now.year, hour=now.hour, - minute=now.minute, second=now.second, - microsecond=now.microsecond) - - -def unmarshall_time(tyme): - """Unmarshall a datetime dict.""" - return datetime.datetime(day=tyme['day'], - month=tyme['month'], - year=tyme['year'], - hour=tyme['hour'], - minute=tyme['minute'], - second=tyme['second'], - microsecond=tyme['microsecond']) - - -def delta_seconds(before, after): - """Return the difference between two timing objects. - - Compute the difference in seconds between two date, time, or - datetime objects (as a float, to microsecond resolution). - """ - delta = after - before - return total_seconds(delta) - - -def total_seconds(delta): - """Return the total seconds of datetime.timedelta object. - - Compute total seconds of datetime.timedelta, datetime.timedelta - doesn't have method total_seconds in Python2.6, calculate it manually. - """ - try: - return delta.total_seconds() - except AttributeError: - return ((delta.days * 24 * 3600) + delta.seconds + - float(delta.microseconds) / (10 ** 6)) - - -def is_soon(dt, window): - """Determines if time is going to happen in the next window seconds. - - :param dt: the time - :param window: minimum seconds to remain to consider the time not soon - - :return: True if expiration is within the given duration - """ - soon = (utcnow() + datetime.timedelta(seconds=window)) - return normalize_time(dt) <= soon diff --git a/kiteclient/tests/__init__.py b/kiteclient/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kiteclient/tests/base.py b/kiteclient/tests/base.py deleted file mode 100644 index 62686f5..0000000 --- a/kiteclient/tests/base.py +++ /dev/null @@ -1,48 +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. - -import os - -import fixtures -import testtools - -_TRUE_VALUES = ('True', 'true', '1', 'yes') - - -class TestCase(testtools.TestCase): - - """Test case base class for all unit tests.""" - - def setUp(self): - """Run before each test method to initialize test environment.""" - - super(TestCase, self).setUp() - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) - except ValueError: - # If timeout value is invalid do not set a timeout. - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - self.useFixture(fixtures.NestedTempfile()) - self.useFixture(fixtures.TempHomeDir()) - - if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES: - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES: - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - - self.log_fixture = self.useFixture(fixtures.FakeLogger()) diff --git a/kiteclient/tests/test_kiteclient.py b/kiteclient/tests/test_kiteclient.py deleted file mode 100644 index 810b3ad..0000000 --- a/kiteclient/tests/test_kiteclient.py +++ /dev/null @@ -1,26 +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. - -""" -test_kiteclient ----------------------------------- - -Tests for `kiteclient` module. -""" - -from kiteclient.tests import base - - -class TestKiteclient(base.TestCase): - - def test_something(self): - pass diff --git a/kiteclient/tests/v1/__init__.py b/kiteclient/tests/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kiteclient/tests/v1/test_esek.py b/kiteclient/tests/v1/test_esek.py deleted file mode 100644 index 5c23b85..0000000 --- a/kiteclient/tests/v1/test_esek.py +++ /dev/null @@ -1,86 +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. - -""" -test_esek ----------------------------------- - -Tests for `esek` module. -""" - -from kiteclient.openstack.common.crypto import utils as cryptoutils -from kiteclient.tests import base -from kiteclient.tests.v1 import utils -from kiteclient.v1 import esek -from kiteclient.v1 import key - -import base64 - -import six - - -class TestEsek(base.TestCase): - - def setUp(self): - super(base.TestCase, self).setUp() - key_ses = utils.DummyKeyResponse(gen=20) - - skey_data = "gTqLlW7x2oyNi3k+9YXTpQ==" - self.srckey = key.Key('testkey', skey_data, session=key_ses) - - dkey_data = "uoUUn/+ZL+hNUwJ0cxTScg==" - self.dstkey = key.Key('destkey', dkey_data, session=key_ses) - - self.skey = "uZnhYaRtzA7QdnDN1hVSWw==" - self.ekey = "fAlG9eGL44ew6q8uTMMKJw==" - - self.esek_data = ( - "LZ6WWNvCot49sEhnwn0Is/xGWYGQF72rCw8emEKHGmZpDcSQ4K0c5Ld0+fmR" - "T8PjzozEzWK97gNJQHZWSAh1JhmvMO+bjkUNlEdepOjTXrIW6QxdNvMY+Bkd" - "dDwrkKga4wZnoGgeMgK+B7cdGsQ8yAPE3vDjbpmIOvHjHXniCUs=") - - def _encrypt(self, data): - crypto = cryptoutils.SymmetricCrypto(enctype='AES', - hashtype='SHA256') - enc = crypto.encrypt(base64.b64decode(self.ekey), - six.b(data), b64encode=True) - sig = crypto.sign(base64.b64decode(self.skey), - six.b(data), b64encode=True) - return enc, sig - - def test_integrity(self): - esek_obj = esek.Esek(self.srckey.key_name, - self.dstkey, - self.esek_data) - b64_sig_key = base64.b64encode(esek_obj.sig_key) - b64_enc_key = base64.b64encode(esek_obj.enc_key) - self.assertEqual(six.b(self.skey), b64_sig_key) - self.assertEqual(six.b(self.ekey), b64_enc_key) - - def test_decryption(self): - esek_obj = esek.Esek(self.srckey.key_name, - self.dstkey, - self.esek_data) - - message = "MESSAGE" - enc, sig = self._encrypt(message) - new_message = esek_obj.decrypt(enc, sig) - self.assertEqual(six.b(message), new_message) - - def test_bad_signature_throws(self): - esek_obj = esek.Esek(self.srckey.key_name, - self.dstkey, - self.esek_data) - message = "MESSAGE" - enc, _ = self._encrypt(message) - sig = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - self.assertRaises(ValueError, esek_obj.decrypt, enc, sig) \ No newline at end of file diff --git a/kiteclient/tests/v1/test_group.py b/kiteclient/tests/v1/test_group.py deleted file mode 100644 index d211141..0000000 --- a/kiteclient/tests/v1/test_group.py +++ /dev/null @@ -1,81 +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. - -""" -test_group ----------------------------------- - -Tests for `group` module. -""" - -from kiteclient.tests import base -from kiteclient.tests.v1 import utils -from kiteclient.v1 import group -from kiteclient.v1 import key - -import base64 -import datetime - -import six - - -class TestTicket(base.TestCase): - - def setUp(self): - super(base.TestCase, self).setUp() - self.nonce = 1062304930675487541 - self.stamp = datetime.datetime(2014, 11, 2, 8, 19, 4, 333230) - - key_ses = utils.DummyKeyResponse(gen=12) - - skey_data = "mIu9E64f0FyJo/BfNCRVGw==" - self.srckey = key.Key('testkeyA', skey_data, session=key_ses) - - self.gkey_signature = ( - "MD2/BRMAlaabYugGkaLXeqrs6RDnKfoDhcJ/2Ty6xco=") - - self.gkey_metadata = ( - "eyJzb3VyY2UiOiAidGVzdGdyb3VwLnRlc3RrZXlBOjEyIiwgImRlc3Rpbm" - "F0aW9uIjogInRlc3Rncm91cDo0IiwgImV4cGlyYXRpb24iOiAiMjAxNC0w" - "OS0xMlQxMzowMjo1Mi44NTk2MTYiLCAiZW5jcnlwdGlvbiI6IHRydWV9") - - self.group_key = ( - "bar6L/o/otlfs+X36x6QW2UZVwAMx/fBOFZhdjB8PtkhZwVd2Z/t7GJ4Ki" - "yB2lgP") - - self.dummy_session = utils.DummyGroupKeyResponse(self.gkey_signature, - self.gkey_metadata, - self.group_key) - - def test_integrity(self): - gkey = group.GroupKey(self.srckey, - "testgroup", - timestamp=self.stamp, - nonce=self.nonce, - session=self.dummy_session) - - # decrypted group key - group_key = six.b("Z6D3jvXWG2Ybg15EfamkEQ==") - - self.assertEqual(group_key, gkey.b64_key) - self.assertEqual(gkey.b64_key, base64.b64encode(gkey.key)) - - def test_bad_signature_throws(self): - bad_signature = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - bad_session = utils.DummyGroupKeyResponse(bad_signature, - self.gkey_metadata, - self.group_key) - self.assertRaises(ValueError, - group.GroupKey, - self.srckey, - "testgroup", - session=bad_session) diff --git a/kiteclient/tests/v1/test_key.py b/kiteclient/tests/v1/test_key.py deleted file mode 100644 index f523ac6..0000000 --- a/kiteclient/tests/v1/test_key.py +++ /dev/null @@ -1,86 +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. - -""" -test_key ----------------------------------- - -Tests for `key` module. -""" - -from kiteclient.tests import base -from kiteclient.tests.v1 import utils -from kiteclient.v1 import key - -import base64 - -import six - - -class TestKey(base.TestCase): - - def setUp(self): - super(base.TestCase, self).setUp() - self.dummy_session = utils.DummyKeyResponse(gen=3) - self.test_key_name = "testkey" - self.test_key_b64key = "uoUUn/+ZL+hNUwJ0cxTScg==" - - def test_createkey_with_session(self): - srckey = key.Key(self.test_key_name, - self.test_key_b64key, - session=self.dummy_session) - - key_id = "%s:%s" % (self.test_key_name, - self.dummy_session.generation) - - self.assertEqual(key_id, srckey.key_name) - self.assertEqual(six.b("uoUUn/+ZL+hNUwJ0cxTScg=="), - base64.b64encode(srckey.key)) - - def test_createkey_with_generation(self): - srckey = key.Key(self.test_key_name, - self.test_key_b64key, - generation=self.dummy_session.generation) - - key_id = "%s:%s" % (self.test_key_name, - self.dummy_session.generation) - - self.assertEqual(key_id, srckey.key_name) - self.assertEqual(six.b("uoUUn/+ZL+hNUwJ0cxTScg=="), - base64.b64encode(srckey.key)) - - def test_bad_key_generation(self): - self.assertRaises(RuntimeError, - key.Key, - self.test_key_name, - self.test_key_b64key, - generation=1, - session=self.dummy_session) - - def test_encryption_roundtrip(self): - srckey = key.Key(self.test_key_name, - self.test_key_b64key, - session=self.dummy_session) - plain_text = six.b("MESSAGE") - crypt_text = srckey.encrypt(plain_text) - self.assertNotEqual(plain_text, crypt_text) - self.assertEqual(plain_text, srckey.decrypt(crypt_text)) - - def test_generate(self): - srckey = key.Key.generate(self.test_key_name, - self.dummy_session) - - key_id = "%s:%s" % (self.test_key_name, - self.dummy_session.generation) - - self.assertEqual(key_id, srckey.key_name) - self.assertNotEqual(None, srckey.key) \ No newline at end of file diff --git a/kiteclient/tests/v1/test_ticket.py b/kiteclient/tests/v1/test_ticket.py deleted file mode 100644 index be73e9d..0000000 --- a/kiteclient/tests/v1/test_ticket.py +++ /dev/null @@ -1,108 +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. - -""" -test_ticket ----------------------------------- - -Tests for `ticket` module. -""" - -from kiteclient.tests import base -from kiteclient.tests.v1 import utils -from kiteclient.v1 import esek -from kiteclient.v1 import key -from kiteclient.v1 import ticket - -import base64 -import datetime - -import six - - -class TestTicket(base.TestCase): - - def setUp(self): - super(base.TestCase, self).setUp() - self.nonce = 1062304930675487541 - self.stamp = datetime.datetime(2014, 7, 2, 8, 19, 4, 333230) - - key_ses = utils.DummyKeyResponse(gen=20) - - skey_data = "gTqLlW7x2oyNi3k+9YXTpQ==" - self.srckey = key.Key('testkey', skey_data, session=key_ses) - - dkey_data = "uoUUn/+ZL+hNUwJ0cxTScg==" - self.dstkey = key.Key('destkey', dkey_data, session=key_ses) - - self.tick_signature = ( - "4cj/JRJmvO9L2UlHu1SBOXIofwu3FEFCILTsznwIkd8=") - - self.tick_metadata = ( - "eyJzb3VyY2UiOiAidGVzdGtleToyMCIsICJkZXN0aW5hdGlvbiI6ICJkZX" - "N0a2V5OjIwIiwgImV4cGlyYXRpb24iOiAiMjAxNC0wNy0wMlQwOTo1Njoz" - "NC4zNDI1NTYiLCAiZW5jcnlwdGlvbiI6IHRydWV9") - - self.tick_ticket = ( - "tuKo7NlhkDFyL7YO9mPgtBe4cbJF9TIJfDcPmkCkeo1tee0p8pF2h3wYwn" - "uC1wlt58lPc5don3ov9h16ncZh8PlIVT9JwSxg1o2tQLcByiTQ+PIqiMBp" - "7uM0E4RZsPlED7f89gV/fIdz03OGPjh9oiN+yxRFL2UdMN8VKJVjFdkuNm" - "zpmqbpmxKnkB4vueI3mokdfd3mr1xkYRrw/+L1xseayktgJX0ablgTMpvs" - "e4V/ssbvZFON/dZMXRrQ4xxWxEI2mVMVq9WkkEPzGaPySZ2TKtWUS/QcFi" - "OTNbP0hMwx2UuIjrUOX1V3cBUs8u/rJ8LCs8yRIT2xds6aLgPz8c9Z+bNO" - "6U0LGkDRfKzaV79z+yjZXMbU+m2WYLIY2Cat") - - self.dummy_session = utils.DummyTicketResponse(self.tick_signature, - self.tick_metadata, - self.tick_ticket) - - def test_integrity(self): - tick = ticket.Ticket(self.srckey, - self.dstkey.name, - timestamp=self.stamp, - nonce=self.nonce, - session=self.dummy_session) - - good_skey = six.b("uZnhYaRtzA7QdnDN1hVSWw==") - good_ekey = six.b("fAlG9eGL44ew6q8uTMMKJw==") - - self.assertEqual(good_ekey, tick.b64_ekey) - self.assertEqual(good_skey, tick.b64_skey) - self.assertEqual(tick.b64_skey, base64.b64encode(tick.skey)) - self.assertEqual(tick.b64_ekey, base64.b64encode(tick.ekey)) - - def test_bad_signature_throws(self): - bad_signature = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - bad_session = utils.DummyTicketResponse(bad_signature, - self.tick_metadata, - self.tick_ticket) - self.assertRaises(ValueError, - ticket.Ticket, - self.srckey, - self.dstkey.name, - session=bad_session) - - def test_encryption_roundtrip(self): - tick = ticket.Ticket(self.srckey, - self.dstkey.name, - timestamp=self.stamp, - nonce=self.nonce, - session=self.dummy_session) - message = six.b("MESSAGE") - - enc, sig = tick.encrypt(message, b64encode=True) - tick_esek = esek.Esek(self.srckey.key_name, - self.dstkey, - tick.b64_esek) - - new_message = tick_esek.decrypt(enc, sig, b64decode=True) - self.assertEqual(message,new_message) \ No newline at end of file diff --git a/kiteclient/tests/v1/utils.py b/kiteclient/tests/v1/utils.py deleted file mode 100644 index 236eb5d..0000000 --- a/kiteclient/tests/v1/utils.py +++ /dev/null @@ -1,69 +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. - - -class DummyKeyResponse(object): - - def __init__(self, gen=1): - self.generation = gen - self.name = "" - - def request(self, path, method, **kwargs): - self.name = path.split('/')[-1] - return self - - def json(self): - return {"generation": self.generation, - "name": self.name} - - -class DummyTicketResponse(object): - - def __init__(self, signature, metadata, ticket): - self.signature = signature - self.metadata = metadata - self.ticket = ticket - - def request(self, path, method, **kwargs): - return self - - def json(self): - return {"signature": self.signature, - "metadata": self.metadata, - "ticket": self.ticket} - - -class DummyGroupResponse(object): - def __init__(self, name): - self.name = name - - def request(self, path, method, **kwargs): - return self - - def json(self): - return {"name": self.name} - - -class DummyGroupKeyResponse(object): - - def __init__(self, signature, metadata, group_key): - self.signature = signature - self.metadata = metadata - self.group_key = group_key - - def request(self, path, method, **kwargs): - return self - - def json(self): - return {"signature": self.signature, - "metadata": self.metadata, - "group_key": self.group_key} diff --git a/kiteclient/v1/__init__.py b/kiteclient/v1/__init__.py deleted file mode 100644 index 84dfcd6..0000000 --- a/kiteclient/v1/__init__.py +++ /dev/null @@ -1,24 +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. - - -from kiteclient.v1.esek import Esek -from kiteclient.v1.group import Group -from kiteclient.v1.key import Key -from kiteclient.v1.ticket import Ticket - - -__all__ = ['Esek', - 'Key', - 'Ticket', - 'Group', - ] diff --git a/kiteclient/v1/esek.py b/kiteclient/v1/esek.py deleted file mode 100644 index 2fa7318..0000000 --- a/kiteclient/v1/esek.py +++ /dev/null @@ -1,57 +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. - -import base64 - -import six - -from kiteclient.openstack.common.crypto import utils as cryptoutils -from kiteclient.openstack.common import jsonutils -from kiteclient.openstack.common import timeutils - - -class Esek(object): - - def __init__(self, source, destination, b64_data, - hashtype='SHA256', key_size=16): - data = jsonutils.loads(destination.decrypt(b64_data, b64decode=True)) - - base_key = base64.b64decode(data['key']) - key_info = '%s,%s,%s' % (source, - destination.key_name, - data['timestamp']) - - crypto = cryptoutils.HKDF(hashtype=hashtype) - key_data = crypto.expand(base_key, six.b(key_info), key_size * 2) - - self.sig_key = key_data[:key_size] - self.enc_key = key_data[key_size:] - - # TODO(jamielennox): timestamp validate - self.timestamp = timeutils.parse_strtime(data['timestamp']) - - def decrypt(self, encrypted, signature, b64decode=True, - enctype='AES', hashtype='SHA256'): - crypto = cryptoutils.SymmetricCrypto(enctype=enctype, - hashtype=hashtype) - - data = crypto.decrypt(self.enc_key, encrypted, b64decode=b64decode) - - # b64encode=b64decode looks funny but we only care about the comparison - # and not the actual data so it doesn't matter if we do it as base64 or - # bytes, just that they are both the same. - sig = crypto.sign(self.sig_key, data, b64encode=b64decode) - - if sig != signature: - raise ValueError("Invalid signature") - - return data diff --git a/kiteclient/v1/group.py b/kiteclient/v1/group.py deleted file mode 100644 index 78b1a7d..0000000 --- a/kiteclient/v1/group.py +++ /dev/null @@ -1,109 +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. - -import base64 - -import six - -from kiteclient.common import meta_data -from kiteclient.common import resource -from kiteclient.openstack.common.crypto import utils as cryptoutils -from kiteclient.openstack.common import jsonutils - - -class GroupKey(resource.Resource): - - base_path = 'groups' - - def __init__(self, source, destination, timestamp=None, nonce=None, - session=None): - self._group_key = None - self.source = source - self._destination = destination - self._timestamp = timestamp - self._metadata = None - self._nonce = nonce - - if session: - self.create(session) - - def __repr__(self): - base = 'src: "{0}", dst: "{1}"'.format(self.source.name, - self._destination) - - group_key = 'Not yet created' - if self._group_key is not None: - group_key = self.b64_key - - return ''.format(base, group_key) - - def create(self, session): - b64_metadata = meta_data.Metadata(self.source.name, - self._destination, - self._timestamp, - self._nonce).encode() - b64_signature = self.source.sign(b64_metadata, b64encode=True) - - json = {'metadata': b64_metadata, - 'signature': b64_signature} - - resp = self._http_post(session, json=json).json() - - b64_metadata = resp['metadata'] - b64_group_key = resp['group_key'] - b64_signature = resp['signature'] - - sig = self.source.sign(six.b(b64_metadata + b64_group_key), - b64encode=True) - - if sig != six.b(b64_signature): - raise ValueError("invalid signature on group key") - - group_key = self.source.decrypt(b64_group_key, b64decode=True) - self._group_key = base64.b64encode(group_key) - self._metadata = jsonutils.loads(base64.b64decode(b64_metadata)) - - @property - def b64_key(self): - return self._group_key - - @property - def key(self): - return base64.b64decode(self._group_key) - - def encrypt(self, data, enctype='AES', hashtype='SHA256', b64encode=True): - crypto = cryptoutils.SymmetricCrypto(enctype=enctype, - hashtype=hashtype) - - enc = crypto.encrypt(self.key, data, b64encode=b64encode) - # TODO(tim.kelsey): add a signing key. - # sig = crypto.sign(self.skey, data, b64encode=b64encode) - return enc # , sig - - -class Group(resource.Resource): - - base_path = 'groups' - - def __init__(self, name, session=None): - self.name = name - if session: - self.create(session) - - def create(self, session): - resp = self._http_put(session, self.name).json() - - if resp['name'] != self.name: - raise ValueError('Name was changed in response') - - def getKey(self, source, session): - return GroupKey(source, self.name, session=session) diff --git a/kiteclient/v1/key.py b/kiteclient/v1/key.py deleted file mode 100644 index ad22ac2..0000000 --- a/kiteclient/v1/key.py +++ /dev/null @@ -1,77 +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. - -import base64 - -from Crypto import Random - -from kiteclient.common import resource -from kiteclient.openstack.common.crypto import utils as cryptoutils - - -class Key(resource.Resource): - - base_path = 'keys' - - def __init__(self, name, b64_key, generation=None, session=None): - self.name = name - self.b64_key = b64_key - self.generation = generation - - if session: - self.create(session) - - @classmethod - def generate(cls, name, session=None): - b64_key = base64.b64encode(Random.new().read(16)) - return cls(name, b64_key, session=session) - - @property - def key(self): - return base64.b64decode(self.b64_key) - - @key.setter - def key(self, val): - self.b64_key = base64.b64encode(val) - - @property - def key_name(self): - return '%s:%d' % (self.name, self.generation) - - def __repr__(self): - return '' % (self.key_name, self.b64_key) - - def sign(self, data, hashtype='SHA256', b64encode=True): - crypto = cryptoutils.SymmetricCrypto(hashtype=hashtype) - return crypto.sign(self.key, data, b64encode=b64encode) - - def encrypt(self, data, enctype='AES', b64encode=True): - crypto = cryptoutils.SymmetricCrypto(enctype=enctype) - return crypto.encrypt(self.key, data, b64encode=b64encode) - - def decrypt(self, data, enctype='AES', b64decode=True): - crypto = cryptoutils.SymmetricCrypto(enctype=enctype) - return crypto.decrypt(self.key, data, b64decode=b64decode) - - def create(self, session): - if self.generation: - raise RuntimeError('This key has already been assigned a ' - 'generation meaning it has already been ' - 'created. Cannot create again') - - resp = self._http_put(session, self.name, - json={'key': self.b64_key}).json() - - if resp['name'] != self.name: - raise ValueError('Name was changed in response') - - self.generation = resp['generation'] diff --git a/kiteclient/v1/ticket.py b/kiteclient/v1/ticket.py deleted file mode 100644 index 2d6c77a..0000000 --- a/kiteclient/v1/ticket.py +++ /dev/null @@ -1,109 +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. - -import base64 - -import six - -from kiteclient.common import meta_data -from kiteclient.common import resource -from kiteclient.openstack.common.crypto import utils as cryptoutils -from kiteclient.openstack.common import jsonutils - - -class Ticket(resource.Resource): - - base_path = 'tickets' - - def __init__(self, source, destination, timestamp=None, nonce=None, - session=None): - self.source = source - self._destination = destination - self._timestamp = timestamp - self._nonce = nonce - - self._ticket = None - self._metadata = None - - if session: - self.create(session) - - def create(self, session): - b64_metadata = meta_data.Metadata(self.source.name, - self._destination, - self._timestamp, - self._nonce).encode() - b64_signature = self.source.sign(b64_metadata, b64encode=True) - - json = {'metadata': b64_metadata, - 'signature': b64_signature} - - resp = self._http_post(session, json=json).json() - - b64_metadata = resp['metadata'] - b64_ticket = resp['ticket'] - b64_signature = resp['signature'] - - sig = self.source.sign(six.b(b64_metadata + b64_ticket), - b64encode=True) - - if sig != six.b(b64_signature): - raise ValueError("invalid signature on ticket") - - data = self.source.decrypt(b64_ticket, b64decode=True) - self._ticket = jsonutils.loads(data) - self._ticket['skey'] = six.b(self._ticket['skey']) - self._ticket['ekey'] = six.b(self._ticket['ekey']) - self._ticket['esek'] = six.b(self._ticket['esek']) - self._metadata = jsonutils.loads(base64.b64decode(b64_metadata)) - - def __repr__(self): - base = 'src: "%s", dst: "%s"' % (self.source.name, self._destination) - - if self._ticket: - ticket = 'skey: "%s", ekey: "%s"' % (self.b64_skey, self.b64_ekey) - else: - ticket = 'Not yet created' - - return '' % (base, ticket) - - @property - def b64_skey(self): - return self._ticket['skey'] - - @property - def skey(self): - return base64.b64decode(self.b64_skey) - - @property - def b64_ekey(self): - return self._ticket['ekey'] - - @property - def ekey(self): - return base64.b64decode(self.b64_ekey) - - @property - def b64_esek(self): - return self._ticket['esek'] - - @property - def esek(self): - return base64.b64decode(self.b64_esek) - - def encrypt(self, data, enctype='AES', hashtype='SHA256', b64encode=True): - crypto = cryptoutils.SymmetricCrypto(enctype=enctype, - hashtype=hashtype) - - enc = crypto.encrypt(self.ekey, data, b64encode=b64encode) - sig = crypto.sign(self.skey, data, b64encode=b64encode) - return enc, sig diff --git a/openstack-common.conf b/openstack-common.conf deleted file mode 100644 index 07fdef6..0000000 --- a/openstack-common.conf +++ /dev/null @@ -1,8 +0,0 @@ -[DEFAULT] - -# The list of modules to copy from oslo-incubator.git - -# The base module to hold the copy of openstack.common -base=kiteclient - -module=crypto \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 11f2efd..0000000 --- a/requirements.txt +++ /dev/null @@ -1,8 +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. -pbr>=0.6,!=0.7,<1.0 -Babel>=1.3 -pycrypto>=2.6 -oslo.utils>=1.4.0 # Apache-2.0 -iso8601>=0.1.9 diff --git a/scripts/basic.py b/scripts/basic.py deleted file mode 100644 index 66f6efb..0000000 --- a/scripts/basic.py +++ /dev/null @@ -1,43 +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. - -import logging - -from keystoneclient.auth import token_endpoint -from keystoneclient import session - -from kiteclient import v1 - -logging.basicConfig(level=logging.DEBUG) - -message = 'MESSAGE' - -auth = token_endpoint.Token('http://localhost:9109/v1', 'aToken') -s = session.Session(auth=auth) - -srckey = v1.Key.generate('testkey', session=s) -print("source", srckey) - -dstkey = v1.Key.generate('destkey', session=s) -print("dest", dstkey) - -tick = v1.Ticket(srckey, dstkey.name, session=s) -print("ticket", tick) - -enc, sig = tick.encrypt(message, b64encode=True) - -esek = v1.Esek(srckey.key_name, dstkey, tick.b64_esek) -new_message = esek.decrypt(enc, sig, b64decode=True) - -assert message == new_message - -print(new_message) diff --git a/scripts/demo-client/client.py b/scripts/demo-client/client.py deleted file mode 100644 index 57149aa..0000000 --- a/scripts/demo-client/client.py +++ /dev/null @@ -1,84 +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. - -from kiteclient import v1 - - -class KiteClient(object): - """KiteClient class. - - This acts as a client to the kite server and will register a key with - kite upon creation. A transport class must be provided, message data - will be read from the transport, decrypted and verified. - - To send a message, data will be encrypted and signed using a kite - ticket then passed onto the transport. A message is formed thus: - - { - "sender" : sender key name, - "body" : encrypted data, base64 encoded, - "signature" : message signature, base64 encoded, - "esec" : message esek data - } - """ - - def __init__(self, name, transport, key=None, session=None, - verbose=False): - self._session = session - self._transport = transport - self.verbose = verbose - - if key is None: - self._key = v1.Key.generate(name, self._session) - else: - self._key = v1.Key(name, key, self._session) - - def _get_ticket(self, target): - ticket = v1.Ticket(self._key, target, session=self._session) - return ticket - - def send(self, data, target): - """Create and send a trusted message. - - :param data: the message body - :param target: the recipient name - """ - ticket = self._get_ticket(target) - enc, sig = ticket.encrypt(data) - message = { - "sender": self._key.key_name, - "body": enc, - "signature": sig, - "esek": ticket.b64_esek - } - - if self.verbose: - print("Sent: %s" % message) - - resp = self._transport.send(message, target) - return resp - - def recv(self): - """Receive, verify and decrypt a secure message - - :param data: the secure message data - """ - message = self._transport.recv() - - if self.verbose: - print("Received: %s" % message) - - esek = v1.Esek(message["sender"], self._key, message["esek"]) - body = esek.decrypt(message["body"], - message["signature"], - b64decode=True) - return body \ No newline at end of file diff --git a/scripts/demo-client/main.py b/scripts/demo-client/main.py deleted file mode 100644 index fd95098..0000000 --- a/scripts/demo-client/main.py +++ /dev/null @@ -1,93 +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. - -from __future__ import print_function - -import client -from keystoneclient.auth import token_endpoint -from keystoneclient import session -import transport - -from kiteclient.openstack.common import gettextutils as u - -import optparse - - -def main(): - usage = "usage: %prog [options] name [-l | target message]" - parser = optparse.OptionParser(usage=usage) - - parser.add_option("-v", "--verbose", dest="verbose", - help=u._("Be verbose."), action="store_true", - default=False) - - parser.add_option('--kite_host', - help=u._('Kite server host address.'), - default="localhost"), - - parser.add_option('--kite_port', - help=u._('Kite server port number.'), - default="9109"), - - parser.add_option('--key', "-k", - help=u._('Optional base64 encoded key.')), - - parser.add_option('--queue', "-q", - help=u._('Message queue url.'), - default="rabbit://localhost"), - - parser.add_option('--listen', "-l", - help=u._('Listen for incoming messages.'), - action="store_true", default=False), - - (options, args) = parser.parse_args() - - if not args: - parser.print_usage() - return -1 - - # NOTE(tkelsey): using developer interface to remove the need to run - # a keystone server. - name = args[0] - host = options.kite_host - port = options.kite_port - kite = "http://%s:%s/v1" % (host, port) - auth = token_endpoint.Token(kite, 'aToken') - - transport_obj = transport.Transport(target=name, url=options.queue) - session_obj = session.Session(auth=auth) - client_obj = client.KiteClient(name, transport_obj, - key=options.key, - session=session_obj, - verbose=options.verbose) - - if options.listen: - try: - message = client_obj.recv() - print(message) - except KeyboardInterrupt: - pass - - else: - if len(args) < 3: - print("target and message are required when not listening") - parser.print_usage() - return -1 - - else: - targ = args[1] - body = args[2] - resp = client_obj.send(body, targ) - print(resp) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/scripts/demo-client/transport.py b/scripts/demo-client/transport.py deleted file mode 100644 index 4a8ce48..0000000 --- a/scripts/demo-client/transport.py +++ /dev/null @@ -1,44 +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. - -from oslo.config import cfg -from oslo import messaging - - -class Transport(object): - - def __init__(self, target, url): - self._transport = messaging.get_transport(cfg.CONF, url) - self._target = messaging.Target(topic=target, - server='server1', - version='1.0') - self.timeout = 2 - self.retry = True - - def send(self, msg, target): - msg_ctxt = {} - targ = messaging.Target(topic=target, - server='server1', - version='1.0') - - result = self._transport._send(targ, msg_ctxt, msg, - wait_for_reply=True, - timeout=self.timeout, - ) - return result - - def recv(self): - listener = self._transport._listen(self._target) - message = listener.poll() - message.reply(reply="OK") - message.acknowledge() - return message.message diff --git a/scripts/group.py b/scripts/group.py deleted file mode 100644 index bff86b7..0000000 --- a/scripts/group.py +++ /dev/null @@ -1,38 +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. - -import logging - -from keystoneclient.auth import token_endpoint -from keystoneclient import session - -from kiteclient import v1 - -logging.basicConfig(level=logging.DEBUG) - -auth = token_endpoint.Token('http://localhost:9109/v1', 'aToken') -s = session.Session(auth=auth) - -group = v1.group.Group('testgroup', session=s) -keyA = v1.Key.generate('testgroup.testkeyA', session=s) -keyB = v1.Key.generate('testgroup.testkeyB', session=s) - -tickA = v1.group.GroupKey(keyA, "testgroup", session=s) -tickB = group.getKey(keyB, session=s) - -print("-----------------------------------------------------------------") -print(keyA) -print("gkey A", tickA) -print("-----------------------------------------------------------------") -print(keyB) -print("gkey B", tickB) -print("-----------------------------------------------------------------") diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3a0f0db..0000000 --- a/setup.cfg +++ /dev/null @@ -1,55 +0,0 @@ -[metadata] -name = python-kiteclient -summary = Interacting with the kite server -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://www.openstack.org/ -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 2.6 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.3 - -[files] -packages = - kiteclient - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = kiteclient/locale -domain = python-kiteclient - -[update_catalog] -domain = python-kiteclient -output_dir = kiteclient/locale -input_file = kiteclient/locale/python-kiteclient.pot - -[entry_points] -openstack.cli.extension = - kds = kiteclient.cli.v1 - -openstack.kds.v1 = - key_set = kiteclient.cli.v1:KeySet - keygroup_create = kiteclient.cli.v1:GroupCreate - keygroup_delete = kiteclient.cli.v1:GroupDelete - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = kiteclient/locale/python-kiteclient.pot \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100755 index 7363757..0000000 --- a/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python -# 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'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 58e64fe..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,14 +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.9.1,<0.10 - -coverage>=3.6 -discover -fixtures>=0.3.14 -python-subunit>=0.0.18 -sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 -oslosphinx>=2.5.0 # Apache-2.0 -testrepository>=0.0.18 -testscenarios>=0.4 -testtools>=0.9.36,!=1.2.0 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 6475b1d..0000000 --- a/tox.ini +++ /dev/null @@ -1,32 +0,0 @@ -[tox] -minversion = 1.6 -envlist = py26,py27,py33,py34,pypy,pep8 -skipsdist = True - -[testenv] -usedevelop = True -install_command = pip install -U {opts} {packages} -setenv = - VIRTUAL_ENV={envdir} -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = python setup.py testr --slowest --testr-args='{posargs}' - -[testenv:pep8] -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[testenv:cover] -commands = python setup.py testr --coverage --testr-args='{posargs}' - -[flake8] -# H803 skipped on purpose per list discussion. -# E123, E125 skipped as they are invalid PEP-8. -# H302 relaxed for now - -show-source = True -ignore = E123,E125,H803,H302 -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build