Retire Sahara: remove repo content
Sahara project is retiring - https://review.opendev.org/c/openstack/governance/+/919374 this commit remove the content of this project repo Depends-On: https://review.opendev.org/c/openstack/project-config/+/919376 Change-Id: I45547184ec98d53346b98f3b3dcee84cf035e39f
This commit is contained in:
parent
38b63d870f
commit
fcc67b0374
.coveragerc.gitignore.stestr.conf.zuul.yamlCONTRIBUTING.rstHACKING.rstLICENSEREADME.rstrequirements.txt
doc
releasenotes
notes
.placeholderapi-v2-features-650eb8cc0f50a729.yamlautogenerated-api-docs-3bc8513e63bfe610.yamlautogenerated-cli-docs-c1e89ec6ea66c4a9.yamlcli-deprecation-da0e7b6dfe77af52.yamldesignate-integration-16c59a6b57dbcfa4.yamldrop-py2-7-862abe2ec0c32c5f.yamlevent-logs-c6d286e25dc7d9b1.yamlexperimental-v2-support-67ccf699e056ed78.yamlfields-unset-068db4c3e680c37d.yamlfix-job-binary-download-py3-5592eca2345305bd.yamlfix-osc-520-regression-a92dff38f04e6a57.yamlimplement-pagination-2ba52769d240a3ce.yamljob-binary-create-optional-bc0f9ee6426c5659.yamljob-create-optional-034307a6b5db2cf2.yamljob-execution-create-optional-1014a403e5ffa7ac.yamljob-job-template-apiv2-change-93ffbf2b1360cddc.yamlmultiple-clusters-change-69a15f00597739d7.yamlnew-cli-6119bf8a4fb24ab6.yamlosc-apiv2-4079c8cdb839ae42.yamlplugin-api-f650c26a030b7df8.yamlremove-functional-tests-c4b9d43c2c32d121.yamlremove-old-cli-commands-06b9936ce044dd0f.yamlremove-py26-dad75fc8d602b3c5.yamlremove-py33-8364cb4805391750.yamlrename_version_to_plugin-version-20cfe17530446391.yamlrework-auth-c3e13a68a935671e.yamlshares-update-d6f7e28acd27aa7f.yamlstart-using-reno-1f3418c11785c9ab.yamltags-update-c794416bcc035cb8.yamlupdate-image-optional-f83c5746d88507cd.yamlvolume-mount-prefix-b6ef396a357cddd0.yaml
source
saharaclient
12
.coveragerc
12
.coveragerc
@ -1,12 +0,0 @@
|
||||
[run]
|
||||
branch = True
|
||||
source = saharaclient
|
||||
omit =
|
||||
.tox/*
|
||||
saharaclient/tests/*
|
||||
|
||||
[paths]
|
||||
source = saharaclient
|
||||
|
||||
[report]
|
||||
ignore_errors = True
|
40
.gitignore
vendored
40
.gitignore
vendored
@ -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
|
||||
.stestr
|
||||
out
|
||||
target
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
*.db
|
||||
.coverage
|
||||
nosetests.xml
|
||||
pylint-report.txt
|
||||
ChangeLog
|
||||
cscope.out
|
||||
.testrepository
|
||||
AUTHORS
|
||||
cover
|
||||
doc/html
|
||||
doc/source/apidoc
|
||||
doc/build
|
||||
*.log
|
||||
# Files created by releasenotes build
|
||||
releasenotes/build
|
@ -1,3 +0,0 @@
|
||||
[DEFAULT]
|
||||
test_path=./saharaclient/tests
|
||||
top_dir=./
|
65
.zuul.yaml
65
.zuul.yaml
@ -1,65 +0,0 @@
|
||||
- project:
|
||||
queue: sahara
|
||||
templates:
|
||||
- openstack-cover-jobs
|
||||
- openstack-python3-zed-jobs
|
||||
- publish-openstack-docs-pti
|
||||
- check-requirements
|
||||
- release-notes-jobs-python3
|
||||
- openstackclient-plugin-jobs
|
||||
check:
|
||||
jobs:
|
||||
- python-saharaclient-scenario:
|
||||
voting: false
|
||||
- python-saharaclient-scenario-v2:
|
||||
voting: false
|
||||
- python-saharaclient-tempest:
|
||||
voting: false
|
||||
- python-saharaclient-tempest-v2:
|
||||
voting: false
|
||||
gate:
|
||||
jobs:
|
||||
- python-saharaclient-scenario:
|
||||
voting: false
|
||||
- python-saharaclient-scenario-v2:
|
||||
voting: false
|
||||
- python-saharaclient-tempest:
|
||||
voting: false
|
||||
- python-saharaclient-tempest-v2:
|
||||
voting: false
|
||||
|
||||
- job:
|
||||
name: python-saharaclient-scenario
|
||||
description: |
|
||||
Run scenario tests for Sahara against python-saharaclient
|
||||
changes.
|
||||
parent: sahara-tests-scenario
|
||||
required-projects:
|
||||
- openstack/python-saharaclient
|
||||
|
||||
- job:
|
||||
name: python-saharaclient-scenario-v2
|
||||
description: |
|
||||
Run scenario tests for Sahara on API v2 against python-saharaclient
|
||||
changes.
|
||||
parent: sahara-tests-scenario-v2
|
||||
required-projects:
|
||||
- openstack/python-saharaclient
|
||||
|
||||
- job:
|
||||
name: python-saharaclient-tempest
|
||||
description: |
|
||||
Run Tempest tests from the Sahara plugin against python-saharaclient
|
||||
changes.
|
||||
parent: sahara-tests-tempest
|
||||
required-projects:
|
||||
- openstack/python-saharaclient
|
||||
|
||||
- job:
|
||||
name: python-saharaclient-tempest-v2
|
||||
description: |
|
||||
Run Tempest tests from the Sahara plugin on API v2 against
|
||||
python-saharaclient changes.
|
||||
parent: sahara-tests-tempest-v2
|
||||
required-projects:
|
||||
- openstack/python-saharaclient
|
@ -1,19 +0,0 @@
|
||||
The source repository for this project can be found at:
|
||||
|
||||
https://opendev.org/openstack/python-saharaclient
|
||||
|
||||
Pull requests submitted through GitHub are not monitored.
|
||||
|
||||
To start contributing to OpenStack, follow the steps in the contribution guide
|
||||
to set up and use Gerrit:
|
||||
|
||||
https://docs.openstack.org/contributors/code-and-documentation/quick-start.html
|
||||
|
||||
Bugs should be filed on Storyboard:
|
||||
|
||||
https://storyboard.openstack.org/#!/project/openstack/python-saharaclient
|
||||
|
||||
For more specific information about contributing to this repository, see the
|
||||
python-saharaclient contributor guide:
|
||||
|
||||
https://docs.openstack.org/python-saharaclient/latest/contributor/contributing.html
|
45
HACKING.rst
45
HACKING.rst
@ -1,45 +0,0 @@
|
||||
Sahara Style Commandments
|
||||
=========================
|
||||
|
||||
- Step 1: Read the OpenStack Style Commandments
|
||||
https://docs.openstack.org/hacking/latest/
|
||||
- Step 2: Read on
|
||||
|
||||
Sahara Specific Commandments
|
||||
----------------------------
|
||||
|
||||
Commit Messages
|
||||
---------------
|
||||
Using a common format for commit messages will help keep our git history
|
||||
readable. Follow these guidelines:
|
||||
|
||||
- [S365] First, provide a brief summary of 50 characters or less. Summaries
|
||||
of greater than 72 characters will be rejected by the gate.
|
||||
|
||||
- [S364] The first line of the commit message should provide an accurate
|
||||
description of the change, not just a reference to a bug or blueprint.
|
||||
|
||||
Imports
|
||||
-------
|
||||
- [S366, S367] Organize your imports according to the ``Import order``
|
||||
|
||||
Dictionaries/Lists
|
||||
------------------
|
||||
|
||||
- [S360] Ensure default arguments are not mutable.
|
||||
- [S368] Must use a dict comprehension instead of a dict constructor with a
|
||||
sequence of key-value pairs. For more information, please refer to
|
||||
http://legacy.python.org/dev/peps/pep-0274/
|
||||
|
||||
Logs
|
||||
----
|
||||
|
||||
- [S373] Don't translate logs
|
||||
|
||||
- [S374] You used a deprecated log level
|
||||
|
||||
Importing json
|
||||
--------------
|
||||
|
||||
- [S375] It's more preferable to use ``jsonutils`` from ``oslo_serialization``
|
||||
instead of ``json`` for operating with ``json`` objects.
|
176
LICENSE
176
LICENSE
@ -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.
|
||||
|
51
README.rst
51
README.rst
@ -1,45 +1,10 @@
|
||||
========================
|
||||
Team and repository tags
|
||||
========================
|
||||
This project is no longer maintained.
|
||||
|
||||
.. image:: https://governance.openstack.org/tc/badges/python-saharaclient.svg
|
||||
:target: https://governance.openstack.org/tc/reference/tags/index.html
|
||||
|
||||
.. Change things from this point on
|
||||
|
||||
Python bindings to the OpenStack Sahara API
|
||||
===========================================
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/python-saharaclient.svg
|
||||
:target: https://pypi.org/project/python-saharaclient/
|
||||
:alt: Latest Version
|
||||
|
||||
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
|
||||
<https://docs.openstack.org/infra/manual/developers.html>`_.
|
||||
|
||||
.. _Docs: https://docs.openstack.org/python-saharaclient/latest/
|
||||
|
||||
* License: Apache License, Version 2.0
|
||||
* `PyPi`_ - package installation
|
||||
* `Online Documentation`_
|
||||
* `Blueprints`_ - feature specifications
|
||||
* `Bugs`_ - stories and issue tracking
|
||||
* `Source`_
|
||||
* `Specs`_
|
||||
* `How to Contribute`_
|
||||
|
||||
.. _PyPi: https://pypi.org/project/python-saharaclient
|
||||
.. _Online Documentation: https://docs.openstack.org/python-saharaclient/latest/
|
||||
.. _Blueprints: https://specs.openstack.org/openstack/sahara-specs/
|
||||
.. _Bugs: https://storyboard.openstack.org/#!/project/934
|
||||
.. _Source: https://opendev.org/openstack/python-saharaclient
|
||||
.. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html
|
||||
.. _Specs: https://specs.openstack.org/openstack/sahara-specs/
|
||||
.. _Release Notes: https://docs.openstack.org/releasenotes/python-saharaclient
|
||||
The contents of this repository are still available in the Git
|
||||
source code management system. To see the contents of this
|
||||
repository before it reached its end of life, please check out the
|
||||
previous commit with "git checkout HEAD^1".
|
||||
|
||||
For any further questions, please email
|
||||
openstack-discuss@lists.openstack.org or join #openstack-dev on
|
||||
OFTC.
|
||||
|
@ -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)
|
386
doc/ext/ext.py
386
doc/ext/ext.py
@ -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 docutils.parsers.rst 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)
|
@ -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
|
@ -1,7 +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.
|
||||
openstackdocstheme>=2.2.1 # Apache-2.0
|
||||
reno>=3.1.0 # Apache-2.0
|
||||
sphinx>=2.0.0,!=2.1.0 # BSD
|
||||
python-saharaclient>=1.1.0
|
@ -1,11 +0,0 @@
|
||||
<h3>Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://wiki.openstack.org/wiki/Sahara">Sahara @ OpenStack Wiki</a></li>
|
||||
<li><a href="https://storyboard.openstack.org/#!/project_group/74">Sahara @ Storyboard</a></li>
|
||||
</ul>
|
||||
|
||||
{% if READTHEDOCS %}
|
||||
<script type='text/javascript'>
|
||||
$('div.body').css('margin', 0)
|
||||
</script>
|
||||
{% endif %}
|
@ -1,4 +0,0 @@
|
||||
{% extends "basic/layout.html" %}
|
||||
{% set css_files = css_files + ['_static/tweaks.css'] %}
|
||||
|
||||
{% block relbar1 %}{% endblock relbar1 %}
|
@ -1,4 +0,0 @@
|
||||
[theme]
|
||||
inherit = nature
|
||||
stylesheet = nature.css
|
||||
pygments_style = tango
|
@ -1,9 +0,0 @@
|
||||
=================
|
||||
Sahara CLI client
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
intro
|
||||
reference
|
@ -1,64 +0,0 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
The Sahara shell utility now is part of the OpenStackClient, so all
|
||||
shell commands take the following form:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ openstack dataprocessing <command> [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 <command>
|
||||
|
||||
For more information about commands and their parameters you can refer to
|
||||
:doc:`the Sahara CLI commands <reference>`.
|
||||
|
||||
For more information about abilities and features of OpenStackClient CLI you
|
||||
can refer to `OpenStackClient documentation <https://docs.openstack.org/python-openstackclient/latest/>`_
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The CLI is configured via environment variables and command-line options which
|
||||
are described in https://docs.openstack.org/python-openstackclient/latest/cli/authentication.html.
|
||||
|
||||
Authentication using username/password is most commonly used and can be
|
||||
provided with environment variables:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export OS_AUTH_URL=<url-to-openstack-identity>
|
||||
export OS_PROJECT_NAME=<project-name>
|
||||
export OS_USERNAME=<username>
|
||||
export OS_PASSWORD=<password> # (optional)
|
||||
|
||||
or command-line options:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
--os-auth-url <url>
|
||||
--os-project-name <project-name>
|
||||
--os-username <username>
|
||||
[--os-password <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=<url-to-sahara-API>
|
@ -1,64 +0,0 @@
|
||||
CLI Reference
|
||||
=============
|
||||
|
||||
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
|
@ -1,258 +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 sys
|
||||
|
||||
import os
|
||||
import warnings
|
||||
|
||||
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',
|
||||
'openstackdocstheme']
|
||||
|
||||
# openstackdocstheme options
|
||||
openstackdocs_repo_name = 'openstack/python-saharaclient'
|
||||
openstackdocs_use_storyboard = True
|
||||
openstackdocs_auto_name = False
|
||||
|
||||
# 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 = 'Sahara Client'
|
||||
copyright = '2013, OpenStack Foundation'
|
||||
|
||||
|
||||
# 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 = 'native'
|
||||
|
||||
# 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.
|
||||
html_theme = 'openstackdocs'
|
||||
|
||||
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
|
||||
# "<project> v<release> 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 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 <link> 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', 'Sahara Client',
|
||||
'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', 'Sahara Client',
|
||||
['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', 'Sahara Client',
|
||||
'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'
|
@ -1,14 +0,0 @@
|
||||
============================
|
||||
So You Want to Contribute...
|
||||
============================
|
||||
|
||||
For general information on contributing to OpenStack, please check out the
|
||||
`contributor guide <https://docs.openstack.org/contributors/>`_ to get started.
|
||||
It covers all the basics that are common to all OpenStack projects: the
|
||||
accounts you need, the basics of interacting with our Gerrit review system, how
|
||||
we communicate as a community, etc.
|
||||
|
||||
python-saharaclient is maintained by the OpenStack Sahara project.
|
||||
To understand our development process and how you can contribute to it, please
|
||||
look at the Sahara project's general contributor's page:
|
||||
https://docs.openstack.org/sahara/latest/contributor/contributing.html
|
@ -1,8 +0,0 @@
|
||||
=================
|
||||
Contributor Guide
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
contributing
|
@ -1,25 +0,0 @@
|
||||
Python bindings to the OpenStack Sahara API
|
||||
===========================================
|
||||
|
||||
This is a client for OpenStack Sahara API. There's :doc:`a Python API client
|
||||
<reference/index>` (the :mod:`saharaclient` module), and a :doc:`command-line utility
|
||||
<cli/index>` (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.
|
||||
|
||||
__ https://docs.openstack.org/sahara/latest/
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
reference/index
|
||||
cli/index
|
||||
contributor/index
|
@ -1,9 +0,0 @@
|
||||
===============
|
||||
Reference guide
|
||||
===============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
pythonclient
|
||||
pythonclient_v2
|
@ -1,177 +0,0 @@
|
||||
Python 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: https://docs.openstack.org/python-keystoneclient/latest/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.PluginManagerV1
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Image Registry ops
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.images.ImageManagerV1
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Node Group Template ops
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.node_group_templates.NodeGroupTemplateManagerV1
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Cluster Template ops
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.cluster_templates.ClusterTemplateManagerV1
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Cluster ops
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.clusters.ClusterManagerV1
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Data Source ops
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.data_sources.DataSourceManagerV1
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Job Binary Internal ops
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.job_binary_internals.JobBinaryInternalsManager
|
||||
:members: create, update
|
||||
|
||||
Job Binary ops
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.job_binaries.JobBinariesManagerV1
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Job ops
|
||||
~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.jobs.JobsManagerV1
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Job Execution ops
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.job_executions.JobExecutionsManager
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Job Types ops
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.job_types.JobTypesManager
|
||||
:members:
|
||||
:inherited-members:
|
@ -1,82 +0,0 @@
|
||||
Python Sahara client for APIv2
|
||||
==============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
There is also support for Sahara's experimental APIv2.
|
||||
|
||||
|
||||
Supported operations
|
||||
--------------------
|
||||
|
||||
Plugin ops
|
||||
~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.plugins.PluginManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Image Registry ops
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.images.ImageManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Node Group Template ops
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.node_group_templates.NodeGroupTemplateManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Cluster Template ops
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.cluster_templates.ClusterTemplateManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Cluster ops
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.clusters.ClusterManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Data Source ops
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.data_sources.DataSourceManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Job Binary ops
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.job_binaries.JobBinariesManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Job Template ops
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.v2.job_templates.JobTemplatesManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Job ops
|
||||
~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.v2.jobs.JobsManagerV2
|
||||
:members:
|
||||
:inherited-members:
|
||||
|
||||
Job Types ops
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: saharaclient.api.job_types.JobTypesManager
|
||||
:members:
|
||||
:inherited-members:
|
||||
:noindex:
|
@ -1,12 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The basic saharaclient and the OSC plugin now include support for
|
||||
the enhanced boot from volume mechanism introduced in the Stein
|
||||
release of Sahara, and support for the keypair replacement
|
||||
mechanism introduced in the Rocky release of Sahara. The OSC plugin
|
||||
also now includes support for the force deletion of clusters
|
||||
feature introduced in the Queens release of Sahara, and support
|
||||
for the decommision of a specific instance feature (albeit only via
|
||||
the --json flag) introduced in the Queens release of Sahara. (All
|
||||
of these features are exclusive to Sahara's APIv2.)
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- >
|
||||
Automatically generated documentation for saharaclient API was added.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- >
|
||||
Automatically generated documentation for saharaclient CLI was added.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
deprecations:
|
||||
- >
|
||||
Old CLI is deprecated and will not be maintained.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Added integration of Designate for hostname resolution through dns
|
||||
servers
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Python 2.7 support has been dropped. Last release of python-saharaclient
|
||||
to support python 2.7 is OpenStack Train. The minimum version of Python now
|
||||
supported by python-saharaclient is Python 3.6.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Providing ability to make dump of event logs for clusters.
|
||||
Also displaying shorten version of event logs by option.
|
@ -1,3 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Initial support for Sahara's experimental APIv2 is present.
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- >
|
||||
[`bug 1534050 <https://bugs.launchpad.net/python-saharaclient/+bug/1534050>`_]
|
||||
Now object's fields can be unset with ``update`` calls.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fix the "job binary download" command when Python 3 is used.
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
A change in python-openstackclient 5.2.0 broke the image register command.
|
||||
The incompatibility is now solved but the python-openstackclient
|
||||
requirement has been bumped to 5.2.0.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- >
|
||||
Pagination for list operations is implemented.
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- >
|
||||
[`bug 1508406 <https://bugs.launchpad.net/python-saharaclient/+bug/1508406>`_]
|
||||
Now ``description`` and ``extra`` parameters of jobs ``create`` method
|
||||
are optional.
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- >
|
||||
[`bug 1506448 <https://bugs.launchpad.net/python-saharaclient/+bug/1506448>`_]
|
||||
Now ``mains``, ``libs`` and ``description`` parameters of jobs ``create``
|
||||
method are optional.
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- >
|
||||
[`bug 1507966 <https://bugs.launchpad.net/python-saharaclient/+bug/1507966>`_]
|
||||
Now input_id, output_id, configs parameters of job executions create
|
||||
method are optional.
|
@ -1,4 +0,0 @@
|
||||
other:
|
||||
- When using APIv2, the viewing (GET) of specific job templates and jobs and
|
||||
the creation (POST) of job templates and jobs now only supports the API
|
||||
behavior of Sahara 9.0.0.0b3 or later.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
other:
|
||||
- When using APIv2, the creation of multiple clusters simultaneously
|
||||
now only supports the API behavior of Sahara 9.0.0.0b2 or later.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- >
|
||||
New CLI as part of the openstackclient was implemented.
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adding the ability for the CLI to communicate with OpenStack
|
||||
Sahara using the new APIv2.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- Plugins updates are supported now in saharaclient. Also
|
||||
information about plugin labels is available for users.
|
@ -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.
|
@ -1,7 +0,0 @@
|
||||
---
|
||||
prelude: >
|
||||
Old CLI commands are removed. Please use OpenStackClient
|
||||
instead.
|
||||
deprecations:
|
||||
- Old CLI commands are removed. Please use OpenStackClient
|
||||
instead.
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
deprecations:
|
||||
- >
|
||||
[`bug 1519510 <https://bugs.launchpad.net/python-saharaclient/+bug/1519510>`_]
|
||||
Support of python 2.6 was dropped.
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
deprecations:
|
||||
- >
|
||||
[`bug 1526170 <https://bugs.launchpad.net/python-saharaclient/+bug/1526170>`_]
|
||||
Support of python 3.3 was dropped.
|
@ -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.
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
The Sahara client library now only supports authentication with a Keystone
|
||||
session object. Consequently the arguments which `saharaclient.api.Client`
|
||||
accepts, and the order of those arguments, have changed.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
features:
|
||||
- >
|
||||
Now shares can be edited on an existing cluster.
|
@ -1,4 +0,0 @@
|
||||
---
|
||||
other:
|
||||
- >
|
||||
Start using reno to manage release notes.
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- >
|
||||
[`bug 1500790 <https://bugs.launchpad.net/python-saharaclient/+bug/1500790>`_]
|
||||
Now tags can be added and removed simultaneously in one call.
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- >
|
||||
[`bug 1510470 <https://bugs.launchpad.net/python-saharaclient/+bug/1510470>`_]
|
||||
Now ``desc`` parameter of ``update_image`` is optional.
|
@ -1,6 +0,0 @@
|
||||
---
|
||||
fixes:
|
||||
- >
|
||||
[`bug 1499697 <https://bugs.launchpad.net/python-saharaclient/+bug/1499697>`_]
|
||||
Now node group templates can be created and updated with
|
||||
``volume_mount_prefix`` parameter.
|
@ -1,6 +0,0 @@
|
||||
===========================
|
||||
2023.2 Series Release Notes
|
||||
===========================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/2023.2
|
@ -1,222 +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 = [
|
||||
'reno.sphinxext',
|
||||
'openstackdocstheme'
|
||||
]
|
||||
|
||||
# openstackdocstheme options
|
||||
openstackdocs_repo_name = 'openstack/python-saharaclient'
|
||||
openstackdocs_use_storyboard = True
|
||||
openstackdocs_auto_name = False
|
||||
|
||||
# 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'
|
||||
|
||||
# Release notes are version independent.
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = ''
|
||||
# The short X.Y version.
|
||||
version = ''
|
||||
|
||||
# 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 = 'native'
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'openstackdocs'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> 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 <link> 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
|
||||
|
||||
# -- Options for Internationalization output ------------------------------
|
||||
locale_dirs = ['locale/']
|
@ -1,22 +0,0 @@
|
||||
===========================
|
||||
Saharaclient Release Notes
|
||||
===========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
unreleased
|
||||
2023.2
|
||||
yoga
|
||||
xena
|
||||
wallaby
|
||||
victoria
|
||||
ussuri
|
||||
train
|
||||
stein
|
||||
rocky
|
||||
queens
|
||||
pike
|
||||
ocata
|
||||
newton
|
||||
mitaka
|
@ -1,6 +0,0 @@
|
||||
===================================
|
||||
Mitaka Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: origin/stable/mitaka
|
@ -1,6 +0,0 @@
|
||||
===================================
|
||||
Newton Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: origin/stable/newton
|
@ -1,6 +0,0 @@
|
||||
===================================
|
||||
Ocata Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: origin/stable/ocata
|
@ -1,6 +0,0 @@
|
||||
===================================
|
||||
Pike Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/pike
|
@ -1,6 +0,0 @@
|
||||
===================================
|
||||
Queens Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/queens
|
@ -1,6 +0,0 @@
|
||||
===================================
|
||||
Rocky Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/rocky
|
@ -1,6 +0,0 @@
|
||||
===================================
|
||||
Stein Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/stein
|
@ -1,6 +0,0 @@
|
||||
==========================
|
||||
Train Series Release Notes
|
||||
==========================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/train
|
@ -1,5 +0,0 @@
|
||||
==============================
|
||||
Current Series Release Notes
|
||||
==============================
|
||||
|
||||
.. release-notes::
|
@ -1,6 +0,0 @@
|
||||
===========================
|
||||
Ussuri Series Release Notes
|
||||
===========================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/ussuri
|
@ -1,6 +0,0 @@
|
||||
=============================
|
||||
Victoria Series Release Notes
|
||||
=============================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/victoria
|
@ -1,6 +0,0 @@
|
||||
============================
|
||||
Wallaby Series Release Notes
|
||||
============================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/wallaby
|
@ -1,6 +0,0 @@
|
||||
=========================
|
||||
Xena Series Release Notes
|
||||
=========================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/xena
|
@ -1,6 +0,0 @@
|
||||
=========================
|
||||
Yoga Series Release Notes
|
||||
=========================
|
||||
|
||||
.. release-notes::
|
||||
:branch: stable/yoga
|
@ -1,14 +0,0 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr>=3.1.1 # Apache-2.0
|
||||
|
||||
keystoneauth1>=3.4.0 # Apache-2.0
|
||||
osc-lib>=2.0.0 # Apache-2.0
|
||||
oslo.log>=5.0.0 # Apache-2.0
|
||||
oslo.serialization>=2.25.0 # Apache-2.0
|
||||
oslo.i18n>=3.20.0 # Apache-2.0
|
||||
oslo.utils>=3.33.0 # Apache-2.0
|
||||
python-openstackclient>=5.2.0 # Apache-2.0
|
||||
requests>=2.14.2 # Apache-2.0
|
@ -1,19 +0,0 @@
|
||||
# Copyright 2017 Huawei, 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.
|
||||
#
|
||||
|
||||
from saharaclient import version
|
||||
|
||||
|
||||
__version__ = version.version_info.version_string()
|
@ -1,20 +0,0 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""oslo.i18n integration module.
|
||||
See https://docs.openstack.org/oslo.i18n/latest/user/usage.html
|
||||
"""
|
||||
|
||||
import oslo_i18n
|
||||
|
||||
|
||||
_ = oslo_i18n.TranslatorFactory(domain='saharaclient').primary
|
@ -1,284 +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
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from urllib import parse
|
||||
|
||||
from saharaclient._i18n import _
|
||||
|
||||
|
||||
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 self.defaults.items():
|
||||
if name not in info:
|
||||
info[name] = value
|
||||
|
||||
def _add_details(self, info):
|
||||
for (k, v) in info.items():
|
||||
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 kwargs.items():
|
||||
if var_value is not None:
|
||||
data[var_name] = var_value
|
||||
|
||||
def _copy_if_updated(self, data, **kwargs):
|
||||
for var_name, var_value in kwargs.items():
|
||||
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 not in [200, 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')
|
||||
|
||||
li = [self.resource_class(self, res)
|
||||
for res in data]
|
||||
|
||||
return Page(li, 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, data=None):
|
||||
if data is not None:
|
||||
kwargs = {'json': data}
|
||||
resp = self.api.delete(url, **kwargs)
|
||||
else:
|
||||
resp = self.api.delete(url)
|
||||
|
||||
if resp.status_code not in [200, 204]:
|
||||
self._raise_api_exception(resp)
|
||||
|
||||
if resp.status_code == 200:
|
||||
return get_json(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 jsonutils.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
|
@ -1,116 +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 keystoneauth1 import adapter
|
||||
|
||||
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
|
||||
from saharaclient.api.v2 import job_templates
|
||||
from saharaclient.api.v2 import jobs as jobs_v2
|
||||
|
||||
|
||||
USER_AGENT = 'python-saharaclient'
|
||||
|
||||
|
||||
class HTTPClient(adapter.Adapter):
|
||||
|
||||
def request(self, *args, **kwargs):
|
||||
kwargs.setdefault('raise_exc', False)
|
||||
kwargs.setdefault('allow', {'allow_experimental': True})
|
||||
return super(HTTPClient, self).request(*args, **kwargs)
|
||||
|
||||
|
||||
class Client(object):
|
||||
|
||||
_api_version = '1.1'
|
||||
|
||||
"""Client for the OpenStack Data Processing API.
|
||||
:param session: Keystone session object. Required.
|
||||
:param string sahara_url: Endpoint override.
|
||||
:param string endpoint_type: Desired Sahara endpoint type.
|
||||
:param string service_type: Sahara service name in Keystone catalog.
|
||||
:param string region_name: Name of a region to select when choosing an
|
||||
endpoint from the service catalog.
|
||||
"""
|
||||
def __init__(self, session=None, sahara_url=None,
|
||||
endpoint_type='publicURL', service_type='data-processing',
|
||||
region_name=None, **kwargs):
|
||||
|
||||
if not session:
|
||||
raise RuntimeError("Must provide session")
|
||||
|
||||
auth = session.auth
|
||||
|
||||
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,
|
||||
version=self._api_version,
|
||||
**kwargs)
|
||||
|
||||
self._register_managers(client)
|
||||
|
||||
def _register_managers(self, client):
|
||||
self.clusters = clusters.ClusterManagerV1(client)
|
||||
self.cluster_templates = (
|
||||
cluster_templates.ClusterTemplateManagerV1(client)
|
||||
)
|
||||
self.node_group_templates = (
|
||||
node_group_templates.NodeGroupTemplateManagerV1(client)
|
||||
)
|
||||
self.plugins = plugins.PluginManagerV1(client)
|
||||
self.images = images.ImageManagerV1(client)
|
||||
self.data_sources = data_sources.DataSourceManagerV1(client)
|
||||
self.jobs = jobs.JobsManagerV1(client)
|
||||
self.job_executions = job_executions.JobExecutionsManager(client)
|
||||
self.job_binaries = job_binaries.JobBinariesManagerV1(client)
|
||||
self.job_binary_internals = (
|
||||
job_binary_internals.JobBinaryInternalsManager(client)
|
||||
)
|
||||
self.job_types = job_types.JobTypesManager(client)
|
||||
|
||||
|
||||
class ClientV2(Client):
|
||||
|
||||
_api_version = '2'
|
||||
|
||||
def _register_managers(self, client):
|
||||
self.clusters = clusters.ClusterManagerV2(client)
|
||||
self.cluster_templates = (
|
||||
cluster_templates.ClusterTemplateManagerV2(client)
|
||||
)
|
||||
self.node_group_templates = (
|
||||
node_group_templates.NodeGroupTemplateManagerV2(client)
|
||||
)
|
||||
self.plugins = plugins.PluginManagerV2(client)
|
||||
self.images = images.ImageManagerV2(client)
|
||||
self.data_sources = data_sources.DataSourceManagerV2(client)
|
||||
self.job_templates = job_templates.JobTemplatesManagerV2(client)
|
||||
self.jobs = jobs_v2.JobsManagerV2(client)
|
||||
self.job_binaries = job_binaries.JobBinariesManagerV2(client)
|
||||
self.job_types = job_types.JobTypesManager(client)
|
@ -1,167 +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 ClusterTemplateManagerV1(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,
|
||||
}
|
||||
|
||||
return self._do_create(data, description, cluster_configs,
|
||||
node_groups, anti_affinity, net_id,
|
||||
default_image_id, use_autoconfig, shares,
|
||||
is_public, is_protected, domain_name)
|
||||
|
||||
def _do_create(self, data, description, cluster_configs, node_groups,
|
||||
anti_affinity, net_id, default_image_id, use_autoconfig,
|
||||
shares, is_public, is_protected, domain_name):
|
||||
|
||||
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)
|
||||
|
||||
def export(self, cluster_template_id):
|
||||
"""Export a Cluster Template."""
|
||||
return self._get('/cluster-templates/%s/export' % cluster_template_id)
|
||||
|
||||
|
||||
class ClusterTemplateManagerV2(ClusterTemplateManagerV1):
|
||||
NotUpdated = base.NotUpdated()
|
||||
|
||||
def create(self, name, plugin_name, plugin_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,
|
||||
'plugin_version': plugin_version
|
||||
}
|
||||
|
||||
return self._do_create(data, description, cluster_configs,
|
||||
node_groups, anti_affinity, net_id,
|
||||
default_image_id, use_autoconfig, shares,
|
||||
is_public, is_protected, domain_name)
|
||||
|
||||
def update(self, cluster_template_id, name=NotUpdated,
|
||||
plugin_name=NotUpdated, plugin_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,
|
||||
plugin_version=plugin_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._patch('/cluster-templates/%s' % cluster_template_id,
|
||||
data, 'cluster_template')
|
||||
|
||||
|
||||
# NOTE(jfreud): keep this around for backwards compatibility
|
||||
ClusterTemplateManager = ClusterTemplateManagerV1
|
@ -1,223 +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 urllib import parse
|
||||
|
||||
from saharaclient.api import base
|
||||
|
||||
|
||||
class Cluster(base.Resource):
|
||||
resource_name = 'Cluster'
|
||||
|
||||
|
||||
class ClusterManagerV1(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,
|
||||
}
|
||||
|
||||
return self._do_create(data, cluster_template_id, default_image_id,
|
||||
is_transient, description, cluster_configs,
|
||||
node_groups, user_keypair_id, anti_affinity,
|
||||
net_id, count, use_autoconfig, shares,
|
||||
is_public, is_protected, api_ver=1.1)
|
||||
|
||||
def _do_create(self, data, cluster_template_id, default_image_id,
|
||||
is_transient, description, cluster_configs, node_groups,
|
||||
user_keypair_id, anti_affinity, net_id, count,
|
||||
use_autoconfig, shares, is_public, is_protected, api_ver):
|
||||
|
||||
# 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:
|
||||
if api_ver >= 2:
|
||||
return self._create('/clusters', data)
|
||||
else:
|
||||
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)
|
||||
|
||||
|
||||
class ClusterManagerV2(ClusterManagerV1):
|
||||
|
||||
def create(self, name, plugin_name, plugin_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,
|
||||
'plugin_version': plugin_version,
|
||||
}
|
||||
|
||||
return self._do_create(data, cluster_template_id, default_image_id,
|
||||
is_transient, description, cluster_configs,
|
||||
node_groups, user_keypair_id, anti_affinity,
|
||||
net_id, count, use_autoconfig, shares,
|
||||
is_public, is_protected, api_ver=2)
|
||||
|
||||
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 (optionally specifiying which instances to
|
||||
delete) or add instances of a new node group to an 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",
|
||||
"instances": ["instance_id1", "instance_id2"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
"""
|
||||
return self._update('/clusters/%s' % cluster_id, scale_object)
|
||||
|
||||
def force_delete(self, cluster_id):
|
||||
"""Force Delete a Cluster."""
|
||||
data = {'force': True}
|
||||
return self._delete('/clusters/%s' % cluster_id, data)
|
||||
|
||||
def update_keypair(self, cluster_id):
|
||||
"""Reflect an updated keypair on the cluster."""
|
||||
data = {'update_keypair': True}
|
||||
return self._patch("/clusters/%s" % cluster_id, data)
|
||||
|
||||
|
||||
# NOTE(jfreud): keep this around for backwards compatibility
|
||||
ClusterManager = ClusterManagerV1
|
@ -1,98 +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 DataSourceManagerV1(base.ResourceManager):
|
||||
resource_class = DataSources
|
||||
version = 1.1
|
||||
|
||||
def create(self, name, description, data_source_type,
|
||||
url, credential_user=None, credential_pass=None,
|
||||
is_public=None, is_protected=None, s3_credentials=None):
|
||||
"""Create a Data Source."""
|
||||
|
||||
data = {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'type': data_source_type,
|
||||
'url': url,
|
||||
}
|
||||
credentials = {}
|
||||
self._copy_if_defined(credentials,
|
||||
user=credential_user,
|
||||
password=credential_pass)
|
||||
credentials = credentials or s3_credentials
|
||||
self._copy_if_defined(data, is_public=is_public,
|
||||
is_protected=is_protected,
|
||||
credentials=credentials)
|
||||
|
||||
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 the keys `user` and `password` for data
|
||||
source in Swift, or with the keys `accesskey`, `secretkey`,
|
||||
`endpoint`, `ssl`, and `bucket_in_path` for data source in S3
|
||||
"""
|
||||
|
||||
if self.version >= 2:
|
||||
UPDATE_FUNC = self._patch
|
||||
else:
|
||||
UPDATE_FUNC = self._update
|
||||
|
||||
return UPDATE_FUNC('/data-sources/%s' % data_source_id,
|
||||
update_data)
|
||||
|
||||
|
||||
class DataSourceManagerV2(DataSourceManagerV1):
|
||||
version = 2
|
||||
|
||||
|
||||
# NOTE(jfreud): keep this around for backwards compatibility
|
||||
DataSourceManager = DataSourceManagerV1
|
@ -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
|
@ -1,92 +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)
|
||||
|
||||
|
||||
class ImageManagerV1(_ImageManager):
|
||||
def update_tags(self, image_id, new_tags):
|
||||
"""Update an Image tags.
|
||||
|
||||
:param new_tags: list of tags that will replace currently
|
||||
assigned tags
|
||||
"""
|
||||
# Do not add :param list in the docstring above until this is solved:
|
||||
# https://github.com/sphinx-doc/sphinx/issues/2549
|
||||
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)
|
||||
|
||||
|
||||
class ImageManagerV2(_ImageManager):
|
||||
def get_tags(self, image_id):
|
||||
return self._get('/images/%s/tags' % image_id)
|
||||
|
||||
def update_tags(self, image_id, new_tags):
|
||||
return self._update('/images/%s/tags' % image_id,
|
||||
{'tags': new_tags})
|
||||
|
||||
def delete_tags(self, image_id):
|
||||
return self._delete('/images/%s/tags' % image_id)
|
||||
|
||||
|
||||
# NOTE(jfreud): keep this around for backwards compatibility
|
||||
ImageManager = ImageManagerV1
|
@ -1,103 +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 JobBinariesManagerV1(base.ResourceManager):
|
||||
resource_class = JobBinaries
|
||||
version = 1.1
|
||||
|
||||
def create(self, name, url, description=None, extra=None, is_public=None,
|
||||
is_protected=None):
|
||||
"""Create a Job Binary.
|
||||
|
||||
:param dict extra: authentication info needed for some job binaries,
|
||||
containing the keys `user` and `password` for job binary in Swift
|
||||
or the keys `accesskey`, `secretkey`, and `endpoint` for job
|
||||
binary in S3
|
||||
|
||||
"""
|
||||
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 the keys `user` and `password` for job binary
|
||||
in Swift, or with the keys `accesskey`, `secretkey`, and `endpoint`
|
||||
for job binary in S3
|
||||
"""
|
||||
|
||||
if self.version >= 2:
|
||||
UPDATE_FUNC = self._patch
|
||||
else:
|
||||
UPDATE_FUNC = self._update
|
||||
|
||||
return UPDATE_FUNC(
|
||||
'/job-binaries/%s' % job_binary_id, data, 'job_binary')
|
||||
|
||||
|
||||
class JobBinariesManagerV2(JobBinariesManagerV1):
|
||||
version = 2
|
||||
|
||||
|
||||
# NOTE(jfreud): keep this around for backwards compatibility
|
||||
JobBinariesManager = JobBinariesManagerV1
|
@ -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 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 of 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)
|
@ -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)
|
@ -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')
|
@ -1,73 +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 JobsManagerV1(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)
|
||||
|
||||
|
||||
# NOTE(jfreud): keep this around for backwards compatibility
|
||||
JobsManager = JobsManagerV1
|
@ -1,240 +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 NodeGroupTemplateManagerV1(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
|
||||
}
|
||||
|
||||
return self._do_create(data, description, volumes_per_node,
|
||||
volumes_size, node_configs, floating_ip_pool,
|
||||
security_groups, auto_security_group,
|
||||
availability_zone, volumes_availability_zone,
|
||||
volume_type, image_id, is_proxy_gateway,
|
||||
volume_local_to_instance, use_autoconfig,
|
||||
shares, is_public, is_protected,
|
||||
volume_mount_prefix)
|
||||
|
||||
def _do_create(self, data, description, volumes_per_node, volumes_size,
|
||||
node_configs, floating_ip_pool, security_groups,
|
||||
auto_security_group, availability_zone,
|
||||
volumes_availability_zone, volume_type, image_id,
|
||||
is_proxy_gateway, volume_local_to_instance, use_autoconfig,
|
||||
shares, is_public, is_protected, volume_mount_prefix,
|
||||
boot_from_volume=None, boot_volume_type=None,
|
||||
boot_volume_az=None, boot_volume_local=None):
|
||||
|
||||
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,
|
||||
boot_from_volume=boot_from_volume,
|
||||
boot_volume_type=boot_volume_type,
|
||||
boot_volume_availability_zone=boot_volume_az,
|
||||
boot_volume_local_to_instance=boot_volume_local
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
def export(self, ng_template_id):
|
||||
"""Export a Node Group Template."""
|
||||
return self._get('/node-group-templates/%s/export' % ng_template_id)
|
||||
|
||||
|
||||
class NodeGroupTemplateManagerV2(NodeGroupTemplateManagerV1):
|
||||
NotUpdated = base.NotUpdated()
|
||||
|
||||
def create(self, name, plugin_name, plugin_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, boot_from_volume=None,
|
||||
boot_volume_type=None, boot_volume_availability_zone=None,
|
||||
boot_volume_local_to_instance=None):
|
||||
"""Create a Node Group Template."""
|
||||
|
||||
data = {
|
||||
'name': name,
|
||||
'plugin_name': plugin_name,
|
||||
'plugin_version': plugin_version,
|
||||
'flavor_id': flavor_id,
|
||||
'node_processes': node_processes
|
||||
}
|
||||
|
||||
return self._do_create(data, description, volumes_per_node,
|
||||
volumes_size, node_configs, floating_ip_pool,
|
||||
security_groups, auto_security_group,
|
||||
availability_zone, volumes_availability_zone,
|
||||
volume_type, image_id, is_proxy_gateway,
|
||||
volume_local_to_instance, use_autoconfig,
|
||||
shares, is_public, is_protected,
|
||||
volume_mount_prefix, boot_from_volume,
|
||||
boot_volume_type,
|
||||
boot_volume_availability_zone,
|
||||
boot_volume_local_to_instance)
|
||||
|
||||
def update(self, ng_template_id, name=NotUpdated, plugin_name=NotUpdated,
|
||||
plugin_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,
|
||||
boot_from_volume=NotUpdated,
|
||||
boot_volume_type=NotUpdated,
|
||||
boot_volume_availability_zone=NotUpdated,
|
||||
boot_volume_local_to_instance=NotUpdated):
|
||||
"""Update a Node Group Template."""
|
||||
|
||||
data = {}
|
||||
self._copy_if_updated(
|
||||
data, name=name, plugin_name=plugin_name,
|
||||
plugin_version=plugin_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,
|
||||
boot_from_volume=boot_from_volume,
|
||||
boot_volume_type=boot_volume_type,
|
||||
boot_volume_availability_zone=boot_volume_availability_zone,
|
||||
boot_volume_local_to_instance=boot_volume_local_to_instance
|
||||
)
|
||||
|
||||
return self._patch('/node-group-templates/%s' % ng_template_id, data,
|
||||
'node_group_template')
|
||||
|
||||
|
||||
# NOTE(jfreud): keep this around for backwards compatibility
|
||||
NodeGroupTemplateManager = NodeGroupTemplateManagerV1
|
@ -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))
|
@ -1,92 +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 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')
|
||||
|
||||
|
||||
class PluginManagerV1(_PluginManager):
|
||||
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']
|
||||
|
||||
|
||||
class PluginManagerV2(_PluginManager):
|
||||
def get_version_details(self, plugin_name, plugin_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, plugin_version),
|
||||
'plugin')
|
||||
|
||||
|
||||
# NOTE(jfreud): keep this around for backwards compatibility
|
||||
PluginManager = PluginManagerV1
|
@ -1,70 +0,0 @@
|
||||
# Copyright (c) 2018 OpenStack Foundation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from saharaclient.api import base
|
||||
|
||||
|
||||
class JobTemplate(base.Resource):
|
||||
resource_name = 'Job Template'
|
||||
|
||||
|
||||
class JobTemplatesManagerV2(base.ResourceManager):
|
||||
resource_class = JobTemplate
|
||||
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 Template."""
|
||||
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('/%s' % 'job-templates', data, 'job_template')
|
||||
|
||||
def list(self, search_opts=None, limit=None,
|
||||
marker=None, sort_by=None, reverse=None):
|
||||
"""Get a list of Job Templates."""
|
||||
query = base.get_query_string(search_opts, limit=limit, marker=marker,
|
||||
sort_by=sort_by, reverse=reverse)
|
||||
|
||||
url = "/%s%s" % ('job-templates', query)
|
||||
return self._page(url, 'job_templates', limit)
|
||||
|
||||
def get(self, job_id):
|
||||
"""Get information about a Job Template."""
|
||||
return self._get('/%s/%s' % ('job-templates', job_id), 'job_template')
|
||||
|
||||
def get_configs(self, job_type):
|
||||
"""Get config hints for a specified Job Template type."""
|
||||
return self._get('/%s/config-hints/%s' % ('job-templates', job_type))
|
||||
|
||||
def delete(self, job_id):
|
||||
"""Delete a Job Template."""
|
||||
self._delete('/%s/%s' % ('job-templates', job_id))
|
||||
|
||||
def update(self, job_id, name=NotUpdated, description=NotUpdated,
|
||||
is_public=NotUpdated, is_protected=NotUpdated):
|
||||
"""Update a Job Template."""
|
||||
|
||||
data = {}
|
||||
self._copy_if_updated(data, name=name, description=description,
|
||||
is_public=is_public, is_protected=is_protected)
|
||||
|
||||
return self._patch('/%s/%s' % ('job-templates', job_id), data)
|
@ -1,72 +0,0 @@
|
||||
# Copyright (c) 2018 OpenStack Foundation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from saharaclient.api import base
|
||||
|
||||
|
||||
class Job(base.Resource):
|
||||
resource_name = 'Job'
|
||||
|
||||
|
||||
class JobsManagerV2(base.ResourceManager):
|
||||
resource_class = Job
|
||||
NotUpdated = base.NotUpdated()
|
||||
|
||||
def list(self, search_opts=None, marker=None, limit=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, obj_id):
|
||||
"""Get information about a Job."""
|
||||
return self._get('/jobs/%s' % obj_id, 'job')
|
||||
|
||||
def delete(self, obj_id):
|
||||
"""Delete a Job."""
|
||||
self._delete('/jobs/%s' % obj_id)
|
||||
|
||||
def create(self, job_template_id, cluster_id, input_id=None,
|
||||
output_id=None, configs=None, interface=None, is_public=None,
|
||||
is_protected=None):
|
||||
"""Launch a Job."""
|
||||
|
||||
data = {
|
||||
"cluster_id": cluster_id,
|
||||
"job_template_id": job_template_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('/jobs', data, 'job')
|
||||
|
||||
def refresh_status(self, obj_id):
|
||||
"""Refresh Job Status."""
|
||||
return self._get(
|
||||
'/jobs/%s?refresh_status=True' % obj_id,
|
||||
'job'
|
||||
)
|
||||
|
||||
def update(self, obj_id, is_public=NotUpdated, is_protected=NotUpdated):
|
||||
"""Update a Job."""
|
||||
|
||||
data = {}
|
||||
self._copy_if_updated(data, is_public=is_public,
|
||||
is_protected=is_protected)
|
||||
return self._patch('/jobs/%s' % obj_id, data)
|
@ -1,48 +0,0 @@
|
||||
# Copyright (c) 2014 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 oslo_utils import importutils
|
||||
|
||||
|
||||
class UnsupportedVersion(Exception):
|
||||
"""Indication for using an unsupported version of the API.
|
||||
|
||||
Indicates that the user is trying to use an unsupported
|
||||
version of the API.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def get_client_class(version):
|
||||
version_map = {
|
||||
'1.0': 'saharaclient.api.client.Client',
|
||||
'1.1': 'saharaclient.api.client.Client',
|
||||
'2': 'saharaclient.api.client.ClientV2',
|
||||
}
|
||||
try:
|
||||
client_path = version_map[str(version)]
|
||||
except (KeyError, ValueError):
|
||||
supported_versions = ', '.join(version_map.keys())
|
||||
msg = ("Invalid client version '%(version)s'; must be one of: "
|
||||
"%(versions)s") % {'version': version,
|
||||
'versions': supported_versions}
|
||||
raise UnsupportedVersion(msg)
|
||||
|
||||
return importutils.import_class(client_path)
|
||||
|
||||
|
||||
def Client(version, *args, **kwargs):
|
||||
client_class = get_client_class(version)
|
||||
return client_class(*args, **kwargs)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user