diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5c4a36d..0000000 --- a/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -*.pyc -*.swp -*.sqlite3 -.coverage* -.noseids -.DS_STORE -*.egg/ -*.egg-info/ -coverage.xml -nosetests.xml -pep8.txt -pylint.txt -doc/build/ -.venv -.tox -build -dist -AUTHORS -ChangeLog -tags -.testrepository/ -*.lock -*.log -.DS_Store diff --git a/.gitreview b/.gitreview deleted file mode 100644 index f0443b2..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/python-evoqueclient.git diff --git a/.testr.conf b/.testr.conf deleted file mode 100755 index 75445cc..0000000 --- a/.testr.conf +++ /dev/null @@ -1,8 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-160} \ - ${PYTHON:-python} -m subunit.run discover -t ./ ./evoqueclient/tests $LISTOPT $IDOPTION - -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index d40c991..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,42 +0,0 @@ -====================== -Contributing to Evoque -====================== - -If you're interested in contributing to the Evoque project, -the following will help get you started. - -Contributor License Agreement -============================= - -In order to contribute to the Evoque project, you need to have -signed OpenStack's contributor's agreement: - -* http://docs.openstack.org/infra/manual/developers.html -* http://wiki.openstack.org/CLA - - -Project Hosting Details -======================= - -* Bug tracker - * https://launchpad.net/evoque - - * https://launchpad.net/python-evoqueclient - -* Wiki - https://wiki.openstack.org/wiki/Evoque - -* IRC channel - * #evoque at FreeNode - - * http://eavesdrop.openstack.org/meetings/evoque - -* Code Hosting - * https://git.openstack.org/cgit/openstack/evoque - - * https://git.openstack.org/cgit/openstack/python-evoqueclient - -* Code Review - * https://review.openstack.org/#/q/project:openstack/evoque+status:open,n,z - - * http://docs.openstack.org/infra/manual/developers.html#development-workflow diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index cb07476..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -Style Commandments -================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a..0000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - diff --git a/README.rst b/README.rst index 5b5782c..d98af48 100644 --- a/README.rst +++ b/README.rst @@ -1,43 +1,10 @@ -Evoque -====== +This project is no longer maintained. -Evoque is a ticket service for OpenStack. +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". -* `Launchpad project`_ - release management -* `Blueprints`_ - feature specifications -* `Bugs`_ - issue tracking -* `Source`_ -* `How to Contribute`_ - -.. _Launchpad project: https://launchpad.net/python-evoqueclient -.. _Blueprints: https://blueprints.launchpad.net/python-evoqueclient -.. _Bugs: https://bugs.launchpad.net/python-evoqueclient -.. _Source: https://git.openstack.org/cgit/openstack/python-evoqueclient -.. _How to Contribute: http://docs.openstack.org/infra/manual/developers.html - -Python Evoqueclient -------------------- -python-evoqueclient is a client library for Evoque built on the Evoque API. -It provides a Python API (the ``evoqueclient`` module) and a command-line tool -(``evoque``). - - -Project Resources ------------------ - -Project status, bugs, and blueprints are tracked on Launchpad: - -* Client bug tracker - * https://launchpad.net/python-evoqueclient - -* Evoque bug tracker - * https://launchpad.net/evoque - -Additional resources are linked from the project wiki page: - - https://wiki.openstack.org/wiki/Evoque - -License -------- - -Apache License Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index de29d45..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,62 +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'evoque' -copyright = u'2015, 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 = [] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 38ba804..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../README.rst \ No newline at end of file diff --git a/evoqueclient/__init__.py b/evoqueclient/__init__.py deleted file mode 100644 index cbcd723..0000000 --- a/evoqueclient/__init__.py +++ /dev/null @@ -1,28 +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 pbr.version - -_ROOT = os.path.abspath(os.path.dirname(__file__)) - - -def get_resource(path): - return os.path.join(_ROOT, 'data', path) - -version_info = pbr.version.VersionInfo('python-evoqueclient') - -try: - __version__ = version_info.version_string() -except AttributeError: - __version__ = None diff --git a/evoqueclient/client.py b/evoqueclient/client.py deleted file mode 100644 index 2b5e853..0000000 --- a/evoqueclient/client.py +++ /dev/null @@ -1,19 +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 evoqueclient.common import utils - - -def Client(version, *args, **kwargs): - module = utils.import_versioned_module(version, 'client') - client_class = getattr(module, 'Client') - return client_class(*args, **kwargs) diff --git a/evoqueclient/common/__init__.py b/evoqueclient/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/evoqueclient/common/base.py b/evoqueclient/common/base.py deleted file mode 100644 index c29956a..0000000 --- a/evoqueclient/common/base.py +++ /dev/null @@ -1,216 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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. - -""" -Base utilities to build API operation managers and objects on top of. -""" - -import abc -import copy - -import six - -from evoqueclient.openstack.common.apiclient import exceptions - - -# Python 2.4 compat -try: - all -except NameError: - def all(iterable): - return True not in (not x for x in iterable) - - -def getid(obj): - """Abstracts the common pattern of allowing both an object or - an object's ID (UUID) as a parameter when dealing with relationships. - """ - try: - return obj.id - except AttributeError: - return obj - - -class Manager(object): - """Managers interact with a particular type of API (servers, flavors, - images, etc.) and provide CRUD operations for them. - """ - resource_class = None - - def __init__(self, api): - self.api = api - - def _list(self, url, response_key=None, obj_class=None, - data=None, headers={}): - - resp, body = self.api.json_request('GET', url, headers=headers) - - if obj_class is None: - obj_class = self.resource_class - - if response_key: - if response_key not in body: - body[response_key] = [] - data = body[response_key] - else: - data = body - return [obj_class(self, res, loaded=True) for res in data if res] - - def _delete(self, url, headers={}): - self.api.raw_request('DELETE', url, headers=headers) - - def _update(self, url, data, response_key=None, headers={}): - resp, body = self.api.json_request('PUT', url, data=data, - headers=headers) - # PUT requests may not return a body - if body: - if response_key: - return self.resource_class(self, body[response_key]) - return self.resource_class(self, body) - - def _create(self, url, data=None, response_key=None, - return_raw=False, headers={}): - if data: - resp, body = self.api.json_request('POST', url, - data=data, headers=headers) - else: - resp, body = self.api.json_request('POST', url, headers=headers) - if return_raw: - if response_key: - return body[response_key] - return body - if response_key: - return self.resource_class(self, body[response_key]) - return self.resource_class(self, body) - - def _get(self, url, response_key=None, return_raw=False, headers={}): - resp, body = self.api.json_request('GET', url, headers=headers) - if return_raw: - if response_key: - return body[response_key] - return body - if response_key: - return self.resource_class(self, body[response_key]) - return self.resource_class(self, body) - - -@six.add_metaclass(abc.ABCMeta) -class ManagerWithFind(Manager): - """Manager with additional `find()`/`findall()` methods.""" - - @abc.abstractmethod - def list(self): - pass - - def find(self, **kwargs): - """Find a single item with attributes matching ``**kwargs``. - - This isn't very efficient: it loads the entire list then filters on - the Python side. - """ - rl = self.findall(**kwargs) - num = len(rl) - - if num == 0: - msg = "No %s matching %s." % (self.resource_class.__name__, kwargs) - raise exceptions.NotFound(msg) - elif num > 1: - raise exceptions.NoUniqueMatch - else: - return self.get(rl[0].id) - - def findall(self, **kwargs): - """Find all items with attributes matching ``**kwargs``. - - This isn't very efficient: it loads the entire list then filters on - the Python side. - """ - found = [] - searches = kwargs.items() - - for obj in self.list(): - try: - if all(getattr(obj, attr) == value - for (attr, value) in searches): - found.append(obj) - except AttributeError: - continue - - return found - - -class Resource(object): - """A resource represents a particular instance of an object (tenant, user, - etc). This is pretty much just a bag for attributes. - - :param manager: Manager object - :param info: dictionary representing resource attributes - :param loaded: prevent lazy-loading if set to True - """ - def __init__(self, manager, info, loaded=False): - self.manager = manager - self._info = info - self._add_details(info) - self._loaded = loaded - - def _add_details(self, info): - for k, v in info.items(): - setattr(self, k, v) - - def __setstate__(self, d): - for k, v in d.items(): - setattr(self, k, v) - - def __getattr__(self, k): - if k not in self.__dict__: - # NOTE(bcwaldon): disallow lazy-loading if already loaded once - if not self.is_loaded(): - self.get() - return self.__getattr__(k) - raise AttributeError(k) - else: - return self.__dict__[k] - - def __repr__(self): - reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and - k != 'manager') - info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) - return "<%s %s>" % (self.__class__.__name__, info) - - def get(self): - # set_loaded() first ... so if we have to bail, we know we tried. - self.set_loaded(True) - if not hasattr(self.manager, 'get'): - return - - new = self.manager.get(self.id) - if new: - self._add_details(new._info) - - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - if hasattr(self, 'id') and hasattr(other, 'id'): - return self.id == other.id - return self._info == other._info - - def is_loaded(self): - return self._loaded - - def set_loaded(self, val): - self._loaded = val - - def to_dict(self): - return copy.deepcopy(self._info) diff --git a/evoqueclient/common/exceptions.py b/evoqueclient/common/exceptions.py deleted file mode 100644 index 5070019..0000000 --- a/evoqueclient/common/exceptions.py +++ /dev/null @@ -1,207 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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 re -import sys - - -# TODO(sjmc7): This module is likely redundant because it's replaced -# by openstack.common.apiclient; should be removed -class BaseException(Exception): - """An error occurred.""" - def __init__(self, message=None): - self.message = message - - def __str__(self): - return self.message or self.__class__.__doc__ - - -class InvalidEndpoint(BaseException): - """The provided endpoint is invalid.""" - - -class CommunicationError(BaseException): - """Unable to communicate with server.""" - - -class ClientException(Exception): - """DEPRECATED!""" - - -class HTTPException(ClientException): - """Base exception for all HTTP-derived exceptions.""" - code = 'N/A' - - def __init__(self, details=None): - self.details = details or self.__class__.__name__ - - def __str__(self): - return "%s (HTTP %s)" % (self.details, self.code) - - -class HTTPMultipleChoices(HTTPException): - code = 300 - - def __str__(self): - self.details = ("Requested version of Application Catalog API is not " - "available.") - return "%s (HTTP %s) %s" % (self.__class__.__name__, self.code, - self.details) - - -class BadRequest(HTTPException): - """DEPRECATED!""" - code = 400 - - -class HTTPBadRequest(BadRequest): - pass - - -class Unauthorized(HTTPException): - """DEPRECATED!""" - code = 401 - - -class HTTPUnauthorized(Unauthorized): - pass - - -class Forbidden(HTTPException): - """DEPRECATED!""" - code = 403 - - -class HTTPForbidden(Forbidden): - pass - - -class NotFound(HTTPException): - """DEPRECATED!""" - code = 404 - - -class HTTPNotFound(NotFound): - pass - - -class HTTPMethodNotAllowed(HTTPException): - code = 405 - - -class Conflict(HTTPException): - """DEPRECATED!""" - code = 409 - - -class HTTPConflict(Conflict): - pass - - -class OverLimit(HTTPException): - """DEPRECATED!""" - code = 413 - - -class HTTPOverLimit(OverLimit): - pass - - -class HTTPInternalServerError(HTTPException): - code = 500 - - -class HTTPNotImplemented(HTTPException): - code = 501 - - -class HTTPBadGateway(HTTPException): - code = 502 - - -class ServiceUnavailable(HTTPException): - """DEPRECATED!""" - code = 503 - - -class HTTPServiceUnavailable(ServiceUnavailable): - pass - - -# NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception -# classes -_code_map = {} -for obj_name in dir(sys.modules[__name__]): - if obj_name.startswith('HTTP'): - obj = getattr(sys.modules[__name__], obj_name) - _code_map[obj.code] = obj - - -def from_response(response): - """Return an instance of an HTTPException based on httplib response.""" - cls = _code_map.get(response.status_code, HTTPException) - body = response.content - if body and response.headers['content-type'].\ - lower().startswith("application/json"): - # Iterate over the nested objects and retreive the "message" attribute. - messages = [obj.get('message') for obj in response.json().values()] - # Join all of the messages together nicely and filter out any objects - # that don't have a "message" attr. - details = '\n'.join(i for i in messages if i is not None) - return cls(details=details) - elif body and \ - response.headers['content-type'].lower().startswith("text/html"): - # Split the lines, strip whitespace and inline HTML from the response. - details = [re.sub(r'<.+?>', '', i.strip()) - for i in response.text.splitlines()] - details = [i for i in details if i] - # Remove duplicates from the list. - details_seen = set() - details_temp = [] - for i in details: - if i not in details_seen: - details_temp.append(i) - details_seen.add(i) - # Return joined string separated by colons. - details = ': '.join(details_temp) - return cls(details=details) - elif body: - details = body.replace('\n\n', '\n') - return cls(details=details) - - return cls() - - -def from_code(code): - cls = _code_map.get(code, HTTPException) - return cls() - - -class NoTokenLookupException(Exception): - """DEPRECATED!""" - pass - - -class EndpointNotFound(Exception): - """DEPRECATED!""" - pass - - -class SSLConfigurationError(BaseException): - pass - - -class SSLCertificateError(BaseException): - pass diff --git a/evoqueclient/common/http.py b/evoqueclient/common/http.py deleted file mode 100644 index bf2cb8f..0000000 --- a/evoqueclient/common/http.py +++ /dev/null @@ -1,301 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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 copy -import hashlib -import os -import socket - -from oslo_log import log as logging -from oslo_serialization import jsonutils -from oslo_utils import encodeutils -import requests -import six -from six.moves.urllib import parse - -from evoqueclient.common import exceptions as exc - -LOG = logging.getLogger(__name__) -USER_AGENT = 'python-evoqueclient' -CHUNKSIZE = 1024 * 64 # 64kB - - -def get_system_ca_file(): - """Return path to system default CA file.""" - # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora, - # Suse, FreeBSD/OpenBSD, MacOSX, and the bundled ca - ca_path = ['/etc/ssl/certs/ca-certificates.crt', - '/etc/pki/tls/certs/ca-bundle.crt', - '/etc/ssl/ca-bundle.pem', - '/etc/ssl/cert.pem', - '/System/Library/OpenSSL/certs/cacert.pem', - requests.certs.where()] - for ca in ca_path: - LOG.debug("Looking for ca file %s", ca) - if os.path.exists(ca): - LOG.debug("Using ca file %s", ca) - return ca - LOG.warn("System ca file could not be found.") - - -class HTTPClient(object): - - def __init__(self, endpoint, **kwargs): - self.endpoint = endpoint - self.auth_url = kwargs.get('auth_url') - self.auth_token = kwargs.get('token') - self.username = kwargs.get('username') - self.password = kwargs.get('password') - self.region_name = kwargs.get('region_name') - self.include_pass = kwargs.get('include_pass') - self.endpoint_url = endpoint - - self.cert_file = kwargs.get('cert_file') - self.key_file = kwargs.get('key_file') - self.timeout = kwargs.get('timeout') - - self.ssl_connection_params = { - 'cacert': kwargs.get('cacert'), - 'cert_file': kwargs.get('cert_file'), - 'key_file': kwargs.get('key_file'), - 'insecure': kwargs.get('insecure'), - } - - self.verify_cert = None - if parse.urlparse(endpoint).scheme == "https": - if kwargs.get('insecure'): - self.verify_cert = False - else: - self.verify_cert = kwargs.get('cacert', get_system_ca_file()) - - def _safe_header(self, name, value): - if name in ['X-Auth-Token', 'X-Subject-Token']: - # because in python3 byte string handling is ... ug - v = value.encode('utf-8') - h = hashlib.sha1(v) - d = h.hexdigest() - return encodeutils.safe_decode(name), "{SHA1}%s" % d - else: - return (encodeutils.safe_decode(name), - encodeutils.safe_decode(value)) - - def log_curl_request(self, method, url, kwargs): - curl = ['curl -i -X %s' % method] - - for (key, value) in kwargs['headers'].items(): - header = '-H \'%s: %s\'' % self._safe_header(key, value) - curl.append(header) - - conn_params_fmt = [ - ('key_file', '--key %s'), - ('cert_file', '--cert %s'), - ('cacert', '--cacert %s'), - ] - for (key, fmt) in conn_params_fmt: - value = self.ssl_connection_params.get(key) - if value: - curl.append(fmt % value) - - if self.ssl_connection_params.get('insecure'): - curl.append('-k') - - if 'data' in kwargs: - curl.append('-d \'%s\'' % kwargs['data']) - - curl.append('%s%s' % (self.endpoint, url)) - LOG.debug(' '.join(curl)) - - @staticmethod - def log_http_response(resp): - status = (resp.raw.version / 10.0, resp.status_code, resp.reason) - dump = ['\nHTTP/%.1f %s %s' % status] - dump.extend(['%s: %s' % (k, v) for k, v in resp.headers.items()]) - dump.append('') - if resp.content: - content = resp.content - if isinstance(content, six.binary_type): - try: - content = encodeutils.safe_decode(resp.content) - except UnicodeDecodeError: - pass - else: - dump.extend([content, '']) - LOG.debug('\n'.join(dump)) - - def _http_request(self, url, method, **kwargs): - """Send an http request with the specified characteristics. - - Wrapper around requests.request to handle tasks such - as setting headers and error handling. - """ - # Copy the kwargs so we can reuse the original in case of redirects - kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) - kwargs['headers'].setdefault('User-Agent', USER_AGENT) - if self.auth_token: - kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) - else: - kwargs['headers'].update(self.credentials_headers()) - if self.auth_url: - kwargs['headers'].setdefault('X-Auth-Url', self.auth_url) - if self.region_name: - kwargs['headers'].setdefault('X-Region-Name', self.region_name) - - self.log_curl_request(method, url, kwargs) - - if self.cert_file and self.key_file: - kwargs['cert'] = (self.cert_file, self.key_file) - - if self.verify_cert is not None: - kwargs['verify'] = self.verify_cert - - if self.timeout is not None: - kwargs['timeout'] = float(self.timeout) - - # Allow the option not to follow redirects - follow_redirects = kwargs.pop('follow_redirects', True) - - # Since requests does not follow the RFC when doing redirection to sent - # back the same method on a redirect we are simply bypassing it. For - # example if we do a DELETE/POST/PUT on a URL and we get a 302 RFC says - # that we should follow that URL with the same method as before, - # requests doesn't follow that and send a GET instead for the method. - # Hopefully this could be fixed as they say in a comment in a future - # point version i.e.: 3.x - # See issue: https://github.com/kennethreitz/requests/issues/1704 - allow_redirects = False - - try: - resp = requests.request( - method, - self.endpoint_url + url, - allow_redirects=allow_redirects, - **kwargs) - except socket.gaierror as e: - message = ("Error finding address for %(url)s: %(e)s" % - {'url': self.endpoint_url + url, 'e': e}) - raise exc.InvalidEndpoint(message=message) - except (socket.error, - socket.timeout, - requests.exceptions.ConnectionError) as e: - endpoint = self.endpoint - message = ("Error communicating with %(endpoint)s %(e)s" % - {'endpoint': endpoint, 'e': e}) - raise exc.CommunicationError(message=message) - - self.log_http_response(resp) - - if 'X-Auth-Key' not in kwargs['headers'] and \ - (resp.status_code == 401 or - (resp.status_code == 500 and "(HTTP 401)" in resp.content)): - raise exc.HTTPUnauthorized("Authentication failed. Please try" - " again.\n%s" - % resp.content) - elif 400 <= resp.status_code < 600: - raise exc.from_response(resp) - elif resp.status_code in (301, 302, 305): - # Redirected. Reissue the request to the new location, - # unless caller specified follow_redirects=False - if follow_redirects: - location = resp.headers.get('location') - path = self.strip_endpoint(location) - resp = self._http_request(path, method, **kwargs) - elif resp.status_code == 300: - raise exc.from_response(resp) - - return resp - - def strip_endpoint(self, location): - if location is None: - message = "Location not returned with 302" - raise exc.InvalidEndpoint(message=message) - elif location.startswith(self.endpoint): - return location[len(self.endpoint):] - else: - message = "Prohibited endpoint redirect %s" % location - raise exc.InvalidEndpoint(message=message) - - def credentials_headers(self): - creds = {} - if self.username: - creds['X-Auth-User'] = self.username - if self.password: - creds['X-Auth-Key'] = self.password - return creds - - def json_request(self, method, url, content_type='application/json', - **kwargs): - kwargs.setdefault('headers', {}) - kwargs['headers'].setdefault('Content-Type', content_type) - # Don't set Accept because we aren't always dealing in JSON - - if 'body' in kwargs: - if 'data' in kwargs: - raise ValueError("Can't provide both 'data' and " - "'body' to a request") - LOG.warning("Use of 'body' is deprecated; use 'data' instead") - kwargs['data'] = kwargs.pop('body') - if 'data' in kwargs: - kwargs['data'] = jsonutils.dumps(kwargs['data']) - - resp = self._http_request(url, method, **kwargs) - body = resp.content - - if body and 'application/json' in resp.headers['content-type']: - try: - body = resp.json() - except ValueError: - LOG.error('Could not decode response body as JSON') - else: - body = None - - return resp, body - - def json_patch_request(self, url, method='PATCH', **kwargs): - content_type = 'application/evoque-packages-json-patch' - return self.json_request( - method, url, content_type=content_type, **kwargs) - - def raw_request(self, method, url, **kwargs): - if 'body' in kwargs: - if 'data' in kwargs: - raise ValueError("Can't provide both 'data' and " - "'body' to a request") - LOG.warning("Use of 'body' is deprecated; use 'data' instead") - kwargs['data'] = kwargs.pop('body') - # Chunking happens automatically if 'body' is a - # file-like object - return self._http_request(url, method, **kwargs) - - def client_request(self, method, url, **kwargs): - resp, body = self.json_request(method, url, **kwargs) - return resp - - def head(self, url, **kwargs): - return self.client_request("HEAD", url, **kwargs) - - def get(self, url, **kwargs): - return self.client_request("GET", url, **kwargs) - - def post(self, url, **kwargs): - return self.client_request("POST", url, **kwargs) - - def put(self, url, **kwargs): - return self.client_request("PUT", url, **kwargs) - - def delete(self, url, **kwargs): - return self.raw_request("DELETE", url, **kwargs) - - def patch(self, url, **kwargs): - return self.client_request("PATCH", url, **kwargs) diff --git a/evoqueclient/common/i18n.py b/evoqueclient/common/i18n.py deleted file mode 100644 index 6759ddd..0000000 --- a/evoqueclient/common/i18n.py +++ /dev/null @@ -1,41 +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 - -""" - -import oslo_i18n - - -_translators = oslo_i18n.TranslatorFactory(domain='evoque') - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# The contextual translation function using the name "_C" -_C = _translators.contextual_form - -# The plural translation function using the name "_P" -_P = _translators.plural_form - -# 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 diff --git a/evoqueclient/common/utils.py b/evoqueclient/common/utils.py deleted file mode 100644 index beca817..0000000 --- a/evoqueclient/common/utils.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2012 OpenStack LLC. -# 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 os - -from oslo_utils import encodeutils -from oslo_utils import importutils -import prettytable - - -# Decorator for cli-args -def arg(*args, **kwargs): - def _decorator(func): - # Because of the sematics of decorator composition if we just append - # to the options list positional options will appear to be backwards. - func.__dict__.setdefault('arguments', []).insert(0, (args, kwargs)) - return func - return _decorator - - -def import_versioned_module(version, submodule=None): - module = 'evoqueclient.v%s' % version - if submodule: - module = '.'.join((module, submodule)) - return importutils.import_module(module) - - -def env(*vars, **kwargs): - """Search for the first defined of possibly many env vars - - Returns the first environment variable defined in vars, or - returns the default defined in kwargs. - """ - for v in vars: - value = os.environ.get(v, None) - if value: - return value - return kwargs.get('default', '') - - -def print_list(objs, fields, field_labels, formatters={}, sortby=0): - pt = prettytable.PrettyTable([f for f in field_labels], caching=False) - pt.align = 'l' - - for o in objs: - row = [] - for field in fields: - if field in formatters: - row.append(formatters[field](o)) - else: - data = getattr(o, field, None) or '' - row.append(data) - pt.add_row(row) - print(encodeutils.safe_encode(pt.get_string())) diff --git a/evoqueclient/openstack/__init__.py b/evoqueclient/openstack/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/evoqueclient/openstack/common/__init__.py b/evoqueclient/openstack/common/__init__.py deleted file mode 100644 index d1223ea..0000000 --- a/evoqueclient/openstack/common/__init__.py +++ /dev/null @@ -1,17 +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 six - - -six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox')) diff --git a/evoqueclient/openstack/common/apiclient/__init__.py b/evoqueclient/openstack/common/apiclient/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/evoqueclient/openstack/common/apiclient/exceptions.py b/evoqueclient/openstack/common/apiclient/exceptions.py deleted file mode 100644 index b90fcc6..0000000 --- a/evoqueclient/openstack/common/apiclient/exceptions.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2011 Nebula, Inc. -# Copyright 2013 Alessio Ababilov -# Copyright 2013 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. - -""" -Exception definitions. -""" - - -class ClientException(Exception): - """The base exception class for all exceptions this library raises. - """ - pass - - -class CommandError(ClientException): - """Error in CLI tool.""" - pass diff --git a/evoqueclient/shell.py b/evoqueclient/shell.py deleted file mode 100644 index 7952e8e..0000000 --- a/evoqueclient/shell.py +++ /dev/null @@ -1,397 +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. - -""" -Command-line interface to the Evoque Project. -""" - -from __future__ import print_function - -import argparse -import sys - -from keystoneclient.v2_0 import client as ksclient -from oslo_log import handlers -from oslo_log import log as logging -from oslo_utils import encodeutils -import six - -import evoqueclient -from evoqueclient import client as apiclient -from evoqueclient.common import utils -from evoqueclient.openstack.common.apiclient import exceptions as exc - - -logger = logging.getLogger(__name__) - - -class EvoqueShell(object): - def get_base_parser(self): - parser = argparse.ArgumentParser( - prog='evoque', - description=__doc__.strip(), - epilog='See "evoque help COMMAND" ' - 'for help on a specific command.', - add_help=False, - formatter_class=HelpFormatter, - ) - - # Global arguments - parser.add_argument('-h', '--help', - action='store_true', - help=argparse.SUPPRESS,) - - parser.add_argument('--version', - action='version', - version=evoqueclient.__version__, - help="Show program's version number and exit.") - - parser.add_argument('-d', '--debug', - default=bool(utils.env('EVOQUECLIENT_DEBUG')), - action='store_true', - help='Defaults to env[EVOQUECLIENT_DEBUG].') - - parser.add_argument('-v', '--verbose', - default=False, action="store_true", - help="Print more verbose output.") - - parser.add_argument('-k', '--insecure', - default=False, - action='store_true', - help="Explicitly allow evoqueclient to perform " - "\"insecure\" SSL (https) requests. " - "The server's certificate will " - "not be verified against any certificate " - "authorities. This option should be used " - "with caution.") - - parser.add_argument('--os-cacert', - metavar='', - default=utils.env('OS_CACERT', default=None), - dest='os_cacert', - help='Specify a CA bundle file to use in ' - 'verifying a TLS (https) server certificate. ' - 'Defaults to env[OS_CACERT].') - - parser.add_argument('--cert-file', - help='Path of certificate file to use in SSL ' - 'connection. This file can optionally be ' - 'prepended with the private key.') - - parser.add_argument('--key-file', - help='Path of client key to use ' - 'in SSL connection. This option ' - 'is not necessary if your key ' - 'is prepended to your cert file.') - - parser.add_argument('--ca-file', - dest='os_cacert', - help=('DEPRECATED! Use %(arg)s.') % - {'arg': '--os-cacert'}) - - parser.add_argument('--api-timeout', - help='Number of seconds to wait for an ' - 'API response, ' - 'defaults to system socket timeout.') - - parser.add_argument('--os-username', - default=utils.env('OS_USERNAME'), - help='Defaults to env[OS_USERNAME].') - - parser.add_argument('--os-password', - default=utils.env('OS_PASSWORD'), - help='Defaults to env[OS_PASSWORD].') - - parser.add_argument('--os-tenant-id', - default=utils.env('OS_TENANT_ID'), - help='Defaults to env[OS_TENANT_ID].') - - parser.add_argument('--os-tenant-name', - default=utils.env('OS_TENANT_NAME'), - help='Defaults to env[OS_TENANT_NAME].') - - parser.add_argument('--os-auth-url', - default=utils.env('OS_AUTH_URL'), - help='Defaults to env[OS_AUTH_URL].') - - parser.add_argument('--os-region-name', - default=utils.env('OS_REGION_NAME'), - help='Defaults to env[OS_REGION_NAME].') - - parser.add_argument('--os-auth-token', - default=utils.env('OS_AUTH_TOKEN'), - help='Defaults to env[OS_AUTH_TOKEN].') - - parser.add_argument('--os-no-client-auth', - default=utils.env('OS_NO_CLIENT_AUTH'), - action='store_true', - help="Do not contact keystone for a token. " - "Defaults to env[OS_NO_CLIENT_AUTH].") - - parser.add_argument('--evoque-url', - default=utils.env('EVOQUE_URL'), - help='Defaults to env[EVOQUE_URL].') - - parser.add_argument('--evoque-api-version', - default=utils.env( - 'EVOQUE_API_VERSION', default='1'), - help='Defaults to env[EVOQUE_API_VERSION] ' - 'or 1.') - - parser.add_argument('--os-service-type', - default=utils.env('OS_SERVICE_TYPE'), - help='Defaults to env[OS_SERVICE_TYPE].') - - parser.add_argument('--os-endpoint-type', - default=utils.env('OS_ENDPOINT_TYPE'), - help='Defaults to env[OS_ENDPOINT_TYPE].') - - return parser - - def get_subcommand_parser(self, version): - parser = self.get_base_parser() - - self.subcommands = {} - subparsers = parser.add_subparsers(metavar='') - submodule = utils.import_versioned_module(version, 'shell') - self._find_actions(subparsers, submodule) - self._find_actions(subparsers, self) - - self._add_bash_completion_subparser(subparsers) - - return parser - - def _add_bash_completion_subparser(self, subparsers): - subparser = subparsers.add_parser( - 'bash_completion', - add_help=False, - formatter_class=HelpFormatter - ) - self.subcommands['bash_completion'] = subparser - subparser.set_defaults(func=self.do_bash_completion) - - def _find_actions(self, subparsers, actions_module): - for attr in (a for a in dir(actions_module) if a.startswith('do_')): - # I prefer to be hypen-separated instead of underscores. - command = attr[3:].replace('_', '-') - callback = getattr(actions_module, attr) - desc = callback.__doc__ or '' - help = desc.strip().split('\n')[0] - arguments = getattr(callback, 'arguments', []) - - subparser = subparsers.add_parser(command, help=help, - description=desc, - add_help=False, - formatter_class=HelpFormatter) - subparser.add_argument('-h', '--help', action='help', - help=argparse.SUPPRESS) - self.subcommands[command] = subparser - for (args, kwargs) in arguments: - subparser.add_argument(*args, **kwargs) - subparser.set_defaults(func=callback) - - def _get_ksclient(self, **kwargs): - """Get an endpoint and auth token from Keystone. - - :param username: name of user - :param password: user's password - :param tenant_id: unique identifier of tenant - :param tenant_name: name of tenant - :param auth_url: endpoint to authenticate against - """ - kc_args = { - 'auth_url': kwargs.get('auth_url'), - 'insecure': kwargs.get('insecure'), - 'cacert': kwargs.get('cacert')} - - if kwargs.get('tenant_id'): - kc_args['tenant_id'] = kwargs.get('tenant_id') - else: - kc_args['tenant_name'] = kwargs.get('tenant_name') - - if kwargs.get('token'): - kc_args['token'] = kwargs.get('token') - else: - kc_args['username'] = kwargs.get('username') - kc_args['password'] = kwargs.get('password') - - return ksclient.Client(**kc_args) - - def _setup_logging(self, debug): - # Output the logs to command-line interface - color_handler = handlers.ColorHandler(sys.stdout) - logger_root = logging.getLogger(None).logger - logger_root.level = logging.DEBUG if debug else logging.WARNING - logger_root.addHandler(color_handler) - - # Set the logger level of special library - logging.getLogger('iso8601') \ - .logger.setLevel(logging.WARNING) - logging.getLogger('urllib3.connectionpool') \ - .logger.setLevel(logging.WARNING) - - def main(self, argv): - # Parse args once to find version - parser = self.get_base_parser() - (options, args) = parser.parse_known_args(argv) - self._setup_logging(options.debug) - - # build available subcommands based on version - api_version = options.evoque_api_version - subcommand_parser = self.get_subcommand_parser(api_version) - self.parser = subcommand_parser - - # Handle top-level --help/-h before attempting to parse - # a command off the command line. - if (not args and options.help) or not argv: - self.do_help(options) - return 0 - - # Parse args again and call whatever callback was selected. - args = subcommand_parser.parse_args(argv) - - # Short-circuit and deal with help command right away. - if args.func == self.do_help: - self.do_help(args) - return 0 - elif args.func == self.do_bash_completion: - self.do_bash_completion(args) - return 0 - - if not args.os_username and not args.os_auth_token: - raise exc.CommandError("You must provide a username via" - " either --os-username or env[OS_USERNAME]" - " or a token via --os-auth-token or" - " env[OS_AUTH_TOKEN]") - - if not args.os_password and not args.os_auth_token: - raise exc.CommandError("You must provide a password via" - " either --os-password or env[OS_PASSWORD]" - " or a token via --os-auth-token or" - " env[OS_AUTH_TOKEN]") - - if args.os_no_client_auth: - if not args.evoque_url: - raise exc.CommandError( - "If you specify --os-no-client-auth" - " you must also specify a Evoque API URL" - " via either --evoque-url or env[EVOQUE_URL]") - else: - # Tenant name or ID is needed to make keystoneclient retrieve a - # service catalog, it's not required if os_no_client_auth is - # specified, neither is the auth URL. - if not (args.os_tenant_id or args.os_tenant_name): - raise exc.CommandError("You must provide a tenant name " - "or tenant id via --os-tenant-name, " - "--os-tenant-id, env[OS_TENANT_NAME] " - "or env[OS_TENANT_ID]") - - if not args.os_auth_url: - raise exc.CommandError("You must provide an auth url via" - " either --os-auth-url or via" - " env[OS_AUTH_URL]") - kwargs = { - 'username': args.os_username, - 'password': args.os_password, - 'token': args.os_auth_token, - 'tenant_id': args.os_tenant_id, - 'tenant_name': args.os_tenant_name, - 'auth_url': args.os_auth_url, - 'service_type': args.os_service_type, - 'endpoint_type': args.os_endpoint_type, - 'insecure': args.insecure, - 'cacert': args.os_cacert, - } - - endpoint = args.evoque_url - - if not args.os_no_client_auth: - _ksclient = self._get_ksclient(**kwargs) - token = args.os_auth_token or _ksclient.auth_token - - kwargs = { - 'token': token, - 'insecure': args.insecure, - 'cacert': args.os_cacert, - 'cert_file': args.cert_file, - 'key_file': args.key_file, - 'username': args.os_username, - 'password': args.os_password, - 'endpoint_type': args.os_endpoint_type, - } - glance_kwargs = kwargs.copy() - - if args.os_region_name: - kwargs['region_name'] = args.os_region_name - glance_kwargs['region_name'] = args.os_region_name - - if args.api_timeout: - kwargs['timeout'] = args.api_timeout - - client = apiclient.Client(api_version, endpoint, **kwargs) - - args.func(client, args) - - def do_bash_completion(self, args): - """Prints all of the commands and options to stdout.""" - commands = set() - options = set() - for sc_str, sc in self.subcommands.items(): - commands.add(sc_str) - for option in list(sc._optionals._option_string_actions): - options.add(option) - - commands.remove('bash-completion') - commands.remove('bash_completion') - print(' '.join(commands | options)) - - @utils.arg('command', metavar='', nargs='?', - help='Display help for ') - def do_help(self, args): - """Display help about this program or one of its subcommands. - """ - if getattr(args, 'command', None): - if args.command in self.subcommands: - self.subcommands[args.command].print_help() - else: - msg = "'%s' is not a valid subcommand" - raise exc.CommandError(msg % args.command) - else: - self.parser.print_help() - - -class HelpFormatter(argparse.HelpFormatter): - def start_section(self, heading): - # Title-case the headings - heading = '%s%s' % (heading[0].upper(), heading[1:]) - super(HelpFormatter, self).start_section(heading) - - -def main(args=None): - if args is None: - args = sys.argv[1:] - try: - EvoqueShell().main(args) - - except KeyboardInterrupt: - print('... terminating evoque client', file=sys.stderr) - sys.exit(1) - except Exception as e: - if '--debug' in args or '-d' in args: - raise - else: - print(encodeutils.safe_encode(six.text_type(e)), file=sys.stderr) - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/evoqueclient/tests/__init__.py b/evoqueclient/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/evoqueclient/tests/functional/__init__.py b/evoqueclient/tests/functional/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/evoqueclient/tests/unit/__init__.py b/evoqueclient/tests/unit/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/evoqueclient/tests/unit/test_common.py b/evoqueclient/tests/unit/test_common.py deleted file mode 100644 index 8de3733..0000000 --- a/evoqueclient/tests/unit/test_common.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2015 99Cloud lnc -# -# 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 oslotest import base - - -class BaseTestCase(base.BaseTestCase): - def test_one(self): - pass diff --git a/evoqueclient/v1/__init__.py b/evoqueclient/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/evoqueclient/v1/client.py b/evoqueclient/v1/client.py deleted file mode 100644 index d6810d3..0000000 --- a/evoqueclient/v1/client.py +++ /dev/null @@ -1,27 +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 evoqueclient.common import http -from evoqueclient.v1 import tickets -from evoqueclient.v1 import workflows - - -class Client(http.HTTPClient): - """Client for the Evoque v1 API. - - """ - - def __init__(self, *args, **kwargs): - """Initialize a new client for the Evoque v1 API.""" - super(Client, self).__init__(*args, **kwargs) - self.tickets = tickets.TicketManager(self) - self.workflows = workflows.WorkflowManager(self) diff --git a/evoqueclient/v1/shell.py b/evoqueclient/v1/shell.py deleted file mode 100644 index 7dd42e4..0000000 --- a/evoqueclient/v1/shell.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 os - -from evoqueclient.common.i18n import _ -from evoqueclient.common import utils - - -# Tickets -def do_ticket_list(ec, args={}): - """List all available tickets.""" - tickets = ec.tickets.list() - field_labels = ["ID", "Name", "Status", "Domain", "User_ID", "Domain_id", - "Project", "User", "Type"] - fields = ["id", "name", "status", "domain", "user_id", "domain_id", - "project", "user", "type"] - utils.print_list(tickets, fields, field_labels) - - -@utils.arg("name", metavar="", - help="Ticket name.") -def do_ticket_create(ec, args): - """Create a ticket.""" - ec.tickets.add({"name": args.name}) - - -# Workflows -def do_workflow_list(ec, args={}): - """List all available workflows.""" - workflows = ec.workflows.list() - field_labels = ["ID", "Name", "Status", "Domain", "User_ID", "Domain_id", - "Project", "User"] - fields = ["id", "name", "status", "domain", "user_id", "domain_id", - "project", "user"] - utils.print_list(workflows, fields, field_labels) - - -@utils.arg("-s", "--spec-file", metavar="", required=True, - help=_('The spec file used to create the workflow.')) -@utils.arg("name", metavar="", - help="Workflow name.") -def do_workflow_create(ec, args): - """Create a workflow.""" - spec_file = os.path.abspath(os.path.expanduser(args.spec_file)) - ec.workflows.add({ - "name": args.name, - "wf_spec": open(spec_file).read() - }) diff --git a/evoqueclient/v1/tickets.py b/evoqueclient/v1/tickets.py deleted file mode 100644 index 2195270..0000000 --- a/evoqueclient/v1/tickets.py +++ /dev/null @@ -1,34 +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 evoqueclient.common import base - - -class Ticket(base.Resource): - def __repr__(self): - return "" % self._info - - def data(self, **kwargs): - return self.manager.data(self, **kwargs) - - -class TicketManager(base.Manager): - resource_class = Ticket - - def list(self, **kwargs): - """Get tickets list with pagination support.""" - - url = '/v1/ticket' - return self._list(url, response_key='tickets') - - def add(self, data): - return self._create('/v1/ticket', data) diff --git a/evoqueclient/v1/workflows.py b/evoqueclient/v1/workflows.py deleted file mode 100644 index 59a25a9..0000000 --- a/evoqueclient/v1/workflows.py +++ /dev/null @@ -1,32 +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 evoqueclient.common import base - - -class Workflow(base.Resource): - def __repr__(self): - return "" % self._info - - def data(self, **kwargs): - return self.manager.data(self, **kwargs) - - -class WorkflowManager(base.Manager): - resource_class = Workflow - - def list(self, **kwargs): - url = '/v1/workflow' - return self._list(url, response_key='workflows') - - def add(self, data): - return self._create('/v1/workflow', data) diff --git a/evoqueclient/version.py b/evoqueclient/version.py deleted file mode 100644 index df1dd5a..0000000 --- a/evoqueclient/version.py +++ /dev/null @@ -1,16 +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 pbr import version - -version_info = version.VersionInfo('python-evoqueclient') diff --git a/openstack-common.conf b/openstack-common.conf deleted file mode 100644 index 8ebbf99..0000000 --- a/openstack-common.conf +++ /dev/null @@ -1,10 +0,0 @@ -[DEFAULT] - -# The list of modules to copy from openstack-common -module=apiclient -module=py3kcompat -module=strutils -module=install_venv_common - -# The base module to hold the copy of openstack.common -base=evoqueclient diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 545a41c..0000000 --- a/requirements.txt +++ /dev/null @@ -1,19 +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>=1.6 -PrettyTable<0.8,>=0.7 -httplib2>=0.7.5 -iso8601>=0.1.9 -six>=1.9.0 -Babel>=1.3 -pyOpenSSL>=0.14 -requests!=2.8.0,>=2.5.2 -PyYAML>=3.1.0 - -oslo.i18n>=1.5.0 # Apache-2.0 -oslo.log>=1.8.0 # Apache-2.0 -oslo.serialization>=1.10.0 # Apache-2.0 -oslo.utils!=2.6.0,>=2.4.0 # Apache-2.0 - -python-keystoneclient!=1.8.0,>=1.6.0 diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index 2d69bbe..0000000 --- a/run_tests.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/bin/bash - -function usage { - echo "Usage: $0 [OPTION]..." - echo "Run python-evoqueclient's test suite(s)" - echo "" - echo " -p, --pep8 Just run pep8" - echo " -h, --help Print this usage message" - echo " -V, --virtual-env Always use virtualenv. Install automatically if not present" - echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment" - echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added." - echo " -u, --update Update the virtual environment with any newer package versions" - echo "" - echo "This script is deprecated and currently retained for compatibility." - echo 'You can run the full test suite for multiple environments by running "tox".' - echo 'You can run tests for only python 2.7 by running "tox -e py27", or run only' - echo 'the pep8 tests with "tox -e pep8".' - exit -} - -just_pep8=0 -always_venv=0 -never_venv=0 -wrapper= -update=0 -force=0 - -export NOSE_WITH_OPENSTACK=1 -export NOSE_OPENSTACK_COLOR=1 -export NOSE_OPENSTACK_RED=0.05 -export NOSE_OPENSTACK_YELLOW=0.025 -export NOSE_OPENSTACK_SHOW_ELAPSED=1 -export NOSE_OPENSTACK_STDOUT=1 - - -function process_option { - case "$1" in - -h|--help) usage;; - -p|--pep8) let just_pep8=1;; - -V|--virtual-env) let always_venv=1; let never_venv=0;; - -f|--force) let force=1;; - -u|--update) update=1;; - -N|--no-virtual-env) let always_venv=0; let never_venv=1;; - esac -} - -for arg in "$@"; do - process_option $arg -done - -function run_tests { - # Cleanup *pyc - ${wrapper} find . -type f -name "*.pyc" -delete - # Just run the test suites in current environment - ${wrapper} $NOSETESTS -} - -function run_pep8 { - echo "Running pep8 ..." - PEP8_EXCLUDE=".venv,.tox,dist,doc,openstack,build" - PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --repeat --select=H402" - PEP8_IGNORE="--ignore=E125,E126,E711,E712" - PEP8_INCLUDE="." - pep8 $PEP8_OPTIONS $PEP8_INCLUDE $PEP8_IGNORE -} - -NOSETESTS="nosetests $noseopts $noseargs" - -if [ $never_venv -eq 0 ] -then - # Remove the virtual environment if --force used - if [ $force -eq 1 ]; then - echo "Cleaning virtualenv..." - rm -rf ${venv} - fi - if [ $update -eq 1 ]; then - echo "Updating virtualenv..." - python tools/install_venv.py - fi - if [ -e ${venv} ]; then - wrapper="${with_venv}" - else - if [ $always_venv -eq 1 ]; then - # Automatically install the virtualenv - python tools/install_venv.py - wrapper="${with_venv}" - else - echo -e "No virtual environment found...create one? (Y/n) \c" - read use_ve - if [ "x$use_ve" = "xY" -o "x$use_ve" = "x" -o "x$use_ve" = "xy" ]; then - # Install the virtualenv and run the test suite in it - python tools/install_venv.py - wrapper=${with_venv} - fi - fi - fi -fi - -if [ $just_pep8 -eq 1 ]; then - run_pep8 - exit -fi - -run_tests || exit - -run_pep8 - diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 0454ab3..0000000 --- a/setup.cfg +++ /dev/null @@ -1,45 +0,0 @@ -[metadata] -name = python-evoqueclient -summary = python-evoqueclient -description-file = - README.rst -license = Apache License, Version 2.0 -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://www.openstack.org/ -classifier = - Development Status :: 4 - Beta - Environment :: Console - Intended Audience :: Developers - Intended Audience :: Information Technology - License :: OSI Approved :: Apache Software License - Operating System :: OS Independent - Programming Language :: Python - -[files] -packages = - evoqueclient - -[entry_points] -console_scripts = - evoque = evoqueclient.shell:main - -[global] -setup-hooks = - pbr.hooks.setup_hook - -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/build/html - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 782bb21..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 9e29679..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,20 +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.11,>=0.10 - -coverage>=3.6 -discover -fixtures>=1.3.1 -mock>=1.2 -requests-mock>=0.6.0 # Apache-2.0 -tempest-lib>=0.10.0 -testrepository>=0.0.18 -testscenarios>=0.4 -testtools>=1.4.0 -oslosphinx>=2.5.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 -os-testr>=0.1.0 - -# doc build requirements -sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 diff --git a/tools/evoque.bash_completion b/tools/evoque.bash_completion deleted file mode 100644 index 83213f4..0000000 --- a/tools/evoque.bash_completion +++ /dev/null @@ -1,26 +0,0 @@ -_evoque_opts="" # lazy init -_evoque_flags="" # lazy init -_evoque_opts_exp="" # lazy init -_evoque() -{ - local cur prev kbc - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - - if [ "x$_evoque_opts" == "x" ] ; then - kbc="$(evoque bash-completion | sed -e "s/ -h / /")" - _evoque_opts="$(echo "$kbc" | sed -e "s/--[a-z0-9_-]*//g" -e "s/[ ][ ]*/ /g")" - _evoque_flags="$(echo " $kbc" | sed -e "s/ [^-][^-][a-z0-9_-]*//g" -e "s/[ ][ ]*/ /g")" - _evoque_opts_exp="$(echo "$_evoque_opts" | sed -e "s/[ ]/|/g")" - fi - - if [[ " ${COMP_WORDS[@]} " =~ " "($_evoque_opts_exp)" " && "$prev" != "help" ]] ; then - COMPREPLY=($(compgen -W "${_evoque_flags}" -- "${cur}")) - else - COMPREPLY=($(compgen -W "${_evoque_opts}" -- "${cur}")) - fi - return 0 -} -complete -o default -F _evoque evoque - diff --git a/tools/install_venv.py b/tools/install_venv.py deleted file mode 100644 index 1e0fc14..0000000 --- a/tools/install_venv.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2010 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Copyright 2010 OpenStack Foundation -# Copyright 2013 IBM Corp. -# -# 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. - -""" -Installation script for python-evoqueclient's development virtualenv -""" - -from __future__ import print_function - -import os -import sys - -import install_venv_common as install_venv # noqa - - -def print_help(): - help = """ - python-evoqueclient development environment setup is complete. - - python-evoqueclient development uses virtualenv to track and manage Python dependencies - while in development and testing. - - To activate the python-evoqueclient virtualenv for the extent of your current shell session - you can run: - - $ source .venv/bin/activate - - Or, if you prefer, you can run commands in the virtualenv on a case by case - basis by running: - - $ tools/with_venv.sh - - Also, make test will automatically use the virtualenv. - """ - print(help) - - -def main(argv): - root = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - venv = os.path.join(root, '.venv') - pip_requires = os.path.join(root, 'requirements.txt') - test_requires = os.path.join(root, 'test-requirements.txt') - py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1]) - project = 'python-evoqueclient' - install = install_venv.InstallVenv(root, venv, pip_requires, test_requires, - py_version, project) - options = install.parse_args(argv) - install.check_python_version() - install.check_dependencies() - install.create_virtualenv(no_site_packages=options.no_site_packages) - install.install_dependencies() - install.run_command([os.path.join(venv, 'bin/python'), - 'setup.py', 'develop']) - print_help() - -if __name__ == '__main__': - main(sys.argv) diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py deleted file mode 100644 index 474bec7..0000000 --- a/tools/install_venv_common.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright 2013 OpenStack, LLC -# Copyright 2013 IBM Corp. -# -# 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. - -"""Provides methods needed by installation script for OpenStack development -virtual environments. - -Synced in from openstack-common -""" - -import argparse -import os -import subprocess -import sys - - -class InstallVenv(object): - - def __init__(self, root, venv, requirements, - test_requirements, py_version, - project): - self.root = root - self.venv = venv - self.requirements = requirements - self.test_requirements = test_requirements - self.py_version = py_version - self.project = project - - def die(self, message, *args): - print >> sys.stderr, message % args - sys.exit(1) - - def check_python_version(self): - if sys.version_info < (2, 6): - self.die("Need Python Version >= 2.6") - - def run_command_with_code(self, cmd, redirect_output=True, - check_exit_code=True): - """Runs a command in an out-of-process shell. - - Returns the output of that command. Working directory is self.root. - """ - if redirect_output: - stdout = subprocess.PIPE - else: - stdout = None - - proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout) - output = proc.communicate()[0] - if check_exit_code and proc.returncode != 0: - self.die('Command "%s" failed.\n%s', ' '.join(cmd), output) - return (output, proc.returncode) - - def run_command(self, cmd, redirect_output=True, check_exit_code=True): - return self.run_command_with_code(cmd, redirect_output, - check_exit_code)[0] - - def get_distro(self): - if (os.path.exists('/etc/fedora-release') or - os.path.exists('/etc/redhat-release')): - return Fedora( - self.root, self.venv, self.requirements, - self.test_requirements, self.py_version, self.project) - else: - return Distro( - self.root, self.venv, self.requirements, - self.test_requirements, self.py_version, self.project) - - def check_dependencies(self): - self.get_distro().install_virtualenv() - - def create_virtualenv(self, no_site_packages=True): - """Creates the virtual environment and installs PIP. - - Creates the virtual environment and installs PIP only into the - virtual environment. - """ - if not os.path.isdir(self.venv): - print 'Creating venv...', - if no_site_packages: - self.run_command(['virtualenv', '-q', '--no-site-packages', - self.venv]) - else: - self.run_command(['virtualenv', '-q', self.venv]) - print 'done.' - else: - print "venv already exists..." - pass - - def pip_install(self, *args): - self.run_command(['tools/with_venv.sh', - 'pip', 'install', '--upgrade'] + list(args), - redirect_output=False) - - def install_dependencies(self): - print 'Installing dependencies with pip (this can take a while)...' - - # First things first, make sure our venv has the latest pip and - # distribute. - # NOTE: we keep pip at version 1.1 since the most recent version causes - # the .venv creation to fail. See: - # https://bugs.launchpad.net/nova/+bug/1047120 - self.pip_install('pip==1.1') - self.pip_install('setuptools') - - self.pip_install('-r', self.requirements) - self.pip_install('-r', self.test_requirements) - - def post_process(self): - self.get_distro().post_process() - - def parse_args(self, argv): - """Parses command-line arguments.""" - parser = argparse.ArgumentParser() - parser.add_argument('-n', '--no-site-packages', - action='store_true', - help="Do not inherit packages from global Python " - "install") - return parser.parse_args(argv[1:]) - - -class Distro(InstallVenv): - - def check_cmd(self, cmd): - return bool(self.run_command(['which', cmd], - check_exit_code=False).strip()) - - def install_virtualenv(self): - if self.check_cmd('virtualenv'): - return - - if self.check_cmd('easy_install'): - print 'Installing virtualenv via easy_install...', - if self.run_command(['easy_install', 'virtualenv']): - print 'Succeeded' - return - else: - print 'Failed' - - self.die('ERROR: virtualenv not found.\n\n%s development' - ' requires virtualenv, please install it using your' - ' favorite package management tool' % self.project) - - def post_process(self): - """Any distribution-specific post-processing gets done here. - - In particular, this is useful for applying patches to code inside - the venv. - """ - pass - - -class Fedora(Distro): - """This covers all Fedora-based distributions. - - Includes: Fedora, RHEL, CentOS, Scientific Linux - """ - - def check_pkg(self, pkg): - return self.run_command_with_code(['rpm', '-q', pkg], - check_exit_code=False)[1] == 0 - - def yum_install(self, pkg, **kwargs): - print "Attempting to install '%s' via yum" % pkg - self.run_command(['sudo', 'yum', 'install', '-y', pkg], **kwargs) - - def apply_patch(self, originalfile, patchfile): - self.run_command(['patch', originalfile, patchfile]) - - def install_virtualenv(self): - if self.check_cmd('virtualenv'): - return - - if not self.check_pkg('python-virtualenv'): - self.yum_install('python-virtualenv', check_exit_code=False) - - super(Fedora, self).install_virtualenv() - - def post_process(self): - """Workaround for a bug in eventlet. - - This currently affects RHEL6.1, but the fix can safely be - applied to all RHEL and Fedora distributions. - - This can be removed when the fix is applied upstream. - - Nova: https://bugs.launchpad.net/nova/+bug/884915 - Upstream: https://bitbucket.org/which_linden/eventlet/issue/89 - """ - - # Install "patch" program if it's not there - if not self.check_pkg('patch'): - self.yum_install('patch') - - # Apply the eventlet patch - self.apply_patch(os.path.join(self.venv, 'lib', self.py_version, - 'site-packages', - 'eventlet/green/subprocess.py'), - 'contrib/redhat-eventlet.patch') diff --git a/tools/with_venv.sh b/tools/with_venv.sh deleted file mode 100755 index c8d2940..0000000 --- a/tools/with_venv.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -TOOLS=`dirname $0` -VENV=$TOOLS/../.venv -source $VENV/bin/activate && $@ diff --git a/tox.ini b/tox.ini deleted file mode 100644 index ae334c1..0000000 --- a/tox.ini +++ /dev/null @@ -1,38 +0,0 @@ -[tox] -envlist = py27,pep8 -minversion = 1.6 -skipsdist = True - -[testenv] -usedevelop = True -whitelist_externals = bash -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:docs] -commands = python setup.py build_sphinx - -[testenv:pep8] -commands = flake8 {posargs} - -[testenv:venv] -commands = {posargs} - -[testenv:cover] -commands = python setup.py testr --coverage --testr-args='--concurrency 1 {posargs}' - -[testenv:pyflakes] -deps = flake8 -commands = flake8 - -[flake8] -# H405 multi line docstring summary not separated with an empty line -ignore = H405 -show-source = true -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,tools