diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 2b789e1..0000000 --- a/.coveragerc +++ /dev/null @@ -1,13 +0,0 @@ -[run] -branch = True -source = saharaclient -omit = - */openstack/common/* - .tox/* - saharaclient/tests/* - -[paths] -source = saharaclient - -[report] -ignore_errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 393b55d..0000000 --- a/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -*.py[co] -*.egg -*.egg-info -dist -build -eggs -parts -var -sdist -develop-eggs -.installed.cfg -pip-log.txt -.tox -*.mo -.mr.developer.cfg -.DS_Store -Thumbs.db -.venv -.idea -out -target -*.iml -*.ipr -*.iws -*.db -.coverage -nosetests.xml -pylint-report.txt -ChangeLog -cscope.out -.testrepository -AUTHORS -cover -doc/html -doc/source/apidoc -doc/source/api -doc/build -*.log -# Files created by releasenotes build -releasenotes/build diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 0593a6d..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/python-saharaclient.git diff --git a/.testr.conf b/.testr.conf deleted file mode 100755 index 4da4d7d..0000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover $DISCOVER_DIRECTORY $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 a04c76b..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,21 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps in the "If you're a developer" -section of this page: - - http://wiki.openstack.org/HowToContribute - -You can find more Sahara-specific info in our How To Participate guide: - - http://docs.openstack.org/developer/python-saharaclient/devref/how_to_participate.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://wiki.openstack.org/GerritWorkflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/python-saharaclient diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 6568acd..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,12 +0,0 @@ -Sahara Style Commandments -========================= - -- Step 1: Read the OpenStack Style Commandments - http://docs.openstack.org/developer/hacking/ -- Step 2: Read on - -Sahara Specific Commandments ----------------------------- - -None so far - 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/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index f1c38fb..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,9 +0,0 @@ -include AUTHORS -include README.rst -include ChangeLog -include LICENSE - -exclude .gitignore -exclude .gitreview - -global-exclude *.pyc diff --git a/README.rst b/README.rst deleted file mode 100644 index 06a2134..0000000 --- a/README.rst +++ /dev/null @@ -1,41 +0,0 @@ -Python bindings to the OpenStack Sahara API -=========================================== - -.. image:: https://img.shields.io/pypi/v/python-saharaclient.svg - :target: https://pypi.python.org/pypi/python-saharaclient/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/python-saharaclient.svg - :target: https://pypi.python.org/pypi/python-saharaclient/ - :alt: Downloads - -This is a client for the OpenStack Sahara API. There's a Python API (the -``saharaclient`` module), and a command-line script (``sahara``). Each -implements the OpenStack Sahara API. You can find documentation for both -Python bindings and CLI in `Docs`_. - -Development takes place via the usual OpenStack processes as outlined -in the `developer guide -`_. - -.. _Docs: http://docs.openstack.org/developer/python-saharaclient/ - -* License: Apache License, Version 2.0 -* `PyPi`_ - package installation -* `Online Documentation`_ -* `Launchpad project`_ - release management -* `Blueprints`_ - feature specifications -* `Bugs`_ - issue tracking -* `Source`_ -* `Specs`_ -* `How to Contribute`_ - -.. _PyPi: https://pypi.python.org/pypi/python-saharaclient -.. _Online Documentation: http://docs.openstack.org/developer/python-saharaclient -.. _Launchpad project: https://launchpad.net/python-saharaclient -.. _Blueprints: https://blueprints.launchpad.net/python-saharaclient -.. _Bugs: https://bugs.launchpad.net/python-saharaclient -.. _Source: https://git.openstack.org/cgit/openstack/python-saharaclient -.. _How to Contribute: http://docs.openstack.org/infra/manual/developers.html -.. _Specs: http://specs.openstack.org/openstack/sahara-specs/ - diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..07a04ab --- /dev/null +++ b/README.txt @@ -0,0 +1,13 @@ +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". + +Use instead the project deb-python-saharaclient at +http://git.openstack.org/cgit/openstack/deb-python-saharaclient . + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/doc/ext/__init__.py b/doc/ext/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/doc/ext/cli.py b/doc/ext/cli.py deleted file mode 100644 index feb28d7..0000000 --- a/doc/ext/cli.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) 2015 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import inspect -import os -import sys - -from docutils import nodes -from . import ext - - -def _get_command(classes): - """Associates each command class with command depending on setup.cfg - """ - commands = {} - setup_file = os.path.join( - os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')), - 'setup.cfg') - for line in open(setup_file, 'r'): - for cl in classes: - if cl in line: - commands[cl] = line.split(' = ')[0].strip().replace('_', ' ') - - return commands - - -class ArgParseDirectiveOSC(ext.ArgParseDirective): - """Sphinx extension that automatically documents commands and options - of the module that contains OpenstackClient/cliff command objects - - Usage example: - - .. cli:: - :module: saharaclient.osc.v1.clusters - - """ - def run(self): - module_name = self.options['module'] - - mod = __import__(module_name, globals(), locals()) - - classes = inspect.getmembers(sys.modules[module_name], inspect.isclass) - classes_names = [cl[0] for cl in classes] - commands = _get_command(classes_names) - - items = [] - - for cl in classes: - parser = cl[1](None, None).get_parser(None) - parser.prog = commands[cl[0]] - items.append(nodes.subtitle(text=commands[cl[0]])) - result = ext.parse_parser( - parser, skip_default_values='nodefault' in self.options) - result = ext.parser_navigate(result, '') - nested_content = ext.nodes.paragraph() - self.state.nested_parse( - self.content, self.content_offset, nested_content) - nested_content = nested_content.children - - for item in nested_content: - if not isinstance(item, ext.nodes.definition_list): - items.append(item) - if 'description' in result: - items.append(self._nested_parse_paragraph(result['description'])) - items.append(ext.nodes.literal_block(text=result['usage'])) - items.append(ext.print_command_args_and_opts( - ext.print_arg_list(result, nested_content), - ext.print_opt_list(result, nested_content), - ext.print_subcommand_list(result, nested_content) - )) - if 'epilog' in result: - items.append(self._nested_parse_paragraph(result['epilog'])) - return items - - -def setup(app): - app.add_directive('cli', ArgParseDirectiveOSC) diff --git a/doc/ext/ext.py b/doc/ext/ext.py deleted file mode 100644 index 9b07ab1..0000000 --- a/doc/ext/ext.py +++ /dev/null @@ -1,386 +0,0 @@ -# Copyright (c) 2013 Alex Rudakov -# -# 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 argparse import ArgumentParser -import os - -from docutils import nodes -from docutils.statemachine import StringList -from docutils.parsers.rst.directives import flag, unchanged -from sphinx.util.compat import Directive -from sphinx.util.nodes import nested_parse_with_titles - -from .parser import parse_parser, parser_navigate - - -def map_nested_definitions(nested_content): - if nested_content is None: - raise Exception('Nested content should be iterable, not null') - # build definition dictionary - definitions = {} - for item in nested_content: - if not isinstance(item, nodes.definition_list): - continue - for subitem in item: - if not isinstance(subitem, nodes.definition_list_item): - continue - if not len(subitem.children) > 0: - continue - classifier = '@after' - idx = subitem.first_child_matching_class(nodes.classifier) - if idx is not None: - ci = subitem[idx] - if len(ci.children) > 0: - classifier = ci.children[0].astext() - if classifier is not None and classifier not in ( - '@replace', '@before', '@after'): - raise Exception('Unknown classifier: %s' % classifier) - idx = subitem.first_child_matching_class(nodes.term) - if idx is not None: - ch = subitem[idx] - if len(ch.children) > 0: - term = ch.children[0].astext() - idx = subitem.first_child_matching_class(nodes.definition) - if idx is not None: - def_node = subitem[idx] - def_node.attributes['classifier'] = classifier - definitions[term] = def_node - return definitions - - -def print_arg_list(data, nested_content): - definitions = map_nested_definitions(nested_content) - items = [] - if 'args' in data: - for arg in data['args']: - my_def = [nodes.paragraph(text=arg['help'])] if arg['help'] else [] - name = arg['name'] - my_def = apply_definition(definitions, my_def, name) - if len(my_def) == 0: - my_def.append(nodes.paragraph(text='Undocumented')) - if 'choices' in arg: - my_def.append(nodes.paragraph( - text=('Possible choices: %s' % ', '.join([str(c) for c in arg['choices']])))) - items.append( - nodes.option_list_item( - '', nodes.option_group('', nodes.option_string(text=name)), - nodes.description('', *my_def))) - return nodes.option_list('', *items) if items else None - - -def print_opt_list(data, nested_content): - definitions = map_nested_definitions(nested_content) - items = [] - if 'options' in data: - for opt in data['options']: - names = [] - my_def = [nodes.paragraph(text=opt['help'])] if opt['help'] else [] - for name in opt['name']: - option_declaration = [nodes.option_string(text=name)] - if opt['default'] is not None \ - and opt['default'] != '==SUPPRESS==': - option_declaration += nodes.option_argument( - '', text='=' + str(opt['default'])) - names.append(nodes.option('', *option_declaration)) - my_def = apply_definition(definitions, my_def, name) - if len(my_def) == 0: - my_def.append(nodes.paragraph(text='Undocumented')) - if 'choices' in opt: - my_def.append(nodes.paragraph( - text=('Possible choices: %s' % ', '.join([str(c) for c in opt['choices']])))) - items.append( - nodes.option_list_item( - '', nodes.option_group('', *names), - nodes.description('', *my_def))) - return nodes.option_list('', *items) if items else None - - -def print_command_args_and_opts(arg_list, opt_list, sub_list=None): - items = [] - if arg_list: - items.append(nodes.definition_list_item( - '', nodes.term(text='Positional arguments:'), - nodes.definition('', arg_list))) - if opt_list: - items.append(nodes.definition_list_item( - '', nodes.term(text='Options:'), - nodes.definition('', opt_list))) - if sub_list and len(sub_list): - items.append(nodes.definition_list_item( - '', nodes.term(text='Sub-commands:'), - nodes.definition('', sub_list))) - return nodes.definition_list('', *items) - - -def apply_definition(definitions, my_def, name): - if name in definitions: - definition = definitions[name] - classifier = definition['classifier'] - if classifier == '@replace': - return definition.children - if classifier == '@after': - return my_def + definition.children - if classifier == '@before': - return definition.children + my_def - raise Exception('Unknown classifier: %s' % classifier) - return my_def - - -def print_subcommand_list(data, nested_content): - definitions = map_nested_definitions(nested_content) - items = [] - if 'children' in data: - for child in data['children']: - my_def = [nodes.paragraph( - text=child['help'])] if child['help'] else [] - name = child['name'] - my_def = apply_definition(definitions, my_def, name) - if len(my_def) == 0: - my_def.append(nodes.paragraph(text='Undocumented')) - if 'description' in child: - my_def.append(nodes.paragraph(text=child['description'])) - my_def.append(nodes.literal_block(text=child['usage'])) - my_def.append(print_command_args_and_opts( - print_arg_list(child, nested_content), - print_opt_list(child, nested_content), - print_subcommand_list(child, nested_content) - )) - items.append( - nodes.definition_list_item( - '', - nodes.term('', '', nodes.strong(text=name)), - nodes.definition('', *my_def) - ) - ) - return nodes.definition_list('', *items) - - -class ArgParseDirective(Directive): - has_content = True - option_spec = dict(module=unchanged, func=unchanged, ref=unchanged, - prog=unchanged, path=unchanged, nodefault=flag, - manpage=unchanged, nosubcommands=unchanged, passparser=flag) - - def _construct_manpage_specific_structure(self, parser_info): - """ - Construct a typical man page consisting of the following elements: - NAME (automatically generated, out of our control) - SYNOPSIS - DESCRIPTION - OPTIONS - FILES - SEE ALSO - BUGS - """ - # SYNOPSIS section - synopsis_section = nodes.section( - '', - nodes.title(text='Synopsis'), - nodes.literal_block(text=parser_info["bare_usage"]), - ids=['synopsis-section']) - # DESCRIPTION section - description_section = nodes.section( - '', - nodes.title(text='Description'), - nodes.paragraph(text=parser_info.get( - 'description', parser_info.get( - 'help', "undocumented").capitalize())), - ids=['description-section']) - nested_parse_with_titles( - self.state, self.content, description_section) - if parser_info.get('epilog'): - # TODO: do whatever sphinx does to understand ReST inside - # docstrings magically imported from other places. The nested - # parse method invoked above seem to be able to do this but - # I haven't found a way to do it for arbitrary text - description_section += nodes.paragraph( - text=parser_info['epilog']) - # OPTIONS section - options_section = nodes.section( - '', - nodes.title(text='Options'), - ids=['options-section']) - if 'args' in parser_info: - options_section += nodes.paragraph() - options_section += nodes.subtitle(text='Positional arguments:') - options_section += self._format_positional_arguments(parser_info) - if 'options' in parser_info: - options_section += nodes.paragraph() - options_section += nodes.subtitle(text='Optional arguments:') - options_section += self._format_optional_arguments(parser_info) - items = [ - # NOTE: we cannot generate NAME ourselves. It is generated by - # docutils.writers.manpage - synopsis_section, - description_section, - # TODO: files - # TODO: see also - # TODO: bugs - ] - if len(options_section.children) > 1: - items.append(options_section) - if 'nosubcommands' not in self.options: - # SUBCOMMANDS section (non-standard) - subcommands_section = nodes.section( - '', - nodes.title(text='Sub-Commands'), - ids=['subcommands-section']) - if 'children' in parser_info: - subcommands_section += self._format_subcommands(parser_info) - if len(subcommands_section) > 1: - items.append(subcommands_section) - if os.getenv("INCLUDE_DEBUG_SECTION"): - import json - # DEBUG section (non-standard) - debug_section = nodes.section( - '', - nodes.title(text="Argparse + Sphinx Debugging"), - nodes.literal_block(text=json.dumps(parser_info, indent=' ')), - ids=['debug-section']) - items.append(debug_section) - return items - - def _format_positional_arguments(self, parser_info): - assert 'args' in parser_info - items = [] - for arg in parser_info['args']: - arg_items = [] - if arg['help']: - arg_items.append(nodes.paragraph(text=arg['help'])) - else: - arg_items.append(nodes.paragraph(text='Undocumented')) - if 'choices' in arg: - arg_items.append( - nodes.paragraph( - text='Possible choices: ' + ', '.join(arg['choices']))) - items.append( - nodes.option_list_item( - '', - nodes.option_group( - '', nodes.option( - '', nodes.option_string(text=arg['metavar']) - ) - ), - nodes.description('', *arg_items))) - return nodes.option_list('', *items) - - def _format_optional_arguments(self, parser_info): - assert 'options' in parser_info - items = [] - for opt in parser_info['options']: - names = [] - opt_items = [] - for name in opt['name']: - option_declaration = [nodes.option_string(text=name)] - if opt['default'] is not None \ - and opt['default'] != '==SUPPRESS==': - option_declaration += nodes.option_argument( - '', text='=' + str(opt['default'])) - names.append(nodes.option('', *option_declaration)) - if opt['help']: - opt_items.append(nodes.paragraph(text=opt['help'])) - else: - opt_items.append(nodes.paragraph(text='Undocumented')) - if 'choices' in opt: - opt_items.append( - nodes.paragraph( - text='Possible choices: ' + ', '.join(opt['choices']))) - items.append( - nodes.option_list_item( - '', nodes.option_group('', *names), - nodes.description('', *opt_items))) - return nodes.option_list('', *items) - - def _format_subcommands(self, parser_info): - assert 'children' in parser_info - items = [] - for subcmd in parser_info['children']: - subcmd_items = [] - if subcmd['help']: - subcmd_items.append(nodes.paragraph(text=subcmd['help'])) - else: - subcmd_items.append(nodes.paragraph(text='Undocumented')) - items.append( - nodes.definition_list_item( - '', - nodes.term('', '', nodes.strong( - text=subcmd['bare_usage'])), - nodes.definition('', *subcmd_items))) - return nodes.definition_list('', *items) - - def _nested_parse_paragraph(self, text): - content = nodes.paragraph() - self.state.nested_parse(StringList(text.split("\n")), 0, content) - return content - - def run(self): - if 'module' in self.options and 'func' in self.options: - module_name = self.options['module'] - attr_name = self.options['func'] - elif 'ref' in self.options: - _parts = self.options['ref'].split('.') - module_name = '.'.join(_parts[0:-1]) - attr_name = _parts[-1] - else: - raise self.error( - ':module: and :func: should be specified, or :ref:') - mod = __import__(module_name, globals(), locals(), [attr_name]) - if not hasattr(mod, attr_name): - raise self.error(( - 'Module "%s" has no attribute "%s"\n' - 'Incorrect argparse :module: or :func: values?' - ) % (module_name, attr_name)) - func = getattr(mod, attr_name) - if isinstance(func, ArgumentParser): - parser = func - elif 'passparser' in self.options: - parser = ArgumentParser() - func(parser) - else: - parser = func() - if 'path' not in self.options: - self.options['path'] = '' - path = str(self.options['path']) - if 'prog' in self.options: - parser.prog = self.options['prog'] - result = parse_parser( - parser, skip_default_values='nodefault' in self.options) - result = parser_navigate(result, path) - if 'manpage' in self.options: - return self._construct_manpage_specific_structure(result) - nested_content = nodes.paragraph() - self.state.nested_parse( - self.content, self.content_offset, nested_content) - nested_content = nested_content.children - items = [] - # add common content between - for item in nested_content: - if not isinstance(item, nodes.definition_list): - items.append(item) - if 'description' in result: - items.append(self._nested_parse_paragraph(result['description'])) - items.append(nodes.literal_block(text=result['usage'])) - items.append(print_command_args_and_opts( - print_arg_list(result, nested_content), - print_opt_list(result, nested_content), - print_subcommand_list(result, nested_content) - )) - if 'epilog' in result: - items.append(self._nested_parse_paragraph(result['epilog'])) - return items - - -def setup(app): - app.add_directive('argparse', ArgParseDirective) \ No newline at end of file diff --git a/doc/ext/parser.py b/doc/ext/parser.py deleted file mode 100644 index fbb8feb..0000000 --- a/doc/ext/parser.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (c) 2013 Alex Rudakov -# -# 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 argparse import _HelpAction, _SubParsersAction -import re - - -class NavigationException(Exception): - pass - - -def parser_navigate(parser_result, path, current_path=None): - if isinstance(path, str): - if path == '': - return parser_result - path = re.split('\s+', path) - current_path = current_path or [] - if len(path) == 0: - return parser_result - if 'children' not in parser_result: - raise NavigationException( - 'Current parser have no children elements. (path: %s)' % - ' '.join(current_path)) - next_hop = path.pop(0) - for child in parser_result['children']: - if child['name'] == next_hop: - current_path.append(next_hop) - return parser_navigate(child, path, current_path) - raise NavigationException( - 'Current parser have no children element with name: %s (path: %s)' % ( - next_hop, ' '.join(current_path))) - - -def _try_add_parser_attribute(data, parser, attribname): - attribval = getattr(parser, attribname, None) - if attribval is None: - return - if not isinstance(attribval, str): - return - if len(attribval) > 0: - data[attribname] = attribval - - -def _format_usage_without_prefix(parser): - """ - Use private argparse APIs to get the usage string without - the 'usage: ' prefix. - """ - fmt = parser._get_formatter() - fmt.add_usage(parser.usage, parser._actions, - parser._mutually_exclusive_groups, prefix='') - return fmt.format_help().strip() - - -def parse_parser(parser, data=None, **kwargs): - if data is None: - data = { - 'name': '', - 'usage': parser.format_usage().strip(), - 'bare_usage': _format_usage_without_prefix(parser), - 'prog': parser.prog, - } - _try_add_parser_attribute(data, parser, 'description') - _try_add_parser_attribute(data, parser, 'epilog') - for action in parser._get_positional_actions(): - if isinstance(action, _HelpAction): - continue - if isinstance(action, _SubParsersAction): - helps = {} - for item in action._choices_actions: - helps[item.dest] = item.help - - # commands which share an existing parser are an alias, - # don't duplicate docs - subsection_alias = {} - subsection_alias_names = set() - for name, subaction in action._name_parser_map.items(): - if subaction not in subsection_alias: - subsection_alias[subaction] = [] - else: - subsection_alias[subaction].append(name) - subsection_alias_names.add(name) - - for name, subaction in action._name_parser_map.items(): - if name in subsection_alias_names: - continue - subalias = subsection_alias[subaction] - subaction.prog = '%s %s' % (parser.prog, name) - subdata = { - 'name': name if not subalias else - '%s (%s)' % (name, ', '.join(subalias)), - 'help': helps.get(name, ''), - 'usage': subaction.format_usage().strip(), - 'bare_usage': _format_usage_without_prefix(subaction), - } - parse_parser(subaction, subdata, **kwargs) - data.setdefault('children', []).append(subdata) - continue - if 'args' not in data: - data['args'] = [] - arg = { - 'name': action.dest, - 'help': action.help or '', - 'metavar': action.metavar - } - if action.choices: - arg['choices'] = action.choices - data['args'].append(arg) - show_defaults = ( - ('skip_default_values' not in kwargs) - or (kwargs['skip_default_values'] is False)) - for action in parser._get_optional_actions(): - if isinstance(action, _HelpAction): - continue - if 'options' not in data: - data['options'] = [] - option = { - 'name': action.option_strings, - 'default': action.default if show_defaults else '==SUPPRESS==', - 'help': action.help or '' - } - if action.choices: - option['choices'] = action.choices - if "==SUPPRESS==" not in option['help']: - data['options'].append(option) - return data diff --git a/doc/source/_templates/sidebarlinks.html b/doc/source/_templates/sidebarlinks.html deleted file mode 100644 index af88d86..0000000 --- a/doc/source/_templates/sidebarlinks.html +++ /dev/null @@ -1,11 +0,0 @@ -

Useful Links

- - -{% if READTHEDOCS %} - -{% endif %} diff --git a/doc/source/_theme_rtd/layout.html b/doc/source/_theme_rtd/layout.html deleted file mode 100644 index cd7ade1..0000000 --- a/doc/source/_theme_rtd/layout.html +++ /dev/null @@ -1,4 +0,0 @@ -{% extends "basic/layout.html" %} -{% set css_files = css_files + ['_static/tweaks.css'] %} - -{% block relbar1 %}{% endblock relbar1 %} \ No newline at end of file diff --git a/doc/source/_theme_rtd/theme.conf b/doc/source/_theme_rtd/theme.conf deleted file mode 100644 index 8c44b0c..0000000 --- a/doc/source/_theme_rtd/theme.conf +++ /dev/null @@ -1,4 +0,0 @@ -[theme] -inherit = nature -stylesheet = nature.css -pygments_style = tango \ No newline at end of file diff --git a/doc/source/api.rst b/doc/source/api.rst deleted file mode 100644 index f49e663..0000000 --- a/doc/source/api.rst +++ /dev/null @@ -1,167 +0,0 @@ -Sahara Client -============= - -Overview --------- - -Sahara Client provides a list of Python interfaces to communicate with the -Sahara REST API. Sahara Client enables users to perform most of the existing -operations like retrieving template lists, creating Clusters, submitting EDP -Jobs, etc. - - -Instantiating a Client ----------------------- - -To start using the Sahara Client users have to create an instance of the -`Client` class. The client constructor has a list of parameters to authenticate -and locate Sahara endpoint. - -.. autoclass:: saharaclient.api.client.Client - :members: - -**Important!** - It is not a mandatory rule to provide all of the parameters above. The minimum - number should be enough to determine Sahara endpoint, check user - authentication and tenant to operate in. - -Authentication check -~~~~~~~~~~~~~~~~~~~~ - -Passing authentication parameters to Sahara Client is deprecated. Keystone -Session object should be used for this purpose. For example: - -.. sourcecode:: python - - from keystoneauth1.identity import v2 - from keystoneauth1 import session - from saharaclient import client - - auth = v2.Password(auth_url=AUTH_URL, - username=USERNAME, - password=PASSWORD, - tenant_name=PROJECT_ID) - - ses = session.Session(auth=auth) - - sahara = client.Client('1.1', session=ses) -.. - -For more information about Keystone Sessions, see `Using Sessions`_. - -.. _Using Sessions: http://docs.openstack.org/developer/python-keystoneclient/using-sessions.html - -Sahara endpoint discovery -~~~~~~~~~~~~~~~~~~~~~~~~~ - -If user has a direct URL pointing to Sahara REST API, it may be specified as -`sahara_url`. If this parameter is missing, Sahara client will use Keystone -Service Catalog to find the endpoint. There are two parameters: `service_type` -and `endpoint_type` to configure endpoint search. Both parameters have -default values. - -.. sourcecode:: python - - from keystoneauth1.identity import v2 - from keystoneauth1 import session - from saharaclient import client - - auth = v2.Password(auth_url=AUTH_URL, - username=USERNAME, - password=PASSWORD, - tenant_name=PROJECT_ID) - - ses = session.Session(auth=auth) - - sahara = client.Client('1.1', session=ses, - service_type="non-default-service-type", - endpoint_type="internalURL") -.. - -Object managers ---------------- -Sahara Client has a list of fields to operate with: - - * plugins - * clusters - * cluster_templates - * node_group_templates - * images - * data_sources - * job_binaries - * job_binary_internals - * job_executions - * job_types - -Each of this fields is a reference to a Manager for a corresponding group of -REST calls. - - -Supported operations --------------------- - -Plugin ops -~~~~~~~~~~ - -.. autoclass:: saharaclient.api.plugins.PluginManager - :members: - -Image Registry ops -~~~~~~~~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.images.ImageManager - :members: - -Node Group Template ops -~~~~~~~~~~~~~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.node_group_templates.NodeGroupTemplateManager - :members: - -Cluster Template ops -~~~~~~~~~~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.cluster_templates.ClusterTemplateManager - :members: - -Cluster ops -~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.clusters.ClusterManager - :members: - -Data Source ops -~~~~~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.data_sources.DataSourceManager - :members: - -Job Binary Internal ops -~~~~~~~~~~~~~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.job_binary_internals.JobBinaryInternalsManager - :members: create, update - -Job Binary ops -~~~~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.job_binaries.JobBinariesManager - :members: - -Job ops -~~~~~~~ - -.. autoclass:: saharaclient.api.jobs.JobsManager - :members: - -Job Execution ops -~~~~~~~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.job_executions.JobExecutionsManager - :members: - -Job Types ops -~~~~~~~~~~~~~ - -.. autoclass:: saharaclient.api.job_types.JobTypesManager - :members: diff --git a/doc/source/cli.rst b/doc/source/cli.rst deleted file mode 100644 index 62637f0..0000000 --- a/doc/source/cli.rst +++ /dev/null @@ -1,64 +0,0 @@ -Sahara CLI Commands -=================== - -The following commands are currently supported by the Sahara CLI: - -Plugins -------- - -.. cli:: - :module: saharaclient.osc.v1.plugins - -Images ------- - -.. cli:: - :module: saharaclient.osc.v1.images - -Node Group Templates --------------------- - -.. cli:: - :module: saharaclient.osc.v1.node_group_templates - -Cluster Templates ------------------ - -.. cli:: - :module: saharaclient.osc.v1.cluster_templates - -Clusters --------- - -.. cli:: - :module: saharaclient.osc.v1.clusters - -Data Sources ------------- - -.. cli:: - :module: saharaclient.osc.v1.data_sources - -Job Binaries ------------- - -.. cli:: - :module: saharaclient.osc.v1.job_binaries - -Job Types ---------- - -.. cli:: - :module: saharaclient.osc.v1.job_types - -Job Templates -------------- - -.. cli:: - :module: saharaclient.osc.v1.job_templates - -Jobs ----- - -.. cli:: - :module: saharaclient.osc.v1.jobs diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index fd50871..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,271 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import subprocess -import sys - -import os - -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) -sys.path.insert(0, os.path.abspath('../../saharaclient')) -sys.path.append(os.path.abspath('..')) -sys.path.append(os.path.abspath('../bin')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.viewcode', 'ext.cli'] - -if not on_rtd: - extensions.append('oslosphinx') - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Sahara Client' -copyright = u'2013, OpenStack Foundation' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# Version info -from saharaclient.version import version_info as saharaclient_version -release = saharaclient_version.release_string() -# The short X.Y version. -version = saharaclient_version.version_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. - -if on_rtd: - html_theme_path = ['.'] - html_theme = '_theme_rtd' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -html_title = 'Sahara Client' - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' -git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local", - "-n1"] -html_last_updated_fmt = subprocess.Popen( - git_cmd, stdout=subprocess.PIPE).communicate()[0] - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -html_sidebars = { - 'index': ['sidebarlinks.html', 'localtoc.html', 'searchbox.html', 'sourcelink.html'], - '**': ['localtoc.html', 'relations.html', - 'searchbox.html', 'sourcelink.html'] -} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'SaharaClientDoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - #'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - #'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'saharaclientdoc.tex', u'Sahara Client', - u'OpenStack Foundation', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'saharaclient', u'Sahara Client', - [u'OpenStack Foundation'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'Sahara Client', u'Sahara Client', - u'OpenStack Foundation', 'Sahara Client', 'Sahara Client', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' diff --git a/doc/source/how_to_participate.rst b/doc/source/how_to_participate.rst deleted file mode 100644 index 14c1ee0..0000000 --- a/doc/source/how_to_participate.rst +++ /dev/null @@ -1,68 +0,0 @@ -How to Participate -================== - -Getting started ---------------- - -* Create account on `Github `_ - (if you don't have one) - - * Make sure that your local git is properly configured by executing - ``git config --list``. If not, configure ``user.name``, ``user.email`` - -* Create account on `Launchpad `_ - (if you don't have one) - -* Subscribe to `OpenStack general mail-list `_ - -* Subscribe to `OpenStack development mail-list `_ - -* Create `OpenStack profile `_ - -* Login to `OpenStack Gerrit `_ with your - Launchpad id - - * Sign `OpenStack Individual Contributor License Agreement `_ - * Make sure that your email is listed in `identities `_ - -* Subscribe to code-reviews. Go to your settings on http://review.openstack.org - - * Go to ``watched projects`` - * Add ``openstack/sahara``, ``openstack/sahara-dashboard``, - ``openstack/sahara-extra``, ``openstack/python-saharaclient``, - ``openstack/sahara-image-elements``, ``openstack/horizon`` - - -How to stay in touch with the community? ----------------------------------------- - -* If you have something to discuss use - `OpenStack development mail-list `_. - Prefix mail subject with ``[Sahara]`` - -* Join ``#openstack-sahara`` IRC channel on `freenode `_ - -* Join public weekly meetings on *Thursdays at 18:00 UTC* on - ``#openstack-meeting-alt`` IRC channel -* Join public weekly meetings on *Thursdays at 14:00 UTC* on - ``#openstack-meeting-3`` IRC channel - - -How to send your first patch on review? ---------------------------------------- - -* Checkout Sahara code from `Github `_ - -* Carefully read https://wiki.openstack.org/wiki/Gerrit_Workflow - - * Pay special attention to https://wiki.openstack.org/wiki/Gerrit_Workflow#Committing_Changes - -* Apply and commit your changes - -* Make sure that your code passes ``PEP8`` checks and unit-tests - -* Send your patch on review - -* Monitor status of your patch review on https://review.openstack.org/#/ - - diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 50a3d08..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,42 +0,0 @@ -Python bindings to the OpenStack Sahara API -=========================================== - -This is a client for OpenStack Sahara API. There's :doc:`a Python API -` (the :mod:`saharaclient` module), and a :doc:`command-line utility -` (installed as an OpenStackClient plugin). Each implements the entire -OpenStack Sahara API. - -You'll need credentials for an OpenStack cloud that implements the -Data Processing API, in order to use the sahara client. - -You may want to read the `OpenStack Sahara Docs`__ -- the overview, at -least -- to get an idea of the concepts. By understanding the concepts -this library should make more sense. - - __ http://docs.openstack.org/developer/sahara/ - -Contents: - -.. toctree:: - :maxdepth: 2 - - api - shell - cli - how_to_participate - -Contributing -============ - -Code is hosted in `review.o.o`_ and mirrored to `github`_ and `git.o.o`_ . -Submit bugs to the Sahara project on `launchpad`_ and to the Sahara client on -`launchpad_client`_. Submit code to the openstack/python-saharaclient project -using `gerrit`_. - -.. _review.o.o: https://review.openstack.org -.. _github: https://github.com/openstack/python-saharaclient -.. _git.o.o: http://git.openstack.org/cgit/openstack/python-saharaclient -.. _launchpad: https://launchpad.net/sahara -.. _launchpad_client: https://launchpad.net/python-saharaclient -.. _gerrit: http://docs.openstack.org/infra/manual/developers.html#development-workflow - diff --git a/doc/source/shell.rst b/doc/source/shell.rst deleted file mode 100644 index 6c6249e..0000000 --- a/doc/source/shell.rst +++ /dev/null @@ -1,64 +0,0 @@ -Sahara CLI -========== - -The Sahara shell utility now is part of the OpenStackClient, so all -shell commands take the following form: - -.. code-block:: bash - - $ openstack dataprocessing [arguments...] - -To get a list of all possible commands you can run: - -.. code-block:: bash - - $ openstack help dataprocessing - -To get detailed help for the command you can run: - -.. code-block:: bash - - $ openstack help dataprocessing - -For more information about commands and their parameters you can refer to -:doc:`the Sahara CLI commands `. - -For more information about abilities and features of OpenStackClient CLI you -can refer to `OpenStackClient documentation `_ - -Configuration -------------- - -The CLI is configured via environment variables and command-line options which -are described in http://docs.openstack.org/developer/python-openstackclient/authentication.html. - -Authentication using username/password is most commonly used and can be -provided with environment variables: - -.. code-block:: bash - - export OS_AUTH_URL= - export OS_PROJECT_NAME= - export OS_USERNAME= - export OS_PASSWORD= # (optional) - -or command-line options: - -.. code-block:: bash - - --os-auth-url - --os-project-name - --os-username - [--os-password ] - -Additionally :program:`sahara` API url can be configured with parameter: - -.. code-block:: bash - - --os-data-processing-url - -or with environment variable: - -.. code-block:: bash - - export OS_DATA_PROCESSING_URL= diff --git a/openstack-common.conf b/openstack-common.conf deleted file mode 100644 index 0b4ad3f..0000000 --- a/openstack-common.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -base=saharaclient - -module=apiclient.auth -module=apiclient.exceptions -module=cliutils -module=_i18n diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/notes/autogenerated-api-docs-3bc8513e63bfe610.yaml b/releasenotes/notes/autogenerated-api-docs-3bc8513e63bfe610.yaml deleted file mode 100644 index 471c98c..0000000 --- a/releasenotes/notes/autogenerated-api-docs-3bc8513e63bfe610.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - > - Automatically generated documentation for saharaclient API was added. diff --git a/releasenotes/notes/autogenerated-cli-docs-c1e89ec6ea66c4a9.yaml b/releasenotes/notes/autogenerated-cli-docs-c1e89ec6ea66c4a9.yaml deleted file mode 100644 index 6044f5e..0000000 --- a/releasenotes/notes/autogenerated-cli-docs-c1e89ec6ea66c4a9.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - > - Automatically generated documentation for saharaclient CLI was added. diff --git a/releasenotes/notes/cli-deprecation-da0e7b6dfe77af52.yaml b/releasenotes/notes/cli-deprecation-da0e7b6dfe77af52.yaml deleted file mode 100644 index e5b7f34..0000000 --- a/releasenotes/notes/cli-deprecation-da0e7b6dfe77af52.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -deprecations: - - > - Old CLI is deprecated and will not be maintained. diff --git a/releasenotes/notes/designate-integration-16c59a6b57dbcfa4.yaml b/releasenotes/notes/designate-integration-16c59a6b57dbcfa4.yaml deleted file mode 100644 index 3cb06fe..0000000 --- a/releasenotes/notes/designate-integration-16c59a6b57dbcfa4.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Added integration of Designate for hostname resolution through dns - servers diff --git a/releasenotes/notes/event-logs-c6d286e25dc7d9b1.yaml b/releasenotes/notes/event-logs-c6d286e25dc7d9b1.yaml deleted file mode 100644 index 45449b4..0000000 --- a/releasenotes/notes/event-logs-c6d286e25dc7d9b1.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Providing ability to make dump of event logs for clusters. - Also displaying shorten version of event logs by option. diff --git a/releasenotes/notes/fields-unset-068db4c3e680c37d.yaml b/releasenotes/notes/fields-unset-068db4c3e680c37d.yaml deleted file mode 100644 index 435b06d..0000000 --- a/releasenotes/notes/fields-unset-068db4c3e680c37d.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - > - [`bug 1534050 `_] - Now object's fields can be unset with ``update`` calls. diff --git a/releasenotes/notes/implement-pagination-2ba52769d240a3ce.yaml b/releasenotes/notes/implement-pagination-2ba52769d240a3ce.yaml deleted file mode 100644 index 178f7a0..0000000 --- a/releasenotes/notes/implement-pagination-2ba52769d240a3ce.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - > - Pagination for list operations is implemented. diff --git a/releasenotes/notes/job-binary-create-optional-bc0f9ee6426c5659.yaml b/releasenotes/notes/job-binary-create-optional-bc0f9ee6426c5659.yaml deleted file mode 100644 index 79b2749..0000000 --- a/releasenotes/notes/job-binary-create-optional-bc0f9ee6426c5659.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - > - [`bug 1508406 `_] - Now ``description`` and ``extra`` parameters of jobs ``create`` method - are optional. diff --git a/releasenotes/notes/job-create-optional-034307a6b5db2cf2.yaml b/releasenotes/notes/job-create-optional-034307a6b5db2cf2.yaml deleted file mode 100644 index 7a603cc..0000000 --- a/releasenotes/notes/job-create-optional-034307a6b5db2cf2.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - > - [`bug 1506448 `_] - Now ``mains``, ``libs`` and ``description`` parameters of jobs ``create`` - method are optional. diff --git a/releasenotes/notes/job-execution-create-optional-1014a403e5ffa7ac.yaml b/releasenotes/notes/job-execution-create-optional-1014a403e5ffa7ac.yaml deleted file mode 100644 index 2b48e97..0000000 --- a/releasenotes/notes/job-execution-create-optional-1014a403e5ffa7ac.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - > - [`bug 1507966 `_] - Now input_id, output_id, configs parameters of job executions create - method are optional. diff --git a/releasenotes/notes/new-cli-6119bf8a4fb24ab6.yaml b/releasenotes/notes/new-cli-6119bf8a4fb24ab6.yaml deleted file mode 100644 index 0a7fdb7..0000000 --- a/releasenotes/notes/new-cli-6119bf8a4fb24ab6.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - > - New CLI as part of the openstackclient was implemented. diff --git a/releasenotes/notes/plugin-api-f650c26a030b7df8.yaml b/releasenotes/notes/plugin-api-f650c26a030b7df8.yaml deleted file mode 100644 index 20dbc4c..0000000 --- a/releasenotes/notes/plugin-api-f650c26a030b7df8.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Plugins updates are supported now in saharaclient. Also - information about plugin labels is available for users. diff --git a/releasenotes/notes/remove-functional-tests-c4b9d43c2c32d121.yaml b/releasenotes/notes/remove-functional-tests-c4b9d43c2c32d121.yaml deleted file mode 100644 index 3475261..0000000 --- a/releasenotes/notes/remove-functional-tests-c4b9d43c2c32d121.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -prelude: > - Functional tests were replaced to sahara-tests repository. Please refer to - README of sahara-tests about how to run these tests now. diff --git a/releasenotes/notes/remove-py26-dad75fc8d602b3c5.yaml b/releasenotes/notes/remove-py26-dad75fc8d602b3c5.yaml deleted file mode 100644 index cf8f520..0000000 --- a/releasenotes/notes/remove-py26-dad75fc8d602b3c5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - > - [`bug 1519510 `_] - Support of python 2.6 was dropped. diff --git a/releasenotes/notes/remove-py33-8364cb4805391750.yaml b/releasenotes/notes/remove-py33-8364cb4805391750.yaml deleted file mode 100644 index ff68223..0000000 --- a/releasenotes/notes/remove-py33-8364cb4805391750.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - > - [`bug 1526170 `_] - Support of python 3.3 was dropped. diff --git a/releasenotes/notes/rename_version_to_plugin-version-20cfe17530446391.yaml b/releasenotes/notes/rename_version_to_plugin-version-20cfe17530446391.yaml deleted file mode 100644 index d8967fd..0000000 --- a/releasenotes/notes/rename_version_to_plugin-version-20cfe17530446391.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -upgrade: - - Option 'version' is replaced by 'plugin-version' option. -fixes: - - Option 'version' is a global option, which is used for getting - the client version. So there were problems with the OpenStack client, - when we specified 'version' of the plugin, but OSC treated - that as a request for getting the current client version. Hence, to fix - this problem, 'version' is replaced by 'plugin-version'. - Related bug 1565775. diff --git a/releasenotes/notes/shares-update-d6f7e28acd27aa7f.yaml b/releasenotes/notes/shares-update-d6f7e28acd27aa7f.yaml deleted file mode 100644 index 59ab850..0000000 --- a/releasenotes/notes/shares-update-d6f7e28acd27aa7f.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - > - Now shares can be edited on an existing cluster. diff --git a/releasenotes/notes/start-using-reno-1f3418c11785c9ab.yaml b/releasenotes/notes/start-using-reno-1f3418c11785c9ab.yaml deleted file mode 100644 index 67726d9..0000000 --- a/releasenotes/notes/start-using-reno-1f3418c11785c9ab.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -other: - - > - Start using reno to manage release notes. diff --git a/releasenotes/notes/tags-update-c794416bcc035cb8.yaml b/releasenotes/notes/tags-update-c794416bcc035cb8.yaml deleted file mode 100644 index 5c35b13..0000000 --- a/releasenotes/notes/tags-update-c794416bcc035cb8.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - > - [`bug 1500790 `_] - Now tags can be added and removed simultaneously in one call. diff --git a/releasenotes/notes/update-image-optional-f83c5746d88507cd.yaml b/releasenotes/notes/update-image-optional-f83c5746d88507cd.yaml deleted file mode 100644 index 1211fcb..0000000 --- a/releasenotes/notes/update-image-optional-f83c5746d88507cd.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - - > - [`bug 1510470 `_] - Now ``desc`` parameter of ``update_image`` is optional. diff --git a/releasenotes/notes/volume-mount-prefix-b6ef396a357cddd0.yaml b/releasenotes/notes/volume-mount-prefix-b6ef396a357cddd0.yaml deleted file mode 100644 index dc78b82..0000000 --- a/releasenotes/notes/volume-mount-prefix-b6ef396a357cddd0.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - > - [`bug 1499697 `_] - Now node group templates can be created and updated with - ``volume_mount_prefix`` parameter. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 8cb5d9e..0000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,219 +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. - -# Sahara Client Release Notes documentation build configuration file - -extensions = [ - 'oslosphinx', - 'reno.sphinxext', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Saharaclient Release Notes' -copyright = u'2015, Sahara Developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -from saharaclient.version import version_info as saharaclient_version -# The full version, including alpha/beta/rc tags. -release = saharaclient_version.version_string_with_vcs() -# The short X.Y version. -version = saharaclient_version.canonical_version_string() - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# 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. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'SaharaClientReleaseNotesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'SaharaClientReleaseNotes.tex', - u'Sahara Client Release Notes Documentation', - u'Sahara Client Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'saharaclientreleasenotes', - u'Sahara Client Release Notes Documentation', - [u'Sahara Developers'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'SaharaClientReleaseNotes', - u'Sahara Client Release Notes Documentation', - u'Sahara Developers', 'SaharaClientReleaseNotes', - 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index 2ab1f9d..0000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -=========================== - Saharaclient Release Notes -=========================== - -.. toctree:: - :maxdepth: 1 - - unreleased - mitaka diff --git a/releasenotes/source/mitaka.rst b/releasenotes/source/mitaka.rst deleted file mode 100644 index e545609..0000000 --- a/releasenotes/source/mitaka.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Mitaka Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/mitaka diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index cd22aab..0000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================== - Current Series Release Notes -============================== - -.. release-notes:: diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c22783b..0000000 --- a/requirements.txt +++ /dev/null @@ -1,18 +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 # Apache-2.0 - -Babel>=2.3.4 # BSD -keystoneauth1>=2.10.0 # Apache-2.0 -osc-lib>=0.4.0 # Apache-2.0 -oslo.log>=1.14.0 # Apache-2.0 -oslo.serialization>=1.10.0 # Apache-2.0 -oslo.i18n>=2.1.0 # Apache-2.0 -oslo.utils>=3.16.0 # Apache-2.0 -python-keystoneclient!=1.8.0,!=2.1.0,>=1.7.0 # Apache-2.0 -python-openstackclient>=2.1.0 # Apache-2.0 -requests>=2.10.0 # Apache-2.0 -six>=1.9.0 # MIT -PrettyTable<0.8,>=0.7 # BSD diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index f5ebe5b..0000000 --- a/run_tests.sh +++ /dev/null @@ -1,164 +0,0 @@ -#!/bin/bash - -set -eu - -function usage { - echo "Usage: $0 [OPTION]..." - echo "Run python-saharaclient test suite" - echo "" - 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 " -s, --no-site-packages Isolate the virtualenv from the global Python environment" - echo " -x, --stop Stop running tests after the first error or failure." - echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added." - echo " -p, --pep8 Just run pep8" - echo " -P, --no-pep8 Don't run pep8" - echo " -c, --coverage Generate coverage report" - echo " -h, --help Print this usage message" - echo " --hide-elapsed Don't print the elapsed time for each test along with slow test list" - echo "" - echo "Note: with no options specified, the script will try to run the tests in a virtual environment," - echo " If no virtualenv is found, the script will ask if you would like to create one. If you " - echo " prefer to run tests NOT in a virtual environment, simply pass the -N option." - exit -} - -function process_option { - case "$1" in - -h|--help) usage;; - -V|--virtual-env) always_venv=1; never_venv=0;; - -N|--no-virtual-env) always_venv=0; never_venv=1;; - -s|--no-site-packages) no_site_packages=1;; - -f|--force) force=1;; - -p|--pep8) just_pep8=1;; - -P|--no-pep8) no_pep8=1;; - -c|--coverage) coverage=1;; - -*) testropts="$testropts $1";; - *) testrargs="$testrargs $1" - esac -} - -venv=.venv -with_venv=tools/with_venv.sh -always_venv=0 -never_venv=0 -force=0 -no_site_packages=0 -installvenvopts= -testrargs= -testropts= -wrapper="" -just_pep8=0 -no_pep8=0 -coverage=0 - -LANG=en_US.UTF-8 -LANGUAGE=en_US:en -LC_ALL=C - -for arg in "$@"; do - process_option $arg -done - -if [ $no_site_packages -eq 1 ]; then - installvenvopts="--no-site-packages" -fi - -function init_testr { - if [ ! -d .testrepository ]; then - ${wrapper} testr init - fi -} - -function run_tests { - # Cleanup *pyc - ${wrapper} find . -type f -name "*.pyc" -delete - - if [ $coverage -eq 1 ]; then - # Do not test test_coverage_ext when gathering coverage. - if [ "x$testrargs" = "x" ]; then - testrargs="^(?!.*test_coverage_ext).*$" - fi - export PYTHON="${wrapper} coverage run --source saharaclient --parallel-mode" - fi - # Just run the test suites in current environment - set +e - TESTRTESTS="$TESTRTESTS $testrargs" - echo "Running \`${wrapper} $TESTRTESTS\`" - ${wrapper} $TESTRTESTS - RESULT=$? - set -e - - copy_subunit_log - - return $RESULT -} - -function copy_subunit_log { - LOGNAME=`cat .testrepository/next-stream` - LOGNAME=$(($LOGNAME - 1)) - LOGNAME=".testrepository/${LOGNAME}" - cp $LOGNAME subunit.log -} - -function run_pep8 { - echo "Running flake8 ..." - ${wrapper} flake8 -} - -TESTRTESTS="testr run --parallel $testropts" - -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 [ -e ${venv} ]; then - wrapper="${with_venv}" - else - if [ $always_venv -eq 1 ]; then - # Automatically install the virtualenv - python tools/install_venv.py $installvenvopts - 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 $installvenvopts - wrapper=${with_venv} - fi - fi - fi -fi - -# Delete old coverage data from previous runs -if [ $coverage -eq 1 ]; then - ${wrapper} coverage erase -fi - -if [ $just_pep8 -eq 1 ]; then - run_pep8 - exit -fi - -init_testr -run_tests - -# NOTE(sirp): we only want to run pep8 when we're running the full-test suite, -# not when we're running tests individually. To handle this, we need to -# distinguish between options (noseopts), which begin with a '-', and -# arguments (testrargs). -if [ -z "$testrargs" ]; then - if [ $no_pep8 -eq 0 ]; then - run_pep8 - fi -fi - -if [ $coverage -eq 1 ]; then - echo "Generating coverage report in covhtml/" - ${wrapper} coverage combine - ${wrapper} coverage html --include='saharaclient/*' --omit='saharaclient/openstack/common/*' -d covhtml -i -fi diff --git a/saharaclient/__init__.py b/saharaclient/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/saharaclient/api/__init__.py b/saharaclient/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/saharaclient/api/base.py b/saharaclient/api/base.py deleted file mode 100644 index 36c9e45..0000000 --- a/saharaclient/api/base.py +++ /dev/null @@ -1,281 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import copy -import json -import logging - -import six -from six.moves.urllib import parse - -from saharaclient.openstack.common._i18n import _ - -LOG = logging.getLogger(__name__) - - -class Resource(object): - resource_name = 'Something' - defaults = {} - - def __init__(self, manager, info): - self.manager = manager - info = info.copy() - self._info = info - self._set_defaults(info) - self._add_details(info) - - def _set_defaults(self, info): - for name, value in six.iteritems(self.defaults): - if name not in info: - info[name] = value - - def _add_details(self, info): - for (k, v) in six.iteritems(info): - try: - setattr(self, k, v) - self._info[k] = v - except AttributeError: - # In this case we already defined the attribute on the class - pass - - def to_dict(self): - return copy.deepcopy(self._info) - - def __str__(self): - return '%s %s' % (self.resource_name, str(self._info)) - - -def _check_items(obj, searches): - try: - return all(getattr(obj, attr) == value for (attr, value) in searches) - except AttributeError: - return False - - -class NotUpdated(object): - """A sentinel class to signal that parameter should not be updated.""" - def __repr__(self): - return 'NotUpdated' - - -class ResourceManager(object): - resource_class = None - - def __init__(self, api): - self.api = api - - def find(self, **kwargs): - return [i for i in self.list() if _check_items(i, kwargs.items())] - - def find_unique(self, **kwargs): - found = self.find(**kwargs) - if not found: - raise APIException(error_code=404, - error_message=_("No matches found.")) - if len(found) > 1: - raise APIException(error_code=409, - error_message=_("Multiple matches found.")) - return found[0] - - def _copy_if_defined(self, data, **kwargs): - for var_name, var_value in six.iteritems(kwargs): - if var_value is not None: - data[var_name] = var_value - - def _copy_if_updated(self, data, **kwargs): - for var_name, var_value in six.iteritems(kwargs): - if not isinstance(var_value, NotUpdated): - data[var_name] = var_value - - def _create(self, url, data, response_key=None, dump_json=True): - if dump_json: - kwargs = {'json': data} - else: - kwargs = {'data': data} - - resp = self.api.post(url, **kwargs) - - if resp.status_code != 202: - self._raise_api_exception(resp) - - if response_key is not None: - data = get_json(resp)[response_key] - else: - data = get_json(resp) - return self.resource_class(self, data) - - def _update(self, url, data, response_key=None, dump_json=True): - if dump_json: - kwargs = {'json': data} - else: - kwargs = {'data': data} - - resp = self.api.put(url, **kwargs) - - if resp.status_code != 202: - self._raise_api_exception(resp) - if response_key is not None: - data = get_json(resp)[response_key] - else: - data = get_json(resp) - - return self.resource_class(self, data) - - def _patch(self, url, data, response_key=None, dump_json=True): - if dump_json: - kwargs = {'json': data} - else: - kwargs = {'data': data} - - resp = self.api.patch(url, **kwargs) - - if resp.status_code != 202: - self._raise_api_exception(resp) - if response_key is not None: - data = get_json(resp)[response_key] - else: - data = get_json(resp) - - return self.resource_class(self, data) - - def _post(self, url, data, response_key=None, dump_json=True): - if dump_json: - kwargs = {'json': data} - else: - kwargs = {'data': data} - - resp = self.api.post(url, **kwargs) - - if resp.status_code != 202: - self._raise_api_exception(resp) - - if response_key is not None: - data = get_json(resp)[response_key] - else: - data = get_json(resp) - - return self.resource_class(self, data) - - def _list(self, url, response_key): - resp = self.api.get(url) - if resp.status_code == 200: - data = get_json(resp)[response_key] - - return [self.resource_class(self, res) - for res in data] - else: - self._raise_api_exception(resp) - - def _page(self, url, response_key, limit=None): - resp = self.api.get(url) - if resp.status_code == 200: - result = get_json(resp) - data = result[response_key] - meta = result.get('markers') - - next, prev = None, None - - if meta: - prev = meta.get('prev') - next = meta.get('next') - - l = [self.resource_class(self, res) - for res in data] - - return Page(l, prev, next, limit) - else: - self._raise_api_exception(resp) - - def _get(self, url, response_key=None): - resp = self.api.get(url) - - if resp.status_code == 200: - if response_key is not None: - data = get_json(resp)[response_key] - else: - data = get_json(resp) - return self.resource_class(self, data) - else: - self._raise_api_exception(resp) - - def _delete(self, url): - resp = self.api.delete(url) - - if resp.status_code != 204: - self._raise_api_exception(resp) - - def _plurify_resource_name(self): - return self.resource_class.resource_name + 's' - - def _raise_api_exception(self, resp): - try: - error_data = get_json(resp) - except Exception: - msg = _("Failed to parse response from Sahara: %s") % resp.reason - raise APIException( - error_code=resp.status_code, - error_message=msg) - - raise APIException(error_code=error_data.get("error_code"), - error_name=error_data.get("error_name"), - error_message=error_data.get("error_message")) - - -def get_json(response): - """Provide backward compatibility with old versions of requests library.""" - - json_field_or_function = getattr(response, 'json', None) - if callable(json_field_or_function): - return response.json() - else: - return json.loads(response.content) - - -class APIException(Exception): - def __init__(self, error_code=None, error_name=None, error_message=None): - super(APIException, self).__init__(error_message) - self.error_code = error_code - self.error_name = error_name - self.error_message = error_message - - -def get_query_string(search_opts, limit=None, marker=None, sort_by=None, - reverse=None): - opts = {} - if marker is not None: - opts['marker'] = marker - if limit is not None: - opts['limit'] = limit - if sort_by is not None: - if reverse: - opts['sort_by'] = "-%s" % sort_by - else: - opts['sort_by'] = sort_by - if search_opts is not None: - opts.update(search_opts) - if opts: - qparams = sorted(opts.items(), key=lambda x: x[0]) - query_string = "?%s" % parse.urlencode(qparams, doseq=True) - else: - query_string = "" - return query_string - - -class Page(list): - def __init__(self, l, prev, next, limit): - super(Page, self).__init__(l) - self.prev = prev - self.next = next - self.limit = limit diff --git a/saharaclient/api/client.py b/saharaclient/api/client.py deleted file mode 100644 index 1fd7602..0000000 --- a/saharaclient/api/client.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import warnings - -from keystoneauth1 import adapter -from keystoneauth1 import exceptions -from keystoneauth1.identity import v2 -from keystoneauth1.identity import v3 -from keystoneauth1 import session as keystone_session -from keystoneauth1 import token_endpoint - -from saharaclient.api import cluster_templates -from saharaclient.api import clusters -from saharaclient.api import data_sources -from saharaclient.api import images -from saharaclient.api import job_binaries -from saharaclient.api import job_binary_internals -from saharaclient.api import job_executions -from saharaclient.api import job_types -from saharaclient.api import jobs -from saharaclient.api import node_group_templates -from saharaclient.api import plugins - - -USER_AGENT = 'python-saharaclient' - - -class HTTPClient(adapter.Adapter): - - def request(self, *args, **kwargs): - kwargs.setdefault('raise_exc', False) - return super(HTTPClient, self).request(*args, **kwargs) - - -class Client(object): - """Client for the OpenStack Data Processing v1 API. - - :param str username: Username for Keystone authentication. - :param str api_key: Password for Keystone authentication. - :param str project_id: Keystone Tenant id. - :param str project_name: Keystone Tenant name. - :param str auth_url: Keystone URL that will be used for authentication. - :param str sahara_url: Sahara REST API URL to communicate with. - :param str endpoint_type: Desired Sahara endpoint type. - :param str service_type: Sahara service name in Keystone catalog. - :param str input_auth_token: Keystone authorization token. - :param session: Keystone Session object. - :param auth: Keystone Authentication Plugin object. - :param boolean insecure: Allow insecure. - :param string cacert: Path to the Privacy Enhanced Mail (PEM) file - which contains certificates needed to establish - SSL connection with the identity service. - :param string region_name: Name of a region to select when choosing an - endpoint from the service catalog. - """ - def __init__(self, username=None, api_key=None, project_id=None, - project_name=None, auth_url=None, sahara_url=None, - endpoint_type='publicURL', service_type='data-processing', - input_auth_token=None, session=None, auth=None, - insecure=False, cacert=None, region_name=None, **kwargs): - - if not session: - warnings.simplefilter('once', category=DeprecationWarning) - warnings.warn('Passing authentication parameters to saharaclient ' - 'is deprecated. Please construct and pass an ' - 'authenticated session object directly.', - DeprecationWarning) - warnings.resetwarnings() - - if input_auth_token: - auth = token_endpoint.Token(sahara_url, input_auth_token) - - else: - auth = self._get_keystone_auth(auth_url=auth_url, - username=username, - api_key=api_key, - project_id=project_id, - project_name=project_name) - - verify = True - if insecure: - verify = False - elif cacert: - verify = cacert - - session = keystone_session.Session(verify=verify) - - if not auth: - auth = session.auth - - # NOTE(Toan): bug #1512801. If sahara_url is provided, it does not - # matter if service_type is orthographically correct or not. - # Only find Sahara service_type and endpoint in Keystone catalog - # if sahara_url is not provided. - if not sahara_url: - service_type = self._determine_service_type(session, - auth, - service_type, - endpoint_type) - - kwargs['user_agent'] = USER_AGENT - kwargs.setdefault('interface', endpoint_type) - kwargs.setdefault('endpoint_override', sahara_url) - - client = HTTPClient(session=session, - auth=auth, - service_type=service_type, - region_name=region_name, - **kwargs) - - self.clusters = clusters.ClusterManager(client) - self.cluster_templates = ( - cluster_templates.ClusterTemplateManager(client) - ) - self.node_group_templates = ( - node_group_templates.NodeGroupTemplateManager(client) - ) - self.plugins = plugins.PluginManager(client) - self.images = images.ImageManager(client) - - self.data_sources = data_sources.DataSourceManager(client) - self.jobs = jobs.JobsManager(client) - self.job_executions = job_executions.JobExecutionsManager(client) - self.job_binaries = job_binaries.JobBinariesManager(client) - self.job_binary_internals = ( - job_binary_internals.JobBinaryInternalsManager(client) - ) - self.job_types = job_types.JobTypesManager(client) - - def _get_keystone_auth(self, username=None, api_key=None, auth_url=None, - project_id=None, project_name=None): - if not auth_url: - raise RuntimeError("No auth url specified") - - if 'v2.0' in auth_url: - return v2.Password(auth_url=auth_url, - username=username, - password=api_key, - tenant_id=project_id, - tenant_name=project_name) - else: - # NOTE(jamielennox): Setting these to default is what - # keystoneclient does in the event they are not passed. - return v3.Password(auth_url=auth_url, - username=username, - password=api_key, - user_domain_id='default', - project_id=project_id, - project_name=project_name, - project_domain_id='default') - - @staticmethod - def _determine_service_type(session, auth, service_type, interface): - """Check a catalog for data-processing or data_processing""" - - # NOTE(jamielennox): calling get_endpoint forces an auth on - # initialization which is required for backwards compatibility. It - # also allows us to reset the service type if not in the catalog. - for st in (service_type, service_type.replace('-', '_')): - try: - url = auth.get_endpoint(session, - service_type=st, - interface=interface) - except exceptions.Unauthorized: - raise RuntimeError("Not Authorized") - except exceptions.EndpointNotFound: - # NOTE(jamielennox): bug #1428447. This should not be - # raised, instead None should be returned. Handle in case - # it changes in the future - url = None - - if url: - return st - - raise RuntimeError("Could not find Sahara endpoint in catalog") diff --git a/saharaclient/api/cluster_templates.py b/saharaclient/api/cluster_templates.py deleted file mode 100644 index 9c7bd43..0000000 --- a/saharaclient/api/cluster_templates.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from saharaclient.api import base - - -class ClusterTemplate(base.Resource): - resource_name = 'Cluster Template' - - -class ClusterTemplateManager(base.ResourceManager): - resource_class = ClusterTemplate - NotUpdated = base.NotUpdated() - - def create(self, name, plugin_name, hadoop_version, description=None, - cluster_configs=None, node_groups=None, anti_affinity=None, - net_id=None, default_image_id=None, use_autoconfig=None, - shares=None, is_public=None, is_protected=None, - domain_name=None): - """Create a Cluster Template.""" - - data = { - 'name': name, - 'plugin_name': plugin_name, - 'hadoop_version': hadoop_version, - } - - self._copy_if_defined(data, - description=description, - cluster_configs=cluster_configs, - node_groups=node_groups, - anti_affinity=anti_affinity, - neutron_management_network=net_id, - default_image_id=default_image_id, - use_autoconfig=use_autoconfig, - shares=shares, - is_public=is_public, - is_protected=is_protected, - domain_name=domain_name) - - return self._create('/cluster-templates', data, 'cluster_template') - - def update(self, cluster_template_id, name=NotUpdated, - plugin_name=NotUpdated, hadoop_version=NotUpdated, - description=NotUpdated, cluster_configs=NotUpdated, - node_groups=NotUpdated, anti_affinity=NotUpdated, - net_id=NotUpdated, default_image_id=NotUpdated, - use_autoconfig=NotUpdated, shares=NotUpdated, - is_public=NotUpdated, is_protected=NotUpdated, - domain_name=NotUpdated): - """Update a Cluster Template.""" - - data = {} - self._copy_if_updated(data, name=name, - plugin_name=plugin_name, - hadoop_version=hadoop_version, - description=description, - cluster_configs=cluster_configs, - node_groups=node_groups, - anti_affinity=anti_affinity, - neutron_management_network=net_id, - default_image_id=default_image_id, - use_autoconfig=use_autoconfig, - shares=shares, - is_public=is_public, - is_protected=is_protected, - domain_name=domain_name) - - return self._update('/cluster-templates/%s' % cluster_template_id, - data, 'cluster_template') - - def list(self, search_opts=None, marker=None, - limit=None, sort_by=None, reverse=None): - """Get list of Cluster Templates.""" - query = base.get_query_string(search_opts, marker=marker, limit=limit, - sort_by=sort_by, reverse=reverse) - url = "/cluster-templates%s" % query - return self._page(url, 'cluster_templates', limit) - - def get(self, cluster_template_id): - """Get information about a Cluster Template.""" - return self._get('/cluster-templates/%s' % cluster_template_id, - 'cluster_template') - - def delete(self, cluster_template_id): - """Delete a Cluster Template.""" - self._delete('/cluster-templates/%s' % cluster_template_id) diff --git a/saharaclient/api/clusters.py b/saharaclient/api/clusters.py deleted file mode 100644 index fde5916..0000000 --- a/saharaclient/api/clusters.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from six.moves.urllib import parse - -from saharaclient.api import base - - -class Cluster(base.Resource): - resource_name = 'Cluster' - - -class ClusterManager(base.ResourceManager): - resource_class = Cluster - NotUpdated = base.NotUpdated() - - def create(self, name, plugin_name, hadoop_version, - cluster_template_id=None, default_image_id=None, - is_transient=None, description=None, cluster_configs=None, - node_groups=None, user_keypair_id=None, - anti_affinity=None, net_id=None, count=None, - use_autoconfig=None, shares=None, - is_public=None, is_protected=None): - """Launch a Cluster.""" - - data = { - 'name': name, - 'plugin_name': plugin_name, - 'hadoop_version': hadoop_version, - } - - # Checking if count is greater than 1, otherwise we set it to None - # so the created dict in the _copy_if_defined method does not contain - # the count parameter. - if count and count <= 1: - count = None - - self._copy_if_defined(data, - cluster_template_id=cluster_template_id, - is_transient=is_transient, - default_image_id=default_image_id, - description=description, - cluster_configs=cluster_configs, - node_groups=node_groups, - user_keypair_id=user_keypair_id, - anti_affinity=anti_affinity, - neutron_management_network=net_id, - count=count, - use_autoconfig=use_autoconfig, - shares=shares, - is_public=is_public, - is_protected=is_protected) - - if count: - return self._create('/clusters/multiple', data) - - return self._create('/clusters', data, 'cluster') - - def scale(self, cluster_id, scale_object): - """Scale an existing Cluster. - - :param scale_object: dict that describes scaling operation - - :Example: - - The following `scale_object` can be used to change the number of - instances in the node group and add instances of new node group to - existing cluster: - - .. sourcecode:: json - - { - "add_node_groups": [ - { - "count": 3, - "name": "new_ng", - "node_group_template_id": "ngt_id" - } - ], - "resize_node_groups": [ - { - "count": 2, - "name": "old_ng" - } - ] - } - - """ - return self._update('/clusters/%s' % cluster_id, scale_object) - - def list(self, search_opts=None, limit=None, marker=None, - sort_by=None, reverse=None): - """Get a list of Clusters.""" - query = base.get_query_string(search_opts, limit=limit, marker=marker, - sort_by=sort_by, reverse=reverse) - url = "/clusters%s" % query - return self._page(url, 'clusters', limit) - - def get(self, cluster_id, show_progress=False): - """Get information about a Cluster.""" - url = ('/clusters/%(cluster_id)s?%(params)s' % - {"cluster_id": cluster_id, - "params": parse.urlencode({"show_progress": show_progress})}) - - return self._get(url, 'cluster') - - def delete(self, cluster_id): - """Delete a Cluster.""" - self._delete('/clusters/%s' % cluster_id) - - def update(self, cluster_id, name=NotUpdated, description=NotUpdated, - is_public=NotUpdated, is_protected=NotUpdated, - shares=NotUpdated): - """Update a Cluster.""" - - data = {} - self._copy_if_updated(data, name=name, description=description, - is_public=is_public, is_protected=is_protected, - shares=shares) - - return self._patch('/clusters/%s' % cluster_id, data) - - def verification_update(self, cluster_id, status): - """Start a verification for a Cluster.""" - data = {'verification': {'status': status}} - return self._patch("/clusters/%s" % cluster_id, data) diff --git a/saharaclient/api/data_sources.py b/saharaclient/api/data_sources.py deleted file mode 100644 index 112cca5..0000000 --- a/saharaclient/api/data_sources.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from saharaclient.api import base - - -class DataSources(base.Resource): - resource_name = 'Data Source' - - -class DataSourceManager(base.ResourceManager): - resource_class = DataSources - - def create(self, name, description, data_source_type, - url, credential_user=None, credential_pass=None, - is_public=None, is_protected=None): - """Create a Data Source.""" - - data = { - 'name': name, - 'description': description, - 'type': data_source_type, - 'url': url, - 'credentials': {} - } - self._copy_if_defined(data['credentials'], - user=credential_user, - password=credential_pass) - - self._copy_if_defined(data, is_public=is_public, - is_protected=is_protected) - - return self._create('/data-sources', data, 'data_source') - - def list(self, search_opts=None, limit=None, marker=None, - sort_by=None, reverse=None): - """Get a list of Data Sources.""" - query = base.get_query_string(search_opts, limit=limit, marker=marker, - sort_by=sort_by, reverse=reverse) - url = "/data-sources%s" % query - return self._page(url, 'data_sources', limit) - - def get(self, data_source_id): - """Get information about a Data Source.""" - return self._get('/data-sources/%s' % data_source_id, 'data_source') - - def delete(self, data_source_id): - """Delete a Data Source.""" - self._delete('/data-sources/%s' % data_source_id) - - def update(self, data_source_id, update_data): - """Update a Data Source. - - :param dict update_data: dict that contains fields that should be - updated with new values. - - Fields that can be updated: - - * name - * description - * type - * url - * is_public - * is_protected - * credentials - dict with `user` and `password` keyword arguments - """ - return self._update('/data-sources/%s' % data_source_id, - update_data) diff --git a/saharaclient/api/helpers.py b/saharaclient/api/helpers.py deleted file mode 100644 index 6633c92..0000000 --- a/saharaclient/api/helpers.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from saharaclient.api import parameters as params - - -class Helpers(object): - def __init__(self, sahara_client): - self.sahara = sahara_client - self.plugins = self.sahara.plugins - - def _get_node_processes(self, plugin): - processes = [] - for proc_lst in plugin.node_processes.values(): - processes += proc_lst - - return [(proc_name, proc_name) for proc_name in processes] - - def get_node_processes(self, plugin_name, hadoop_version): - plugin = self.plugins.get_version_details(plugin_name, hadoop_version) - - return self._get_node_processes(plugin) - - def _extract_parameters(self, configs, scope, applicable_target): - parameters = [] - for config in configs: - if (config['scope'] == scope and - config['applicable_target'] == applicable_target): - - parameters.append(params.Parameter(config)) - - return parameters - - def get_cluster_general_configs(self, plugin_name, hadoop_version): - plugin = self.plugins.get_version_details(plugin_name, hadoop_version) - - return self._extract_parameters(plugin.configs, 'cluster', "general") - - def get_general_node_group_configs(self, plugin_name, hadoop_version): - plugin = self.plugins.get_version_details(plugin_name, hadoop_version) - - return self._extract_parameters(plugin.configs, 'node', 'general') - - def get_targeted_node_group_configs(self, plugin_name, hadoop_version): - plugin = self.plugins.get_version_details(plugin_name, hadoop_version) - - parameters = dict() - - for service in plugin.node_processes.keys(): - parameters[service] = self._extract_parameters(plugin.configs, - 'node', service) - - return parameters - - def get_targeted_cluster_configs(self, plugin_name, hadoop_version): - plugin = self.plugins.get_version_details(plugin_name, hadoop_version) - - parameters = dict() - - for service in plugin.node_processes.keys(): - parameters[service] = self._extract_parameters(plugin.configs, - 'cluster', service) - - return parameters diff --git a/saharaclient/api/images.py b/saharaclient/api/images.py deleted file mode 100644 index c10033b..0000000 --- a/saharaclient/api/images.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from saharaclient.api import base - - -class Image(base.Resource): - resource_name = 'Image' - defaults = {'description': ''} - - -class ImageManager(base.ResourceManager): - resource_class = Image - - def list(self, search_opts=None): - """Get a list of registered images.""" - query = base.get_query_string(search_opts) - return self._list('/images%s' % query, 'images') - - def get(self, id): - """Get information about an image""" - return self._get('/images/%s' % id, 'image') - - def unregister_image(self, image_id): - """Remove an Image from Sahara Image Registry.""" - self._delete('/images/%s' % image_id) - - def update_image(self, image_id, user_name, desc=None): - """Create or update an Image in Image Registry.""" - desc = desc if desc else '' - data = {"username": user_name, - "description": desc} - - return self._post('/images/%s' % image_id, data) - - def update_tags(self, image_id, new_tags): - """Update an Image tags. - - :param list new_tags: list of tags that will replace currently - assigned tags - """ - old_image = self.get(image_id) - - old_tags = frozenset(old_image.tags) - new_tags = frozenset(new_tags) - - to_add = list(new_tags - old_tags) - to_remove = list(old_tags - new_tags) - - add_response, remove_response = None, None - - if to_add: - add_response = self._post('/images/%s/tag' % image_id, - {'tags': to_add}, 'image') - - if to_remove: - remove_response = self._post('/images/%s/untag' % image_id, - {'tags': to_remove}, 'image') - - return remove_response or add_response or self.get(image_id) diff --git a/saharaclient/api/job_binaries.py b/saharaclient/api/job_binaries.py deleted file mode 100644 index 38637e3..0000000 --- a/saharaclient/api/job_binaries.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from saharaclient.api import base - - -class JobBinaries(base.Resource): - resource_name = 'Job Binary' - - -class JobBinariesManager(base.ResourceManager): - resource_class = JobBinaries - - def create(self, name, url, description=None, extra=None, is_public=None, - is_protected=None): - """Create a Job Binary.""" - data = { - "name": name, - "url": url - } - - self._copy_if_defined(data, description=description, extra=extra, - is_public=is_public, is_protected=is_protected) - - return self._create('/job-binaries', data, 'job_binary') - - def list(self, search_opts=None, limit=None, marker=None, - sort_by=None, reverse=None): - """Get a list of Job Binaries.""" - query = base.get_query_string(search_opts, limit=limit, marker=marker, - sort_by=sort_by, reverse=reverse) - url = "/job-binaries%s" % query - return self._page(url, 'binaries', limit) - - def get(self, job_binary_id): - """Get information about a Job Binary.""" - return self._get('/job-binaries/%s' % job_binary_id, 'job_binary') - - def delete(self, job_binary_id): - """Delete a Job Binary.""" - self._delete('/job-binaries/%s' % job_binary_id) - - def get_file(self, job_binary_id): - """Download a Job Binary.""" - resp = self.api.get('/job-binaries/%s/data' % job_binary_id) - - if resp.status_code != 200: - self._raise_api_exception(resp) - return resp.content - - def update(self, job_binary_id, data): - """Update Job Binary. - - :param dict data: dict that contains fields that should be updated - with new values. - - Fields that can be updated: - - * name - * description - * url - * is_public - * is_protected - * extra - dict with `user` and `password` keyword arguments - """ - return self._update( - '/job-binaries/%s' % job_binary_id, data, 'job_binary') diff --git a/saharaclient/api/job_binary_internals.py b/saharaclient/api/job_binary_internals.py deleted file mode 100644 index 9c7b139..0000000 --- a/saharaclient/api/job_binary_internals.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from six.moves.urllib import parse as urlparse - -from saharaclient.api import base - - -class JobBinaryInternal(base.Resource): - resource_name = 'JobBinaryInternal' - - -class JobBinaryInternalsManager(base.ResourceManager): - resource_class = JobBinaryInternal - NotUpdated = base.NotUpdated() - - def create(self, name, data): - """Create a Job Binary Internal. - - :param str data: raw data ot script text - """ - return self._update('/job-binary-internals/%s' % - urlparse.quote(name.encode('utf-8')), data, - 'job_binary_internal', dump_json=False) - - def list(self, search_opts=None, limit=None, marker=None, - sort_by=None, reverse=None): - """Get a list of Job Binary Internals.""" - query = base.get_query_string(search_opts, limit=limit, marker=marker, - sort_by=sort_by, reverse=reverse) - url = "/job-binary-internals%s" % query - return self._page(url, 'binaries', limit) - - def get(self, job_binary_id): - """Get information about a Job Binary Internal.""" - return self._get('/job-binary-internals/%s' % job_binary_id, - 'job_binary_internal') - - def delete(self, job_binary_id): - """Delete a Job Binary Internal.""" - self._delete('/job-binary-internals/%s' % job_binary_id) - - def update(self, job_binary_id, name=NotUpdated, is_public=NotUpdated, - is_protected=NotUpdated): - """Update a Job Binary Internal.""" - - data = {} - self._copy_if_updated(data, name=name, is_public=is_public, - is_protected=is_protected) - - return self._patch('/job-binary-internals/%s' % job_binary_id, data) diff --git a/saharaclient/api/job_executions.py b/saharaclient/api/job_executions.py deleted file mode 100644 index a76597a..0000000 --- a/saharaclient/api/job_executions.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from saharaclient.api import base - - -class JobExecution(base.Resource): - resource_name = 'JobExecution' - - -class JobExecutionsManager(base.ResourceManager): - resource_class = JobExecution - NotUpdated = base.NotUpdated() - - def list(self, search_opts=None, marker=None, limit=None, - sort_by=None, reverse=None): - """Get a list of Job Executions.""" - query = base.get_query_string(search_opts, limit=limit, marker=marker, - sort_by=sort_by, reverse=reverse) - url = "/job-executions%s" % query - return self._page(url, 'job_executions', limit) - - def get(self, obj_id): - """Get information about a Job Execution.""" - return self._get('/job-executions/%s' % obj_id, 'job_execution') - - def delete(self, obj_id): - """Delete a Job Execution.""" - self._delete('/job-executions/%s' % obj_id) - - def create(self, job_id, cluster_id, input_id=None, - output_id=None, configs=None, interface=None, is_public=None, - is_protected=None): - """Launch a Job.""" - - url = "/jobs/%s/execute" % job_id - data = { - "cluster_id": cluster_id, - } - - self._copy_if_defined(data, input_id=input_id, output_id=output_id, - job_configs=configs, interface=interface, - is_public=is_public, is_protected=is_protected) - - return self._create(url, data, 'job_execution') - - def update(self, obj_id, is_public=NotUpdated, is_protected=NotUpdated): - """Update a Job Execution.""" - - data = {} - self._copy_if_updated(data, is_public=is_public, - is_protected=is_protected) - return self._patch('/job-executions/%s' % obj_id, data) diff --git a/saharaclient/api/job_types.py b/saharaclient/api/job_types.py deleted file mode 100644 index 25eed81..0000000 --- a/saharaclient/api/job_types.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2015 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. - -from saharaclient.api import base - - -class JobType(base.Resource): - resource_name = 'JobType' - - -class JobTypesManager(base.ResourceManager): - resource_class = JobType - - def list(self, search_opts=None): - """Get a list of job types supported by plugins.""" - query = base.get_query_string(search_opts) - return self._list('/job-types%s' % query, 'job_types') diff --git a/saharaclient/api/jobs.py b/saharaclient/api/jobs.py deleted file mode 100644 index 8fdde51..0000000 --- a/saharaclient/api/jobs.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from saharaclient.api import base - - -class Job(base.Resource): - resource_name = 'Job' - - -class JobsManager(base.ResourceManager): - resource_class = Job - NotUpdated = base.NotUpdated() - - def create(self, name, type, mains=None, libs=None, description=None, - interface=None, is_public=None, is_protected=None): - """Create a Job.""" - data = { - 'name': name, - 'type': type - } - - self._copy_if_defined(data, description=description, mains=mains, - libs=libs, interface=interface, - is_public=is_public, is_protected=is_protected) - - return self._create('/jobs', data, 'job') - - def list(self, search_opts=None, limit=None, - marker=None, sort_by=None, reverse=None): - """Get a list of Jobs.""" - query = base.get_query_string(search_opts, limit=limit, marker=marker, - sort_by=sort_by, reverse=reverse) - url = "/jobs%s" % query - return self._page(url, 'jobs', limit) - - def get(self, job_id): - """Get information about a Job""" - return self._get('/jobs/%s' % job_id, 'job') - - def get_configs(self, job_type): - """Get config hints for a specified Job type.""" - return self._get('/jobs/config-hints/%s' % job_type) - - def delete(self, job_id): - """Delete a Job""" - self._delete('/jobs/%s' % job_id) - - def update(self, job_id, name=NotUpdated, description=NotUpdated, - is_public=NotUpdated, is_protected=NotUpdated): - """Update a Job.""" - - data = {} - self._copy_if_updated(data, name=name, description=description, - is_public=is_public, is_protected=is_protected) - - return self._patch('/jobs/%s' % job_id, data) diff --git a/saharaclient/api/node_group_templates.py b/saharaclient/api/node_group_templates.py deleted file mode 100644 index 90c1b4d..0000000 --- a/saharaclient/api/node_group_templates.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from saharaclient.api import base - - -class NodeGroupTemplate(base.Resource): - resource_name = 'Node Group Template' - - -class NodeGroupTemplateManager(base.ResourceManager): - resource_class = NodeGroupTemplate - NotUpdated = base.NotUpdated() - - def create(self, name, plugin_name, hadoop_version, flavor_id, - description=None, volumes_per_node=None, volumes_size=None, - node_processes=None, node_configs=None, floating_ip_pool=None, - security_groups=None, auto_security_group=None, - availability_zone=None, volumes_availability_zone=None, - volume_type=None, image_id=None, is_proxy_gateway=None, - volume_local_to_instance=None, use_autoconfig=None, - shares=None, is_public=None, is_protected=None, - volume_mount_prefix=None): - """Create a Node Group Template.""" - - data = { - 'name': name, - 'plugin_name': plugin_name, - 'hadoop_version': hadoop_version, - 'flavor_id': flavor_id, - 'node_processes': node_processes - } - - self._copy_if_defined(data, - description=description, - node_configs=node_configs, - floating_ip_pool=floating_ip_pool, - security_groups=security_groups, - auto_security_group=auto_security_group, - availability_zone=availability_zone, - image_id=image_id, - is_proxy_gateway=is_proxy_gateway, - use_autoconfig=use_autoconfig, - shares=shares, - is_public=is_public, - is_protected=is_protected - ) - - if volumes_per_node: - data.update({"volumes_per_node": volumes_per_node, - "volumes_size": volumes_size}) - if volumes_availability_zone: - data.update({"volumes_availability_zone": - volumes_availability_zone}) - if volume_type: - data.update({"volume_type": volume_type}) - if volume_local_to_instance: - data.update( - {"volume_local_to_instance": volume_local_to_instance}) - if volume_mount_prefix: - data.update({"volume_mount_prefix": volume_mount_prefix}) - - return self._create('/node-group-templates', data, - 'node_group_template') - - def update(self, ng_template_id, name=NotUpdated, plugin_name=NotUpdated, - hadoop_version=NotUpdated, flavor_id=NotUpdated, - description=NotUpdated, volumes_per_node=NotUpdated, - volumes_size=NotUpdated, node_processes=NotUpdated, - node_configs=NotUpdated, floating_ip_pool=NotUpdated, - security_groups=NotUpdated, auto_security_group=NotUpdated, - availability_zone=NotUpdated, - volumes_availability_zone=NotUpdated, volume_type=NotUpdated, - image_id=NotUpdated, is_proxy_gateway=NotUpdated, - volume_local_to_instance=NotUpdated, use_autoconfig=NotUpdated, - shares=NotUpdated, is_public=NotUpdated, - is_protected=NotUpdated, volume_mount_prefix=NotUpdated): - """Update a Node Group Template.""" - - data = {} - self._copy_if_updated( - data, name=name, plugin_name=plugin_name, - hadoop_version=hadoop_version, flavor_id=flavor_id, - description=description, volumes_per_node=volumes_per_node, - volumes_size=volumes_size, node_processes=node_processes, - node_configs=node_configs, floating_ip_pool=floating_ip_pool, - security_groups=security_groups, - auto_security_group=auto_security_group, - availability_zone=availability_zone, - volumes_availability_zone=volumes_availability_zone, - volume_type=volume_type, image_id=image_id, - is_proxy_gateway=is_proxy_gateway, - volume_local_to_instance=volume_local_to_instance, - use_autoconfig=use_autoconfig, shares=shares, - is_public=is_public, is_protected=is_protected, - volume_mount_prefix=volume_mount_prefix - ) - - return self._update('/node-group-templates/%s' % ng_template_id, data, - 'node_group_template') - - def list(self, search_opts=None, marker=None, - limit=None, sort_by=None, reverse=None): - """Get a list of Node Group Templates.""" - query = base.get_query_string(search_opts, limit=limit, marker=marker, - sort_by=sort_by, reverse=reverse) - url = "/node-group-templates%s" % query - return self._page(url, 'node_group_templates', limit) - - def get(self, ng_template_id): - """Get information about a Node Group Template.""" - return self._get('/node-group-templates/%s' % ng_template_id, - 'node_group_template') - - def delete(self, ng_template_id): - """Delete a Node Group Template.""" - self._delete('/node-group-templates/%s' % ng_template_id) diff --git a/saharaclient/api/parameters.py b/saharaclient/api/parameters.py deleted file mode 100644 index 4575b56..0000000 --- a/saharaclient/api/parameters.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - - -class Parameter(object): - """This bean is used for building config entries.""" - def __init__(self, config): - self.name = config['name'] - self.description = config.get('description', "No description") - self.required = not config['is_optional'] - self.default_value = config.get('default_value', None) - self.initial_value = self.default_value - self.param_type = config['config_type'] - self.priority = int(config.get('priority', 2)) diff --git a/saharaclient/api/plugins.py b/saharaclient/api/plugins.py deleted file mode 100644 index 21156cf..0000000 --- a/saharaclient/api/plugins.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (c) 2013 Mirantis 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. - -from six.moves.urllib import parse as urlparse - -from saharaclient.api import base - - -class Plugin(base.Resource): - resource_name = 'Plugin' - - def __init__(self, manager, info): - base.Resource.__init__(self, manager, info) - - # Horizon requires each object in table to have an id - self.id = self.name - - -class PluginManager(base.ResourceManager): - resource_class = Plugin - - def list(self, search_opts=None): - """Get a list of Plugins.""" - query = base.get_query_string(search_opts) - return self._list('/plugins%s' % query, 'plugins') - - def get(self, plugin_name): - """Get information about a Plugin.""" - return self._get('/plugins/%s' % plugin_name, 'plugin') - - def get_version_details(self, plugin_name, hadoop_version): - """Get version details - - Get the list of Services and Service Parameters for a specified - Plugin and Plugin Version. - """ - return self._get('/plugins/%s/%s' % (plugin_name, hadoop_version), - 'plugin') - - def update(self, plugin_name, values): - """Update plugin and then return updated result to user - - """ - return self._patch("/plugins/%s" % plugin_name, values, 'plugin') - - def convert_to_cluster_template(self, plugin_name, hadoop_version, - template_name, filecontent): - """Convert to cluster template - - Create Cluster Template directly, avoiding Cluster Template - mechanism. - """ - resp = self.api.post('/plugins/%s/%s/convert-config/%s' % - (plugin_name, - hadoop_version, - urlparse.quote(template_name)), - data=filecontent) - if resp.status_code != 202: - raise RuntimeError('Failed to upload template file for plugin "%s"' - ' and version "%s"' % - (plugin_name, hadoop_version)) - else: - return base.get_json(resp)['cluster_template'] diff --git a/saharaclient/api/shell.py b/saharaclient/api/shell.py deleted file mode 100644 index 40c339c..0000000 --- a/saharaclient/api/shell.py +++ /dev/null @@ -1,1012 +0,0 @@ -# Copyright 2013 Red Hat, Inc. -# 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 argparse -import datetime -import inspect -import json -import os.path -import sys - -from saharaclient.openstack.common.apiclient import exceptions -from saharaclient.openstack.common import cliutils as utils - - -def _print_list_field(field): - return lambda obj: ', '.join(getattr(obj, field)) - - -def _filter_call_args(args, func, remap={}): - """Filter args according to func's parameter list. - - Take three arguments: - * args - a dictionary - * func - a function - * remap - a dictionary - Remove from dct all the keys which are not among the parameters - of func. Before filtering, remap the keys in the args dict - according to remap dict. - """ - - for name, new_name in remap.items(): - if name in args: - args[new_name] = args[name] - del args[name] - - valid_args = inspect.getargspec(func).args - for name in args.keys(): - if name not in valid_args: - print('WARNING: "%s" is not a valid parameter and will be ' - 'discarded from the request' % name) - del args[name] - - -def _print_node_group_field(cluster): - return ', '.join(map(lambda x: ': '.join(x), - [(node_group['name'], - str(node_group['count'])) - for node_group in cluster.node_groups])) - - -def _show_node_group_template(template): - template._info['node_processes'] = ( - ', '.join(template._info['node_processes']) - ) - utils.print_dict(template._info) - - -def _show_cluster_template(template): - template._info['node_groups'] = _print_node_group_field(template) - utils.print_dict(template._info) - - -def _show_cluster(cluster): - # TODO(mattf): Make this pretty, e.g format node_groups and info urls - # Forcing wrap=47 allows for clean display on a terminal of width 80 - utils.print_dict(cluster._info, wrap=47) - - -def _show_job_binary_data(data): - columns = ('id', 'name') - utils.print_list(data, columns) - - -def _show_data_source(source): - # TODO(mattf): why are we passing credentials around like this? - if 'credentials' in source._info: - del source._info['credentials'] - utils.print_dict(source._info) - - -def _show_job_binary(binary): - # TODO(mattf): why are we passing credentials around like this? - if 'extra' in binary._info: - del binary._info['extra'] - utils.print_dict(binary._info) - - -def _show_job_template(template): - # TODO(mattf): Make "mains" property pretty - # TODO(mattf): handle/remove "extra" creds - utils.print_dict(template._info) - - -def _show_job(job): - # TODO(mattf): make display of info pretty, until then - # extract the important status information - job._info['status'] = job._info['info']['status'] - del job._info['info'] - utils.print_dict(job._info) - - -def _get_by_id_or_name(manager, id=None, name=None, **kwargs): - if not (name or id): - raise exceptions.CommandError("either NAME or ID is required") - if id: - return manager.get(id, **kwargs) - ls = manager.find(name=name) - if len(ls) == 0: - raise exceptions.CommandError("%s '%s' not found" % - (manager.resource_class.resource_name, - name)) - elif len(ls) > 1: - raise exceptions.CommandError("%s '%s' not unique, try by ID" % - (manager.resource_class.resource_name, - name)) - return manager.get(ls[0].id, **kwargs) - - -# -# Plugins -# ~~~~~~~ -# plugin-list -# -# plugin-show --name [--version ] -# - -def do_plugin_list(cs, args): - """Print a list of available plugins.""" - plugins = cs.plugins.list() - columns = ('name', 'versions', 'title') - utils.print_list(plugins, columns, - {'versions': _print_list_field('versions')}) - - -@utils.arg('--name', - metavar='', - required=True, - help='Name of the plugin.') -# TODO(mattf) - saharaclient does not support query w/ version -# @utils.arg('--version', -# metavar='', -# help='Optional version') -def do_plugin_show(cs, args): - """Show details of a plugin.""" - plugin = cs.plugins.get(args.name) - plugin._info['versions'] = ', '.join(plugin._info['versions']) - utils.print_dict(plugin._info) - - -# -# Image Registry -# ~~~~~~~~~~~~~~ -# image-list [--tag ]* -# -# image-show --name |--id -# -# image-register --name |--id -# [--username ] [--description ] -# -# image-unregister --name |--id -# -# image-add-tag --name |--id --tag + -# -# image-remove-tag --name |--id --tag + -# - -# TODO(mattf): [--tag ]* -def do_image_list(cs, args): - """Print a list of available images.""" - images = cs.images.list() - columns = ('name', 'id', 'username', 'tags', 'description') - utils.print_list(images, columns, {'tags': _print_list_field('tags')}) - - -@utils.arg('--name', - help='Name of the image.') -@utils.arg('--id', - metavar='', - help='ID of the image.') -def do_image_show(cs, args): - """Show details of an image.""" - image = _get_by_id_or_name(cs.images, args.id, args.name) - del image._info['metadata'] - image._info['tags'] = ', '.join(image._info['tags']) - utils.print_dict(image._info) - - -# TODO(mattf): Add --name, must lookup in glance index -@utils.arg('--id', - metavar='', - required=True, - help='ID of image, run "glance image-list" to see all IDs.') -@utils.arg('--username', - default='root', - metavar='', - help='Username of privileged user in the image.') -@utils.arg('--description', - default='', - metavar='', - help='Description of the image.') -def do_image_register(cs, args): - """Register an image from the Image index.""" - # TODO(mattf): image register should not be through update - cs.images.update_image(args.id, args.username, args.description) - # TODO(mattf): No indication of result, expect image details - - -@utils.arg('--name', - help='Name of the image.') -@utils.arg('--id', - metavar='', - help='ID of image to unregister.') -def do_image_unregister(cs, args): - """Unregister an image.""" - cs.images.unregister_image( - args.id or _get_by_id_or_name(cs.images, name=args.name).id - ) - # TODO(mattf): No indication of result, expect result to display - - -@utils.arg('--name', - help='Name of the image.') -@utils.arg('--id', - metavar='', - help='ID of image to tag.') -# TODO(mattf): Change --tag to --tag+ -@utils.arg('--tag', - metavar='', - required=True, - help='Tag to add.') -def do_image_add_tag(cs, args): - """Add a tag to an image.""" - # TODO(mattf): Need proper add_tag API call - id = args.id or _get_by_id_or_name(cs.images, name=args.name).id - cs.images.update_tags(id, cs.images.get(id).tags + [args.tag, ]) - # TODO(mattf): No indication of result, expect image details - - -@utils.arg('--name', - help='Name of the image.') -@utils.arg('--id', - metavar='', - help='Image to tag.') -# TODO(mattf): Change --tag to --tag+ -@utils.arg('--tag', - metavar='', - required=True, - help='Tag to remove.') -def do_image_remove_tag(cs, args): - """Remove a tag from an image.""" - # TODO(mattf): Need proper remove_tag API call - id = args.id or _get_by_id_or_name(cs.images, name=args.name).id - cs.images.update_tags(id, - filter(lambda x: x != args.tag, - cs.images.get(id).tags)) - # TODO(mattf): No indication of result, expect image details - - -# -# Clusters -# ~~~~~~~~ -# cluster-list -# -# cluster-show --name |--id [--json] [--show-progress] -# -# cluster-create [--json ] -# -# cluster-scale --name |--id [--json ] -# -# cluster-delete --name |--id -# - -def do_cluster_list(cs, args): - """Print a list of available clusters.""" - clusters = cs.clusters.list() - for cluster in clusters: - cluster.node_count = sum(map(lambda g: g['count'], - cluster.node_groups)) - columns = ('name', 'id', 'status', 'node_count') - utils.print_list(clusters, columns) - - -@utils.arg('--name', - help='Name of the cluster.') -@utils.arg('--id', - metavar='', - help='ID of the cluster to show.') -@utils.arg('--show-progress', - help='Show provision progress events of the cluster.') -@utils.arg('--json', - action='store_true', - default=False, - help='Print JSON representation of the cluster.') -def do_cluster_show(cs, args): - """Show details of a cluster.""" - cluster = _get_by_id_or_name(cs.clusters, args.id, args.name, - show_progress=args.show_progress) - if args.json: - print(json.dumps(cluster._info)) - else: - _show_cluster(cluster) - - -@utils.arg('--json', - default=sys.stdin, - type=argparse.FileType('r'), - help='JSON representation of cluster.') -@utils.arg('--count', - default=1, - type=int, - help='Number of clusters to create.') -def do_cluster_create(cs, args): - """Create a cluster.""" - # TODO(mattf): improve template validation, e.g. template w/o name key - template = json.loads(args.json.read()) - # The neutron_management_network parameter to clusters.create is - # called net_id. Therefore, we must translate before invoking - # create w/ **template. It may be desirable to simple change - # clusters.create in the future. - remap = {'neutron_management_network': 'net_id'} - template['count'] = args.count - _filter_call_args(template, cs.clusters.create, remap) - - _show_cluster(cs.clusters.create(**template)) - - -@utils.arg('--name', - help='Name of the cluster.') -@utils.arg('--id', - metavar='', - help='ID of the cluster.') -@utils.arg('--json', - default=sys.stdin, - type=argparse.FileType('r'), - help='JSON representation of cluster scale.') -def do_cluster_scale(cs, args): - """Scale a cluster.""" - cluster_id = args.id or _get_by_id_or_name(cs.clusters, name=args.name).id - scale_template = json.loads(args.json.read()) - _show_cluster(cs.clusters.scale(cluster_id, **scale_template)) - - -@utils.arg('--name', - help='Name of the cluster.') -@utils.arg('--id', - metavar='', - help='ID of the cluster to delete.') -def do_cluster_delete(cs, args): - """Delete a cluster.""" - cs.clusters.delete( - args.id or _get_by_id_or_name(cs.clusters, name=args.name).id - ) - # TODO(mattf): No indication of result - - -# -# Node Group Templates -# ~~~~~~~~~~~~~~~~~~~~ -# node-group-template-list -# -# node-group-template-show --name