diff --git a/.gitignore b/.gitignore deleted file mode 100644 index aab8db3b..00000000 --- a/.gitignore +++ /dev/null @@ -1,67 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg -*.eggs - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -cover/ -htmlcov/ -.tox/ -.coverage -.coverage.* -.idea -.cache -.stestr/ -coverage.xml - -# Translations -*.mo - -# Django stuff: -*.log - -# Sphinx documentation -doc/build/ - -# PyBuilder -target/ - -# Files created by releasenotes build -releasenotes/build - -# pbr generated files -AUTHORS -ChangeLog - -# swap file -*.swp diff --git a/.stestr.conf b/.stestr.conf deleted file mode 100644 index e3000769..00000000 --- a/.stestr.conf +++ /dev/null @@ -1,3 +0,0 @@ -[DEFAULT] -test_path=${OS_TEST_PATH:-./senlinclient/tests/unit} -top_dir=./ diff --git a/.zuul.yaml b/.zuul.yaml deleted file mode 100644 index a7bd8117..00000000 --- a/.zuul.yaml +++ /dev/null @@ -1,41 +0,0 @@ -- job: - name: senlinclient-functional - parent: devstack-tox-functional - required-projects: - - openstack/python-senlinclient - - openstack/senlin - vars: - openrc_enable_export: true - devstack_plugins: - senlin: https://opendev.org/openstack/senlin - devstack_local_conf: - post-config: - $SENLIN_CONF: - DEFAULT: - cloud_backend: openstack_test - default_log_levels: >- - amqp=WARN,amqplib=WARN,sqlalchemy=WARN,oslo_messaging=WARN - ,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN - ,urllib3.connectionpool=WARN - ,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN - ,keystonemiddleware=WARN - ,routes.middleware=WARN - ,stevedore=WARN - ,oslo_messaging._drivers.amqp=WARN - ,oslo_messaging._drivers.amqpdriver=WARN - irrelevant-files: - - ^senlinclient/tests/unit/.*$ - - ^setup.cfg$ - - ^tools/.*$ - -- project: - templates: - - check-requirements - - openstack-python3-jobs - - openstackclient-plugin-jobs - - publish-openstack-docs-pti - - release-notes-jobs-python3 - check: - jobs: - - senlinclient-functional: - voting: false diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 50355a8a..00000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,16 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps documented at: - - https://docs.openstack.org/infra/manual/developers.html - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - - https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/python-senlinclient diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 67db8588..00000000 --- a/LICENSE +++ /dev/null @@ -1,175 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/README.rst b/README.rst index 7280a436..4ee2c5f1 100644 --- a/README.rst +++ b/README.rst @@ -1,18 +1,10 @@ -======================== -Team and repository tags -======================== +This project is no longer maintained. -.. image:: https://governance.openstack.org/tc/badges/python-senlinclient.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html +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". -.. Change things from this point on - -OpenStackClient Plugin for Senlin Clustering Service -==================================================== - -This is a client library for Senlin built on the Senlin clustering API. It -provides a plugin for the openstackclient command-line tool. - -Development takes place via the usual OpenStack processes as outlined in the -`developer guide `_. -The master repository is in `Git `_. +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-dev on +OFTC. diff --git a/TODO b/TODO deleted file mode 100644 index 504793e1..00000000 --- a/TODO +++ /dev/null @@ -1,23 +0,0 @@ -High Priority -============= - - - Support action_cancel - - Add support to HTTPS connection - * This means a cert and key option using plain HTTP package, while - it means using Transport when we switched to OpenStackSDK - - Add checking for token based authentication - - Add CLI argument checking, required vs optional - -Middle Priority -=============== - - - Use code from https://review.opendev.org/#/c/95679/ to replace - _append_global_identity_args(parser) - - Add unit tests - - Figure out how to use access_info and reauthenticate parameters for - authentication. - - Support trust based authentication - -Low Priority -============ - diff --git a/bindep.txt b/bindep.txt deleted file mode 100644 index a2011f5f..00000000 --- a/bindep.txt +++ /dev/null @@ -1,5 +0,0 @@ -# This file contains runtime (non-python) dependencies -# More info at: http://docs.openstack.org/infra/bindep/readme.html - -# tools/misc-sanity-checks.sh validates .po[t] files -gettext [test] diff --git a/doc/.gitignore b/doc/.gitignore deleted file mode 100644 index 8e0be80f..00000000 --- a/doc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -source/ref/ diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 8fab18b0..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-senlinclient.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-senlinclient.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/python-senlinclient" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python-senlinclient" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index e96c14f5..00000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,6 +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 -sphinx>=2.0.0,!=2.1.0 # BSD -reno>=3.1.0 # Apache-2.0 diff --git a/doc/source/cli/index.rst b/doc/source/cli/index.rst deleted file mode 100644 index e23fd7f9..00000000 --- a/doc/source/cli/index.rst +++ /dev/null @@ -1,88 +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. - -=================== -Senlin CLI man page -=================== - - -SYNOPSIS -======== - -The Senlin clustering service doesn't provide its own command line tool -since Queens release. Users are supposed to use :program:`openstack cluster` -commands instead. The python-senlinclient project is an implementation of the -OpenStackClient (OSC) plugin that interacts with the Senlin clustering service. - -:program:`openstack` [options] [command-options] - -:program:`openstack help cluster` - - -DESCRIPTION -=========== - -The :program:`openstack cluster` command line utility interacts with OpenStack Cluster -Service (Senlin). - -In order to use the CLI, you must provide your OpenStack username, password, -project (historically called tenant), and auth endpoint. You can use -configuration options `--os-username`, `--os-password`, `--os-project-name`, -`--os-identity-api-version`, `-os-user-domain-name`, `--os-project-domain-name` -and `--os-auth-url` or set corresponding environment -variables:: - - export OS_USERNAME=user - export OS_PASSWORD=pass - export OS_PROJECT_NAME=myproject - export OS_IDENTITY_API_VERSION=3 - export OS_AUTH_URL=http://auth.example.com:5000/v3 - export OS_USER_DOMAIN_NAME=Default - export OS_PROJECT_DOMAIN_NAME=Default - -OPTIONS -======= - -To get a list of available commands and options run:: - - openstack help cluster - -To get usage and options of a command:: - - openstack help cluster - -EXAMPLES -======== - -Get help for profile create command:: - - openstack help cluster profile create - -List all the profiles:: - - openstack cluster profile list - -Create new profile:: - - openstack cluster profile create --spec-file cirros_basic.yaml PF001 - -Show a specific profile details:: - - openstack cluster profile show PF001 - -Create a node:: - - openstack cluster node create --profile PF001 NODE001 - -For more information, please see the senlin documentation. -`https://docs.openstack.org/senlin/latest/tutorial/basics.html` diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 03d9aad2..00000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,70 +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. -# -# python-senlinclient documentation build configuration file - -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'openstackdocstheme', -] - -# The content that will be inserted into the main body of an autoclass -# directive. -autoclass_content = 'both' - -# 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' - -# openstackdocstheme options -openstackdocs_repo_name = 'openstack/python-senlinclient' -openstackdocs_bug_project = 'python-senlinclient' -openstackdocs_bug_tag = '' -copyright = 'OpenStack Contributors' - -# List of directories, relative to source directory, that shouldn't be searched -# for source files. -exclude_trees = [] - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'native' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -html_theme = 'openstackdocs' - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'senlin', 'OpenStack Senlin command line client', - ['OpenStack Contributors'], 1), -] diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst deleted file mode 100644 index b41c9d33..00000000 --- a/doc/source/contributor/index.rst +++ /dev/null @@ -1,55 +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. - -================== -SenlinClient Tests -================== - -Unit Tests -========== - -Senlinclient contains a suite of unit tests, in the senlinclient/tests/unit -directory. - -Any proposed code change will be automatically rejected by the OpenStack -Jenkins server if the change causes unit test failures. - -Running the tests ------------------ -There are a number of ways to run unit tests currently, and there's a -combination of frameworks used depending on what commands you use. The -preferred method is to use tox, which calls stestr via the tox.ini file. -To run all tests simply run:: - - tox - -This will create a virtual environment, load all the packages from -test-requirements.txt and run all unit tests as well as run flake8 and hacking -checks against the code. - -Note that you can inspect the tox.ini file to get more details on the available -options and what the test run does by default. - -Running a subset of tests using tox ------------------------------------ -One common activity is to just run a single test, you can do this with tox -simply by specifying to just run py27 or py35 tests against a single test:: - - tox -epy27 senlinclient.tests.unit.v1.test_node.TestNodeList.test_node_list_defaults - -Or all tests in the test_node.py file:: - - tox -epy27 senlinclient.tests.unit.v1.test_node - -For more information on these options and how to run tests, please see the -`stestr documentation `_. diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index e15ceb9c..00000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -=============================================== -Welcome to python-senlinclient's documentation! -=============================================== - -Contents --------- - -.. toctree:: - :maxdepth: 2 - - install/index - contributor/index - cli/index - - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`search` - diff --git a/doc/source/install/index.rst b/doc/source/install/index.rst deleted file mode 100644 index 016cc759..00000000 --- a/doc/source/install/index.rst +++ /dev/null @@ -1,36 +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. - -.. _guide-install: - -============ -Installation -============ - -If you are installing senlinclient from an OpenStack distribution, follow the -guide provided by the vendor. - -If you prefer installing senlinclient from source repo, you can do it by -first get senlinclient code from OpenStack git repository. - -:: - - $ cd /opt/stack - $ git clone https://opendev.org/openstack/python-senlinclient.git - -Then execute the following command - -:: - - $ cd python-senlinclient - $ sudo python setup.py install diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/notes/bug-1814171-b1c58797c9ca9f44.yaml b/releasenotes/notes/bug-1814171-b1c58797c9ca9f44.yaml deleted file mode 100644 index e6124205..00000000 --- a/releasenotes/notes/bug-1814171-b1c58797c9ca9f44.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - | - [`bug 1814171 `_] - Fixed a bug so that cluster delete and node delete return action id - associated with the delete action. diff --git a/releasenotes/notes/cli-deprecation-241b9569b85f8fbd.yaml b/releasenotes/notes/cli-deprecation-241b9569b85f8fbd.yaml deleted file mode 100644 index d156131c..00000000 --- a/releasenotes/notes/cli-deprecation-241b9569b85f8fbd.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -other: - - The 'senlin' CLI will be removed in April 2017. This message is now - explicitly printed when senlin CLI commands are invoked. diff --git a/releasenotes/notes/cluster-collect-a9d1bc8c2e799c7c.yaml b/releasenotes/notes/cluster-collect-a9d1bc8c2e799c7c.yaml deleted file mode 100644 index 9724c9ce..00000000 --- a/releasenotes/notes/cluster-collect-a9d1bc8c2e799c7c.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - A new command 'senlin cluster-collect' and its corresponding OSC plugin - command has been added. This new command can be used to aggregate a - specific property across a cluster. diff --git a/releasenotes/notes/cluster-policy-list-42ff03ef25d64dd1.yaml b/releasenotes/notes/cluster-policy-list-42ff03ef25d64dd1.yaml deleted file mode 100644 index 55f65ecf..00000000 --- a/releasenotes/notes/cluster-policy-list-42ff03ef25d64dd1.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -fixes: - - The cluster policy list command was broken by new SDK changes and then - fixed. The 'enabled' field is now renamed to 'is_enabled'. diff --git a/releasenotes/notes/cluster-run-210247ab70b289a5.yaml b/releasenotes/notes/cluster-run-210247ab70b289a5.yaml deleted file mode 100644 index 064f3b66..00000000 --- a/releasenotes/notes/cluster-run-210247ab70b289a5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - A new CLI command 'senlin cluster-run' and a new OSC plugin command - 'openstack cluster run' have been added. Use the 'help' command to find - out how to use it. diff --git a/releasenotes/notes/cluster-scaling-command-e0d96f2cd0c7ca5f.yaml b/releasenotes/notes/cluster-scaling-command-e0d96f2cd0c7ca5f.yaml deleted file mode 100644 index 3856593a..00000000 --- a/releasenotes/notes/cluster-scaling-command-e0d96f2cd0c7ca5f.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - OSC commands for cluster scaling are changed from 'cluster scale in' - and 'cluster scale out' to 'cluster shrink' and 'cluster expand' - respectively. diff --git a/releasenotes/notes/deletion-output-a841931367a2689d.yaml b/releasenotes/notes/deletion-output-a841931367a2689d.yaml deleted file mode 100644 index a8f3fadc..00000000 --- a/releasenotes/notes/deletion-output-a841931367a2689d.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - The senlin CLI 'node-delete' and the OSC plugin command - 'cluster node delete' now outputs the action IDs when successful. Error - messages are printed when appropriate. diff --git a/releasenotes/notes/drop-py-2-7-cced38f13fd3b44c.yaml b/releasenotes/notes/drop-py-2-7-cced38f13fd3b44c.yaml deleted file mode 100644 index bc734922..00000000 --- a/releasenotes/notes/drop-py-2-7-cced38f13fd3b44c.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - | - Python 2.7 support has been dropped. Last release of python-senlinclient - to support python 2.7 is OpenStack Train. The minimum version of Python now - supported by python-senlinclient is Python 3.6. diff --git a/releasenotes/notes/fix-region-732c2be90e58c347.yaml b/releasenotes/notes/fix-region-732c2be90e58c347.yaml deleted file mode 100644 index d2abbdaa..00000000 --- a/releasenotes/notes/fix-region-732c2be90e58c347.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -fixes: - - Fixed a bug that region name is not respected when connecting to cloud. diff --git a/releasenotes/notes/force-delete-c8d6cf4d6f049cb2.yaml b/releasenotes/notes/force-delete-c8d6cf4d6f049cb2.yaml deleted file mode 100644 index 1bad5f4c..00000000 --- a/releasenotes/notes/force-delete-c8d6cf4d6f049cb2.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -fixes: - - Fixed a bug that force deletion of cluster or node was not working. diff --git a/releasenotes/notes/micro-version-1.10-dabb632bfa40b79b.yaml b/releasenotes/notes/micro-version-1.10-dabb632bfa40b79b.yaml deleted file mode 100644 index db18599d..00000000 --- a/releasenotes/notes/micro-version-1.10-dabb632bfa40b79b.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -fixes: - - Changed CURRENT_API_VERSION to "1.10". diff --git a/releasenotes/notes/micro-version-a292ce3b00d886af.yaml b/releasenotes/notes/micro-version-a292ce3b00d886af.yaml deleted file mode 100644 index 6ed3285a..00000000 --- a/releasenotes/notes/micro-version-a292ce3b00d886af.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - The senlinclient now supports API micro-versioning. Current supported - version is 'clustering 1.2'. diff --git a/releasenotes/notes/node-check-recover-469bf81db9f9f1ec.yaml b/releasenotes/notes/node-check-recover-469bf81db9f9f1ec.yaml deleted file mode 100644 index 5bc21a0a..00000000 --- a/releasenotes/notes/node-check-recover-469bf81db9f9f1ec.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Added command for node-check and node-recover. diff --git a/releasenotes/notes/others-e13ff69738d062c6.yaml b/releasenotes/notes/others-e13ff69738d062c6.yaml deleted file mode 100644 index 93adf661..00000000 --- a/releasenotes/notes/others-e13ff69738d062c6.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -other: - - Switched testr switch to stestr. - - Fixed tox python3 overrides. - - Followed the new PTI for document build. - - Fix tox python3 overrides. - - Removed pypy because pypy is no longer supported by oslo libraries. \ No newline at end of file diff --git a/releasenotes/notes/policy-validate-193a5ebb7db3440a.yaml b/releasenotes/notes/policy-validate-193a5ebb7db3440a.yaml deleted file mode 100644 index d1bfb3cd..00000000 --- a/releasenotes/notes/policy-validate-193a5ebb7db3440a.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - A policy-validate command has been added to senlin command line. - OSC support is added as well. diff --git a/releasenotes/notes/profile-validate-587f1a964e93c0bf.yaml b/releasenotes/notes/profile-validate-587f1a964e93c0bf.yaml deleted file mode 100644 index 2f466e80..00000000 --- a/releasenotes/notes/profile-validate-587f1a964e93c0bf.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - A profile-validate command has been added to command line. It can be - used for validating the spec of a profile without creating it. diff --git a/releasenotes/notes/python-3.5-c9fd8e34c4046357.yaml b/releasenotes/notes/python-3.5-c9fd8e34c4046357.yaml deleted file mode 100644 index 9c64d6fa..00000000 --- a/releasenotes/notes/python-3.5-c9fd8e34c4046357.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - The support to python 3.5 has been verified and gated. diff --git a/releasenotes/notes/receiver-create-8305d4efbdf35f35.yaml b/releasenotes/notes/receiver-create-8305d4efbdf35f35.yaml deleted file mode 100644 index dea8a549..00000000 --- a/releasenotes/notes/receiver-create-8305d4efbdf35f35.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -other: - - The receiver creation command (both senlin CLI and OSC plugin command) - now allow 'cluster' and 'action' to be left unspecified if the receiver - type is not 'webhook'. diff --git a/releasenotes/notes/retire-senlin-cli-8ba21807b584993d.yaml b/releasenotes/notes/retire-senlin-cli-8ba21807b584993d.yaml deleted file mode 100644 index 83d9de26..00000000 --- a/releasenotes/notes/retire-senlin-cli-8ba21807b584993d.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - The `senlin` command line support is completely dropped. Users are expected - to use `openstack cluster` commands to interact with Senlin service. diff --git a/releasenotes/notes/senlinclient-1.1.0-daf1f24c73ee8b17.yaml b/releasenotes/notes/senlinclient-1.1.0-daf1f24c73ee8b17.yaml deleted file mode 100644 index 3c76b5b6..00000000 --- a/releasenotes/notes/senlinclient-1.1.0-daf1f24c73ee8b17.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -fixes: - - Fix resource list operations for openstackclient. - - Add filter "is_enabled" for policy binding list. - - Fix policy binding operations including attach, detach and update. - - Remove unsupported sort key "user" for event-list. - - Fix metadata purging. - - Add "cluster_id" colume for openstack cluster event list. - - Support "global_project" arguments for action-list. - - Fix resource update operations. diff --git a/releasenotes/notes/senlinclient-1.2.0-4680ea85ba2dc6c8.yaml b/releasenotes/notes/senlinclient-1.2.0-4680ea85ba2dc6c8.yaml deleted file mode 100644 index 44fe2b78..00000000 --- a/releasenotes/notes/senlinclient-1.2.0-4680ea85ba2dc6c8.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - Support node replace operation. - - Enhance the parameter check for "path" in cluster collect operation. - - Help message for metadata clean operations. -fixes: - - Fix incorrect description of profile/policy validate operations. - - Fix project_id and user_id show bug for profile/policy validate and - cluster policy show operations. - - Fix enabled option for senlin cluster-policy-detach command. diff --git a/releasenotes/notes/test-function-test-d90d7af1994a5f88.yaml b/releasenotes/notes/test-function-test-d90d7af1994a5f88.yaml deleted file mode 100644 index 4e652cef..00000000 --- a/releasenotes/notes/test-function-test-d90d7af1994a5f88.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Improved functional test for python-senlinclient. - - Aded profile, policy, cluster and receiver functional test. \ No newline at end of file diff --git a/releasenotes/source/2023.1.rst b/releasenotes/source/2023.1.rst deleted file mode 100644 index d1238479..00000000 --- a/releasenotes/source/2023.1.rst +++ /dev/null @@ -1,6 +0,0 @@ -=========================== -2023.1 Series Release Notes -=========================== - -.. release-notes:: - :branch: stable/2023.1 diff --git a/releasenotes/source/2023.2.rst b/releasenotes/source/2023.2.rst deleted file mode 100644 index a4838d7d..00000000 --- a/releasenotes/source/2023.2.rst +++ /dev/null @@ -1,6 +0,0 @@ -=========================== -2023.2 Series Release Notes -=========================== - -.. release-notes:: - :branch: stable/2023.2 diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 0b44ef5b..00000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,275 +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. - -# Senlin Release Notes documentation build configuration file, created by -# sphinx-quickstart on Tue Nov 3 17:40:50 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'reno.sphinxext', - 'openstackdocstheme', -] - -# 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 = 'Senlin Client Release Notes' -copyright = '2015, Senlin Developers' - -# Release notes are version independent. -# The full version, including alpha/beta/rc tags. -release = '' -# The short X.Y version. -version = '' - -# 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 = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# openstackdocstheme options -openstackdocs_repo_name = 'openstack/python-senlinclient' -openstackdocs_bug_project = 'python-senlinclient' -openstackdocs_bug_tag = '' -openstackdocs_auto_name = False - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'SenlinClientReleaseNotesdoc' - - -# -- 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', 'SenlinClientReleaseNotes.tex', - 'Senlin Client Release Notes Documentation', - 'Senlin 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', 'senlinclientreleasenotes', - 'Senlin Client Release Notes Documentation', - ['Senlin 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', 'SenlinClientReleaseNotes', - 'Senlin Client Release Notes Documentation', - 'Senlin Developers', 'SenlinClientReleaseNotes', - '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/'] diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index f165ed27..00000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,23 +0,0 @@ -============================= -Senlin Client Release Notes -============================= - -.. toctree:: - :maxdepth: 1 - - unreleased - 2023.2 - 2023.1 - zed - yoga - xena - wallaby - victoria - ussuri - train - stein - rocky - queens - pike - ocata - newton diff --git a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po deleted file mode 100644 index caa8e0e5..00000000 --- a/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,288 +0,0 @@ -# Andi Chandler , 2017. #zanata -# Andi Chandler , 2018. #zanata -# Andi Chandler , 2022. #zanata -# Andi Chandler , 2023. #zanata -msgid "" -msgstr "" -"Project-Id-Version: Senlin Client Release Notes\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-02-28 05:32+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2023-07-28 12:45+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en_GB\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "0.5.0" -msgstr "0.5.0" - -msgid "1.0.0" -msgstr "1.0.0" - -msgid "1.1.0" -msgstr "1.1.0" - -msgid "1.10.0" -msgstr "1.10.0" - -msgid "1.2.0" -msgstr "1.2.0" - -msgid "1.6.0" -msgstr "1.6.0" - -msgid "1.8.0" -msgstr "1.8.0" - -msgid "2.0.0" -msgstr "2.0.0" - -msgid "2023.1 Series Release Notes" -msgstr "2023.1 Series Release Notes" - -msgid "" -"A new CLI command 'senlin cluster-run' and a new OSC plugin command " -"'openstack cluster run' have been added. Use the 'help' command to find out " -"how to use it." -msgstr "" -"A new CLI command 'senlin cluster-run' and a new OSC plugin command " -"'openstack cluster run' have been added. Use the 'help' command to find out " -"how to use it." - -msgid "" -"A new command 'senlin cluster-collect' and its corresponding OSC plugin " -"command has been added. This new command can be used to aggregate a specific " -"property across a cluster." -msgstr "" -"A new command 'senlin cluster-collect' and its corresponding OSC plugin " -"command has been added. This new command can be used to aggregate a specific " -"property across a cluster." - -msgid "" -"A policy-validate command has been added to senlin command line. OSC support " -"is added as well." -msgstr "" -"A policy-validate command has been added to Senlin command line. OSC support " -"is added as well." - -msgid "" -"A profile-validate command has been added to command line. It can be used " -"for validating the spec of a profile without creating it." -msgstr "" -"A profile-validate command has been added to command line. It can be used " -"for validating the spec of a profile without creating it." - -msgid "Add \"cluster_id\" colume for openstack cluster event list." -msgstr "Add \"cluster_id\" column for openstack cluster event list." - -msgid "Add filter \"is_enabled\" for policy binding list." -msgstr "Add filter \"is_enabled\" for policy binding list." - -msgid "Added command for node-check and node-recover." -msgstr "Added command for node-check and node-recover." - -msgid "Aded profile, policy, cluster and receiver functional test." -msgstr "Added profile, policy, cluster and receiver functional test." - -msgid "Bug Fixes" -msgstr "Bug Fixes" - -msgid "Changed CURRENT_API_VERSION to \"1.10\"." -msgstr "Changed CURRENT_API_VERSION to \"1.10\"." - -msgid "Current Series Release Notes" -msgstr "Current Series Release Notes" - -msgid "Enhance the parameter check for \"path\" in cluster collect operation." -msgstr "Enhance the parameter check for \"path\" in cluster collect operation." - -msgid "Fix enabled option for senlin cluster-policy-detach command." -msgstr "Fix enabled option for Senlin cluster-policy-detach command." - -msgid "Fix incorrect description of profile/policy validate operations." -msgstr "Fix incorrect description of profile/policy validate operations." - -msgid "Fix metadata purging." -msgstr "Fix metadata purging." - -msgid "Fix policy binding operations including attach, detach and update." -msgstr "Fix policy binding operations including attach, detach and update." - -msgid "" -"Fix project_id and user_id show bug for profile/policy validate and cluster " -"policy show operations." -msgstr "" -"Fix project_id and user_id show bug for profile/policy validate and cluster " -"policy show operations." - -msgid "Fix resource list operations for openstackclient." -msgstr "Fix resource list operations for openstackclient." - -msgid "Fix resource update operations." -msgstr "Fix resource update operations." - -msgid "Fix tox python3 overrides." -msgstr "Fix tox python3 overrides." - -msgid "Fixed a bug that force deletion of cluster or node was not working." -msgstr "Fixed a bug that force deletion of cluster or node was not working." - -msgid "Fixed a bug that region name is not respected when connecting to cloud." -msgstr "" -"Fixed a bug that region name is not respected when connecting to cloud." - -msgid "Fixed tox python3 overrides." -msgstr "Fixed tox python3 overrides." - -msgid "Followed the new PTI for document build." -msgstr "Followed the new PTI for document build." - -msgid "Help message for metadata clean operations." -msgstr "Help message for metadata clean operations." - -msgid "Improved functional test for python-senlinclient." -msgstr "Improved functional test for python-senlinclient." - -msgid "New Features" -msgstr "New Features" - -msgid "Newton Series Release Notes" -msgstr "Newton Series Release Notes" - -msgid "" -"OSC commands for cluster scaling are changed from 'cluster scale in' and " -"'cluster scale out' to 'cluster shrink' and 'cluster expand' respectively." -msgstr "" -"OSC commands for cluster scaling are changed from 'cluster scale in' and " -"'cluster scale out' to 'cluster shrink' and 'cluster expand' respectively." - -msgid "Ocata Series Release Notes" -msgstr "Ocata Series Release Notes" - -msgid "Other Notes" -msgstr "Other Notes" - -msgid "Pike Series Release Notes" -msgstr "Pike Series Release Notes" - -msgid "" -"Python 2.7 support has been dropped. Last release of python-senlinclient to " -"support python 2.7 is OpenStack Train. The minimum version of Python now " -"supported by python-senlinclient is Python 3.6." -msgstr "" -"Python 2.7 support has been dropped. Last release of python-senlinclient to " -"support python 2.7 is OpenStack Train. The minimum version of Python now " -"supported by python-senlinclient is Python 3.6." - -msgid "Queens Series Release Notes" -msgstr "Queens Series Release Notes" - -msgid "Remove unsupported sort key \"user\" for event-list." -msgstr "Remove unsupported sort key \"user\" for event-list." - -msgid "Removed pypy because pypy is no longer supported by oslo libraries." -msgstr "Removed pypy because pypy is no longer supported by oslo libraries." - -msgid "Rocky Series Release Notes" -msgstr "Rocky Series Release Notes" - -msgid "Senlin Client Release Notes" -msgstr "Senlin Client Release Notes" - -msgid "Stein Series Release Notes" -msgstr "Stein Series Release Notes" - -msgid "Support \"global_project\" arguments for action-list." -msgstr "Support \"global_project\" arguments for action-list." - -msgid "Support node replace operation." -msgstr "Support node replace operation." - -msgid "Switched testr switch to stestr." -msgstr "Switched testr switch to stestr." - -msgid "" -"The 'senlin' CLI will be removed in April 2017. This message is now " -"explicitly printed when senlin CLI commands are invoked." -msgstr "" -"The 'senlin' CLI will be removed in April 2017. This message is now " -"explicitly printed when Senlin CLI commands are invoked." - -msgid "" -"The `senlin` command line support is completely dropped. Users are expected " -"to use `openstack cluster` commands to interact with Senlin service." -msgstr "" -"The `senlin` command line support is completely dropped. Users are expected " -"to use `openstack cluster` commands to interact with Senlin service." - -msgid "" -"The cluster policy list command was broken by new SDK changes and then " -"fixed. The 'enabled' field is now renamed to 'is_enabled'." -msgstr "" -"The cluster policy list command was broken by new SDK changes and then " -"fixed. The 'enabled' field is now renamed to 'is_enabled'." - -msgid "" -"The receiver creation command (both senlin CLI and OSC plugin command) now " -"allow 'cluster' and 'action' to be left unspecified if the receiver type is " -"not 'webhook'." -msgstr "" -"The receiver creation command (both Senlin CLI and OSC plugin command) now " -"allow 'cluster' and 'action' to be left unspecified if the receiver type is " -"not 'webhook'." - -msgid "" -"The senlin CLI 'node-delete' and the OSC plugin command 'cluster node " -"delete' now outputs the action IDs when successful. Error messages are " -"printed when appropriate." -msgstr "" -"The Senlin CLI 'node-delete' and the OSC plugin command 'cluster node " -"delete' now outputs the action IDs when successful. Error messages are " -"printed when appropriate." - -msgid "" -"The senlinclient now supports API micro-versioning. Current supported " -"version is 'clustering 1.2'." -msgstr "" -"The senlinclient now supports API micro-versioning. Current supported " -"version is 'clustering 1.2'." - -msgid "The support to python 3.5 has been verified and gated." -msgstr "The support to python 3.5 has been verified and gated." - -msgid "Train Series Release Notes" -msgstr "Train Series Release Notes" - -msgid "Upgrade Notes" -msgstr "Upgrade Notes" - -msgid "Ussuri Series Release Notes" -msgstr "Ussuri Series Release Notes" - -msgid "Victoria Series Release Notes" -msgstr "Victoria Series Release Notes" - -msgid "Wallaby Series Release Notes" -msgstr "Wallaby Series Release Notes" - -msgid "Xena Series Release Notes" -msgstr "Xena Series Release Notes" - -msgid "Yoga Series Release Notes" -msgstr "Yoga Series Release Notes" - -msgid "Zed Series Release Notes" -msgstr "Zed Series Release Notes" - -msgid "" -"[`bug 1814171 `_] Fixed a " -"bug so that cluster delete and node delete return action id associated with " -"the delete action." -msgstr "" -"[`bug 1814171 `_] Fixed a " -"bug so that cluster delete and node delete return action id associated with " -"the delete action." diff --git a/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po deleted file mode 100644 index c67ba728..00000000 --- a/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,42 +0,0 @@ -# Gérald LONLAS , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: python-senlinclient\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-03-07 08:03+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-10-22 06:14+0000\n" -"Last-Translator: Gérald LONLAS \n" -"Language-Team: French\n" -"Language: fr\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" - -msgid "0.5.0" -msgstr "0.5.0" - -msgid "1.0.0" -msgstr "1.0.0" - -msgid "Bug Fixes" -msgstr "Corrections de bugs" - -msgid "Current Series Release Notes" -msgstr "Note de la release actuelle" - -msgid "New Features" -msgstr "Nouvelles fonctionnalités" - -msgid "Newton Series Release Notes" -msgstr "Note de release pour Newton" - -msgid "Other Notes" -msgstr "Autres notes" - -msgid "Senlin Client Release Notes" -msgstr "Note de release du Client Senlin" - -msgid "Upgrade Notes" -msgstr "Notes de mises à jours" diff --git a/releasenotes/source/locale/zh_CN/LC_MESSAGES/releasenotes.po b/releasenotes/source/locale/zh_CN/LC_MESSAGES/releasenotes.po deleted file mode 100644 index a46888b4..00000000 --- a/releasenotes/source/locale/zh_CN/LC_MESSAGES/releasenotes.po +++ /dev/null @@ -1,40 +0,0 @@ -# zzxwill , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: python-senlinclient\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-03-07 08:03+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-25 02:41+0000\n" -"Last-Translator: zzxwill \n" -"Language-Team: Chinese (China)\n" -"Language: zh_CN\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=1; plural=0\n" - -msgid "0.5.0" -msgstr "0.5.0" - -msgid "Added command for node-check and node-recover." -msgstr "已为node-check和node-recover添加了命令。" - -msgid "Current Series Release Notes" -msgstr "当前版本发布说明" - -msgid "New Features" -msgstr "新特性" - -msgid "" -"OSC commands for cluster scaling are changed from 'cluster scale in' and " -"'cluster scale out' to 'cluster shrink' and 'cluster expand' respectively." -msgstr "" -"集群扩展的OSC命令分别从'cluster scale in'和'cluster scale out'改成了'cluster " -"shrink'和'cluster expand'。" - -msgid "Senlin Client Release Notes" -msgstr "Senlin Client发布说明" - -msgid "Upgrade Notes" -msgstr "升级说明" diff --git a/releasenotes/source/newton.rst b/releasenotes/source/newton.rst deleted file mode 100644 index 97036ed2..00000000 --- a/releasenotes/source/newton.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Newton Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/newton diff --git a/releasenotes/source/ocata.rst b/releasenotes/source/ocata.rst deleted file mode 100644 index ebe62f42..00000000 --- a/releasenotes/source/ocata.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Ocata Series Release Notes -=================================== - -.. release-notes:: - :branch: origin/stable/ocata diff --git a/releasenotes/source/pike.rst b/releasenotes/source/pike.rst deleted file mode 100644 index e43bfc0c..00000000 --- a/releasenotes/source/pike.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Pike Series Release Notes -=================================== - -.. release-notes:: - :branch: stable/pike diff --git a/releasenotes/source/queens.rst b/releasenotes/source/queens.rst deleted file mode 100644 index 36ac6160..00000000 --- a/releasenotes/source/queens.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Queens Series Release Notes -=================================== - -.. release-notes:: - :branch: stable/queens diff --git a/releasenotes/source/rocky.rst b/releasenotes/source/rocky.rst deleted file mode 100644 index 40dd517b..00000000 --- a/releasenotes/source/rocky.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Rocky Series Release Notes -=================================== - -.. release-notes:: - :branch: stable/rocky diff --git a/releasenotes/source/stein.rst b/releasenotes/source/stein.rst deleted file mode 100644 index efaceb66..00000000 --- a/releasenotes/source/stein.rst +++ /dev/null @@ -1,6 +0,0 @@ -=================================== - Stein Series Release Notes -=================================== - -.. release-notes:: - :branch: stable/stein diff --git a/releasenotes/source/train.rst b/releasenotes/source/train.rst deleted file mode 100644 index 58390039..00000000 --- a/releasenotes/source/train.rst +++ /dev/null @@ -1,6 +0,0 @@ -========================== -Train Series Release Notes -========================== - -.. release-notes:: - :branch: stable/train diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index cd22aabc..00000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================== - Current Series Release Notes -============================== - -.. release-notes:: diff --git a/releasenotes/source/ussuri.rst b/releasenotes/source/ussuri.rst deleted file mode 100644 index e21e50e0..00000000 --- a/releasenotes/source/ussuri.rst +++ /dev/null @@ -1,6 +0,0 @@ -=========================== -Ussuri Series Release Notes -=========================== - -.. release-notes:: - :branch: stable/ussuri diff --git a/releasenotes/source/victoria.rst b/releasenotes/source/victoria.rst deleted file mode 100644 index 4efc7b6f..00000000 --- a/releasenotes/source/victoria.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================= -Victoria Series Release Notes -============================= - -.. release-notes:: - :branch: stable/victoria diff --git a/releasenotes/source/wallaby.rst b/releasenotes/source/wallaby.rst deleted file mode 100644 index d77b5659..00000000 --- a/releasenotes/source/wallaby.rst +++ /dev/null @@ -1,6 +0,0 @@ -============================ -Wallaby Series Release Notes -============================ - -.. release-notes:: - :branch: stable/wallaby diff --git a/releasenotes/source/xena.rst b/releasenotes/source/xena.rst deleted file mode 100644 index 1be85be3..00000000 --- a/releasenotes/source/xena.rst +++ /dev/null @@ -1,6 +0,0 @@ -========================= -Xena Series Release Notes -========================= - -.. release-notes:: - :branch: stable/xena diff --git a/releasenotes/source/yoga.rst b/releasenotes/source/yoga.rst deleted file mode 100644 index 43cafdea..00000000 --- a/releasenotes/source/yoga.rst +++ /dev/null @@ -1,6 +0,0 @@ -========================= -Yoga Series Release Notes -========================= - -.. release-notes:: - :branch: unmaintained/yoga diff --git a/releasenotes/source/zed.rst b/releasenotes/source/zed.rst deleted file mode 100644 index 9608c05e..00000000 --- a/releasenotes/source/zed.rst +++ /dev/null @@ -1,6 +0,0 @@ -======================== -Zed Series Release Notes -======================== - -.. release-notes:: - :branch: stable/zed diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 3c515412..00000000 --- a/requirements.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Requirements lower bounds listed here are our best effort to keep them up to -# date but we do not test them so no guarantee of having them all correct. If -# you find any incorrect lower bounds, let us know or propose a fix. - -# 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!=2.1.0,>=2.0.0 # Apache-2.0 -PrettyTable>=0.7.2 # BSD -keystoneauth1>=3.11.0 # Apache-2.0 -openstacksdk>=0.24.0 # Apache-2.0 -osc-lib>=1.11.0 # Apache-2.0 -oslo.i18n>=3.15.3 # Apache-2.0 -oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 -oslo.utils>=3.33.0 # Apache-2.0 -python-heatclient>=1.10.0 # Apache-2.0 -PyYAML>=5.3.1 # MIT -requests>=2.14.2 # Apache-2.0 diff --git a/senlinclient/__init__.py b/senlinclient/__init__.py deleted file mode 100644 index bcb55a03..00000000 --- a/senlinclient/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import pbr.version - - -__version__ = pbr.version.VersionInfo('python-senlinclient').version_string() diff --git a/senlinclient/client.py b/senlinclient/client.py deleted file mode 100644 index 3d9c751f..00000000 --- a/senlinclient/client.py +++ /dev/null @@ -1,23 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.common import utils - - -def Client(api_ver, *args, **kwargs): - """Import versioned client module. - - :param api_ver: API version required. - """ - module = utils.import_versioned_module(api_ver, 'client') - cls = getattr(module, 'Client') - return cls(*args, **kwargs) diff --git a/senlinclient/common/__init__.py b/senlinclient/common/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/senlinclient/common/exc.py b/senlinclient/common/exc.py deleted file mode 100644 index 4053594b..00000000 --- a/senlinclient/common/exc.py +++ /dev/null @@ -1,312 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from keystoneauth1.exceptions import base as kae_base -from keystoneauth1.exceptions import http as kae_http -from openstack import exceptions as sdkexc -from oslo_serialization import jsonutils -from requests import exceptions as reqexc - -from senlinclient.common.i18n import _ - -verbose = False - - -class BaseException(Exception): - """An error occurred.""" - def __init__(self, message=None): - self.message = message - - def __str__(self): - return self.message or self.__class__.__doc__ - - -class CommandError(BaseException): - """Invalid usage of CLI.""" - - -class FileFormatError(BaseException): - """Illegal file format detected.""" - - -class PollingExceededError(BaseException): - """Desired resource state not achived within polling period.""" - - -class HTTPException(BaseException): - """Base exception for all HTTP-derived exceptions.""" - code = 'N/A' - - def __init__(self, error=None): - super(HTTPException, self).__init__(error) - try: - self.error = error - if 'error' not in self.error: - raise KeyError(_('Key "error" not exists')) - except KeyError: - # If key 'error' does not exist, self.message becomes - # no sense. In this case, we return doc of current - # exception class instead. - self.error = {'error': {'message': self.__class__.__doc__}} - except Exception: - self.error = {'error': - {'message': self.message or self.__class__.__doc__}} - - def __str__(self): - message = self.error['error'].get('message', 'Internal Error') - if verbose: - traceback = self.error['error'].get('traceback', '') - return (_('ERROR: %(message)s\n%(traceback)s') % - {'message': message, 'traceback': traceback}) - else: - code = self.error['error'].get('code', 'Unknown') - return _('ERROR(%(code)s): %(message)s') % {'code': code, - 'message': message} - - -class ClientError(HTTPException): - pass - - -class ServerError(HTTPException): - pass - - -class HTTPBadRequest(ClientError): - # 400 - pass - - -class HTTPUnauthorized(ClientError): - # 401 - pass - - -class HTTPForbidden(ClientError): - # 403 - pass - - -class HTTPNotFound(ClientError): - # 404 - pass - - -class HTTPMethodNotAllowed(ClientError): - # 405 - pass - - -class HTTPNotAcceptable(ClientError): - # 406 - pass - - -class HTTPProxyAuthenticationRequired(ClientError): - # 407 - pass - - -class HTTPRequestTimeout(ClientError): - # 408 - pass - - -class HTTPConflict(ClientError): - # 409 - pass - - -class HTTPGone(ClientError): - # 410 - pass - - -class HTTPLengthRequired(ClientError): - # 411 - pass - - -class HTTPPreconditionFailed(ClientError): - # 412 - pass - - -class HTTPRequestEntityTooLarge(ClientError): - # 413 - pass - - -class HTTPRequestURITooLong(ClientError): - # 414 - pass - - -class HTTPUnsupportedMediaType(ClientError): - # 415 - pass - - -class HTTPRequestRangeNotSatisfiable(ClientError): - # 416 - pass - - -class HTTPExpectationFailed(ClientError): - # 417 - pass - - -class HTTPInternalServerError(ServerError): - # 500 - pass - - -class HTTPNotImplemented(ServerError): - # 501 - pass - - -class HTTPBadGateway(ServerError): - # 502 - pass - - -class HTTPServiceUnavailable(ServerError): - # 503 - pass - - -class HTTPGatewayTimeout(ServerError): - # 504 - pass - - -class HTTPVersionNotSupported(ServerError): - # 505 - pass - - -class ConnectionRefused(HTTPException): - # 111 - pass - - -_EXCEPTION_MAP = { - 111: ConnectionRefused, - 400: HTTPBadRequest, - 401: HTTPUnauthorized, - 403: HTTPForbidden, - 404: HTTPNotFound, - 405: HTTPMethodNotAllowed, - 406: HTTPNotAcceptable, - 407: HTTPProxyAuthenticationRequired, - 408: HTTPRequestTimeout, - 409: HTTPConflict, - 410: HTTPGone, - 411: HTTPLengthRequired, - 412: HTTPPreconditionFailed, - 413: HTTPRequestEntityTooLarge, - 414: HTTPRequestURITooLong, - 415: HTTPUnsupportedMediaType, - 416: HTTPRequestRangeNotSatisfiable, - 417: HTTPExpectationFailed, - 500: HTTPInternalServerError, - 501: HTTPNotImplemented, - 502: HTTPBadGateway, - 503: HTTPServiceUnavailable, - 504: HTTPGatewayTimeout, - 505: HTTPVersionNotSupported, -} - - -def parse_exception(exc): - """Parse exception code and yield useful information. - - :param exc: details of the exception. - """ - if isinstance(exc, sdkexc.HttpException): - if exc.details is None: - data = exc.response.json() - code = data.get('code', None) - message = data.get('message', None) - error = data.get('error', None) - if error: - record = { - 'error': { - 'code': exc.http_status, - 'message': message or exc.message - } - } - else: - info = data.values()[0] - record = { - 'error': { - 'code': info.get('code', code), - 'message': info.get('message', message) - } - } - else: - try: - record = jsonutils.loads(exc.details) - except Exception: - # If the exc.details is not in JSON format - record = { - 'error': { - 'code': exc.http_status, - 'message': exc, - } - } - elif isinstance(exc, reqexc.RequestException): - # Exceptions that are not captured by SDK - record = { - 'error': { - 'code': exc.message[1].errno, - 'message': exc.message[0], - } - } - - elif isinstance(exc, str): - record = jsonutils.loads(exc) - # some exception from keystoneauth1 is not shaped by SDK - elif isinstance(exc, kae_http.HttpError): - record = { - 'error': { - 'code': exc.http_status, - 'message': exc.message - } - } - elif isinstance(exc, kae_base.ClientException): - record = { - 'error': { - # other exceptions from keystoneauth1 is an internal - # error to senlin, so set status code to 500 - 'code': 500, - 'message': exc.message - } - } - else: - print(_('Unknown exception: %s') % exc) - return - - try: - code = record['error']['code'] - except KeyError as err: - print(_('Malformed exception record, missing field "%s"') % err) - print(_('Original error record: %s') % record) - return - - if code in _EXCEPTION_MAP: - inst = _EXCEPTION_MAP.get(code) - raise inst(record) - else: - raise HTTPException(record) diff --git a/senlinclient/common/format_utils.py b/senlinclient/common/format_utils.py deleted file mode 100644 index f7973bc0..00000000 --- a/senlinclient/common/format_utils.py +++ /dev/null @@ -1,51 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from osc_lib.command import command - - -class RawFormat(command.ShowOne): - - def produce_output(self, parsed_args, column_names, data): - if data is None: - return - - self.formatter.emit_one(column_names, data, - self.app.stdout, parsed_args) - - -class JsonFormat(RawFormat): - - @property - def formatter_default(self): - return 'json' - - -class YamlFormat(RawFormat): - - @property - def formatter_default(self): - return 'yaml' - - -class ShellFormat(RawFormat): - - @property - def formatter_default(self): - return 'shell' - - -class ValueFormat(RawFormat): - - @property - def formatter_default(self): - return 'value' diff --git a/senlinclient/common/i18n.py b/senlinclient/common/i18n.py deleted file mode 100644 index 3b50a8fc..00000000 --- a/senlinclient/common/i18n.py +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -oslo_i18n integration module. -See https://docs.openstack.org/oslo.i18n/latest/user/usage.html -""" - -import oslo_i18n - - -_translators = oslo_i18n.TranslatorFactory(domain='senlinclient') - -# The primary translation function using the well-known name "_" -_ = _translators.primary diff --git a/senlinclient/common/utils.py b/senlinclient/common/utils.py deleted file mode 100644 index e0eb346c..00000000 --- a/senlinclient/common/utils.py +++ /dev/null @@ -1,236 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from heatclient.common import template_utils -import logging -from openstack import exceptions as sdk_exc -from oslo_serialization import jsonutils -from oslo_utils import importutils -import prettytable -import time -import yaml - -from senlinclient.common import exc -from senlinclient.common.i18n import _ - - -log = logging.getLogger(__name__) - - -def import_versioned_module(version, submodule=None): - module = 'senlinclient.v%s' % version - if submodule: - module = '.'.join((module, submodule)) - return importutils.import_module(module) - - -def format_nested_dict(d, fields, column_names): - if d is None: - return '' - pt = prettytable.PrettyTable(caching=False, print_empty=False, - header=True, field_names=column_names) - for n in column_names: - pt.align[n] = 'l' - - keys = sorted(d.keys()) - for field in keys: - value = d[field] - if not isinstance(value, str): - value = jsonutils.dumps(value, indent=2, ensure_ascii=False) - if value is None: - value = '-' - pt.add_row([field, value.strip('"')]) - - return pt.get_string() - - -def nested_dict_formatter(d, column_names): - return lambda o: format_nested_dict(o, d, column_names) - - -def json_formatter(js): - return jsonutils.dumps(js, indent=2, ensure_ascii=False) - - -def list_formatter(record): - return '\n'.join(record or []) - - -def print_action_result(rid, res): - if res[0] == "OK": - output = _("accepted by action %s") % res[1] - else: - output = _("failed due to '%s'") % res[1] - print(_(" %(cid)s: %(output)s") % {"cid": rid, "output": output}) - - -def format_parameters(params, parse_semicolon=True): - """Reformat parameters into dict of format expected by the API.""" - if not params or params == ['{}']: - return {} - - if parse_semicolon: - # expect multiple invocations of --parameters but fall back to ';' - # delimited if only one --parameters is specified - if len(params) == 1: - params = params[0].split(';') - - parameters = {} - for p in params: - try: - (n, v) = p.split(('='), 1) - except ValueError: - msg = _('Malformed parameter(%s). Use the key=value format.') % p - raise exc.CommandError(msg) - - if n not in parameters: - parameters[n] = v - else: - if not isinstance(parameters[n], list): - parameters[n] = [parameters[n]] - parameters[n].append(v) - - return parameters - - -def format_json_parameter(param): - '''Return JSON dict from JSON formatted param. - - :parameter param JSON formatted string - :return JSON dict - ''' - if not param: - return {} - - try: - return jsonutils.loads(param) - except ValueError: - msg = _('Malformed parameter(%s). Use the JSON format.') % param - raise exc.CommandError(msg) - - -def get_spec_content(filename): - with open(filename, 'r') as f: - try: - data = yaml.safe_load(f) - except Exception as ex: - raise exc.CommandError(_('The specified file is not a valid ' - 'YAML file: %s') % str(ex)) - return data - - -def process_stack_spec(spec): - # Heat stack is a headache, because it demands for client side file - # content processing - try: - tmplfile = spec.get('template', None) - except AttributeError as ex: - raise exc.FileFormatError(_('The specified file is not a valid ' - 'YAML file: %s') % str(ex)) - if not tmplfile: - raise exc.FileFormatError(_('No template found in the given ' - 'spec file')) - - tpl_files, template = template_utils.get_template_contents( - template_file=tmplfile) - - env_files, env = template_utils.process_multiple_environments_and_files( - env_paths=spec.get('environment', None)) - - new_spec = { - # TODO(Qiming): add context support - 'disable_rollback': spec.get('disable_rollback', True), - 'context': spec.get('context', {}), - 'parameters': spec.get('parameters', {}), - 'timeout': spec.get('timeout', 60), - 'template': template, - 'files': dict(list(tpl_files.items()) + list(env_files.items())), - 'environment': env - } - - return new_spec - - -def await_action(senlin_client, action_id, - poll_count_max=10, poll_interval=5): - - def check_action(): - try: - action = senlin_client.get_action(action_id) - except sdk_exc.ResourceNotFound: - raise exc.CommandError(_('Action not found: %s') - % action_id) - action_states = ['succeeded', 'failed', 'cancelled'] - if action.status.lower() in action_states: - log.info("Action %s completed with status %s." - % (action.id, action.status)) - return True - log.info("Awaiting action %s completion status (current: %s)." - % (action.id, action.status)) - return False - - _check(check_action, poll_count_max, poll_interval) - - -def await_cluster_status(senlin_client, cluster_id, statuses=None, - poll_count_max=10, poll_interval=5): - - if not statuses or len(statuses) <= 0: - statuses = ['ACTIVE', 'ERROR', 'WARNING'] - - def check_status(): - try: - cluster = senlin_client.get_cluster(cluster_id) - except sdk_exc.ResourceNotFound: - raise exc.CommandError(_('Cluster not found: %s') % cluster_id) - - if cluster.status.lower() in [fs.lower() for fs in statuses]: - return True - log.info("Awaiting cluster status (desired: %s - current: %s)." % - (', '.join(statuses), cluster.status)) - return False - - _check(check_status, poll_count_max, poll_interval) - - -def await_cluster_delete(senlin_client, cluster_id, - poll_count_max=10, poll_interval=5): - - def check_deleted(): - try: - senlin_client.get_cluster(cluster_id) - except sdk_exc.ResourceNotFound: - log.info("Successfully deleted cluster %s." % cluster_id) - return True - log.info("Awaiting cluster deletion for %s." % cluster_id) - return False - - _check(check_deleted, poll_count_max, poll_interval) - - -def _check(check_func, poll_count_max=10, poll_interval=5): - # a negative poll_count_max is considered indefinite - - poll_increment = 1 - if poll_count_max < 0: - poll_count_max = 1 - poll_increment = 0 - - poll_count = 0 - while poll_count < poll_count_max: - if check_func(): - return - - time.sleep(poll_interval) - poll_count += poll_increment - raise exc.PollingExceededError() diff --git a/senlinclient/locale/zh_CN/LC_MESSAGES/senlinclient.po b/senlinclient/locale/zh_CN/LC_MESSAGES/senlinclient.po deleted file mode 100644 index e7124e04..00000000 --- a/senlinclient/locale/zh_CN/LC_MESSAGES/senlinclient.po +++ /dev/null @@ -1,535 +0,0 @@ -# zzxwill , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: python-senlinclient VERSION\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2018-02-28 14:44+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-08-20 01:56+0000\n" -"Last-Translator: zzxwill \n" -"Language-Team: Chinese (China)\n" -"Language: zh_CN\n" -"X-Generator: Zanata 4.3.3\n" -"Plural-Forms: nplurals=1; plural=0\n" - -msgid "" -"A dictionary of parameters that will be passed to target action when the " -"receiver is triggered" -msgstr "字典类型的参数在receiver被触发时将传递给目标动作" - -msgid "" -"A positive integer meaning the number of nodes to add, or a negative integer " -"indicating the number of nodes to remove" -msgstr "正整数意味着要添加的节点个数,或者一个负整数,表明要删除的节点个数" - -msgid "" -"A value that is interpreted as the percentage of size adjustment. This value " -"can be positive or negative" -msgstr "一个值被解释为大小调整的百分比,这个值可以是正数,也可以是负数" - -#, python-format -msgid "Action not found: %s" -msgstr "Action没找到:%s" - -msgid "Adjustment cannot be zero." -msgstr "调整值不能为0。" - -msgid "" -"An integer specifying the number of nodes for adjustment when " -"is specified" -msgstr "当指定时,整数值表明节点调整的数目" - -msgid "Are you sure you want to delete this cluster(s) [y/N]?" -msgstr "你确认你想删除这个集群吗[y/N]?" - -msgid "Are you sure you want to delete this node(s) [y/N]?" -msgstr "你确认你想删除这个节点吗[y/N]?" - -msgid "Are you sure you want to delete this policy(s) [y/N]?" -msgstr "你确认你想删除这个策略吗[y/N]?" - -msgid "Are you sure you want to delete this profile(s) [y/N]?" -msgstr "你确认你想删除这个样版吗[y/N]?" - -msgid "Are you sure you want to delete this receiver(s) [y/N]?" -msgstr "你确认你想删除这个receiver吗[y/N]?" - -msgid "Cluster Id or Name for this node" -msgstr "该节点的集群Id或名称" - -msgid "Cluster capacity must be larger than or equal to zero." -msgstr "集群的容量必须大于或等于0。" - -msgid "Cluster creation timeout in seconds" -msgstr "集群创建超时时限(秒)" - -#, python-format -msgid "Cluster not found: %s" -msgstr "集群没找到:%s" - -msgid "" -"Desired capacity of the cluster. Default to min_size if min_size is " -"specified else 0." -msgstr "集群期望的容量,如果min_size给定了,默认是min_size,否则是0。" - -#, python-format -msgid "ERROR(%(code)s): %(message)s" -msgstr "错误(%(code)s): %(message)s" - -#, python-format -msgid "" -"ERROR: %(message)s\n" -"%(traceback)s" -msgstr "" -"错误: %(message)s\n" -"%(traceback)s" - -#, python-format -msgid "Event not found: %s" -msgstr "事件没有找到:%s" - -#, python-format -msgid "Failed to delete %(count)s of the %(total)s specified policy(s)." -msgstr "删除%(total)s个给定的策略中的%(count)s个失败。" - -#, python-format -msgid "Failed to delete %(count)s of the %(total)s specified profile(s)." -msgstr "删除%(total)s个给定的样版中的%(count)s个失败。" - -#, python-format -msgid "Failed to delete %(count)s of the %(total)s specified receiver(s)." -msgstr "删除%(total)s个给定的receiver中的%(count)s个失败。" - -msgid "" -"Filter parameters to apply on returned clusters. This can be specified " -"multiple times, or once with parameters separated by a semicolon. The valid " -"filter keys are: ['status', 'name']" -msgstr "" -"过滤参数以应用在返回的集群上。该操作可以指定多次,或者用分号分隔参数之后指定" -"一次。有效的过滤键是['status', 'name']" - -msgid "" -"Filter parameters to apply on returned nodes. This can be specified multiple " -"times, or once with parameters separated by a semicolon. The valid filter " -"keys are: ['status','name']" -msgstr "" -"过滤参数以应用在返回的节点上。该参数可以指定多次,也可以用分号分隔参数之后执" -"行一次。有效的过滤键是['status','name']" - -msgid "" -"Filter parameters to apply on returned policies. This can be specified " -"multiple times, or once with parameters separated by a semicolon. The valid " -"filter keys are: ['type', 'name']" -msgstr "" -"过滤参数以应用在返回的策略上。该参数可以指定多次,也可以用分号分隔参数之后执" -"行一次。有效的过滤键是['type', 'name']" - -msgid "ID of event to display details for" -msgstr "显示事件详情的ID" - -msgid "ID or name of cluster from which nodes are to be listed" -msgstr "集群的ID或名字,该集群中的节点都将被列出来" - -msgid "ID or name of cluster(s) to operate on." -msgstr "将要操作的集群的ID或名字。" - -msgid "ID or name of new profile to use" -msgstr "将要使用的新样版的ID或名字" - -msgid "ID or name of node(s) to check." -msgstr "将要检查的节点的ID或名字。" - -msgid "ID or name of node(s) to recover." -msgstr "将要恢复的节点的ID或名字。" - -msgid "" -"ID or name of nodes to be added; multiple nodes can be separated with \",\"" -msgstr "待添加节点的ID或名称;多个节点可以用“,”分隔" - -msgid "ID or name of policy to be attached" -msgstr "将要关联的策略的ID或名字" - -msgid "ID or name of policy to be detached" -msgstr "将要解除关联的策略的ID或名字" - -msgid "ID or name of policy to be updated" -msgstr "将被更新的策略的ID或名字" - -msgid "ID or name of the cluster to query on" -msgstr "将要查询的集群的ID或名字" - -msgid "ID or name of the policy to query on" -msgstr "将要查询的策略的ID或名字" - -msgid "Include physical object details" -msgstr "包含物理对象的详情" - -msgid "" -"Indicate that the cluster list should include clusters from all projects. " -"This option is subject to access policy checking. Default is False" -msgstr "" -"这表明集群列表应该包含所有项目的集群。该选项从属于访问策略检查,默认是False" - -msgid "" -"Indicate that the list should include policies from all projects. This " -"option is subject to access policy checking. Default is False" -msgstr "" -"这表明列表应该包含所有项目的策略。该选项从属于访问策略检查,默认是False" - -msgid "" -"Indicate that the list should include profiles from all projects. This " -"option is subject to access policy checking. Default is False" -msgstr "" -"这表明列表应该包含所有项目的样版。该选项从属于访问策略检查,默认是False" - -msgid "" -"Indicate that the list should include receivers from all projects. This " -"option is subject to access policy checking. Default is False" -msgstr "" -"这表明列表应该包含所有项目的receiver。该选项从属于访问策略检查,默认是False" - -msgid "" -"Indicate that this node list should include nodes from all projects. This " -"option is subject to access policy checking. Default is False" -msgstr "" -"这表明节点列表应该包含所有项目的节点。该选项从属于访问策略检查,默认是False" - -msgid "Key \"error\" not exists" -msgstr "键\"error\"不存在" - -msgid "Limit the number of actions returned" -msgstr "限定action返回的个数" - -msgid "Limit the number of clusters returned" -msgstr "限定集群返回的个数" - -msgid "Limit the number of events returned" -msgstr "限定事件返回的个数" - -msgid "Limit the number of nodes returned" -msgstr "限定节点返回的个数" - -msgid "Limit the number of policies returned" -msgstr "限定策略返回的个数" - -msgid "Limit the number of profiles returned" -msgstr "限定样版返回的个数" - -msgid "Limit the number of receivers returned" -msgstr "限定receiver返回的个数" - -#, python-format -msgid "Malformed exception record, missing field \"%s\"" -msgstr "异常记录的格式不正确,缺少字段\"%s\"" - -#, python-format -msgid "Malformed parameter(%s). Use the key=value format." -msgstr "参数(%s)格式不正确,使用key=value格式。" - -msgid "Malformed parameter(status:ACTIVE). Use the key=value format." -msgstr "参数(status:ACTIVE)格式不正确,使用key=value格式。" - -msgid "Max size cannot be less than the specified capacity." -msgstr "最大值不能小于给定的容量。" - -msgid "Max size of the cluster. Default to -1, means unlimited" -msgstr "集群容量上限。默认为-1,表示无限制" - -msgid "" -"Metadata values to be attached to the cluster. This can be specified " -"multiple times, or once with key-value pairs separated by a semicolon." -msgstr "" -"将要关联到集群的元数据。该元数据可以指定多次,也可以用分号分割键值对之后指定" -"一次。" - -msgid "" -"Metadata values to be attached to the node. This can be specified multiple " -"times, or once with key-value pairs separated by a semicolon" -msgstr "" -"将要关联到节点的元数据。该元数据可以指定多次,也可以用分号分隔键值对之后指定" -"一次" - -msgid "" -"Metadata values to be attached to the node. This can be specified multiple " -"times, or once with key-value pairs separated by a semicolon." -msgstr "" -"将要关联到节点的元数据。该元数据可以指定多次,也可以用分号分隔键值对之后指定" -"一次。" - -msgid "" -"Metadata values to be attached to the profile. This can be specified " -"multiple times, or once with key-value pairs separated by a semicolon" -msgstr "" -"将要关联到样版的元数据。该元数据可以指定多次,也可以用分号分隔键值对之后指定" -"一次" - -msgid "Min size cannot be larger than max size." -msgstr "最小值不能大于最大值。" - -msgid "Min size cannot be larger than the specified capacity" -msgstr "最小值不能大于给定的容量" - -msgid "Min size cannot be less than zero." -msgstr "最小值不能小于0。" - -msgid "Min size of the cluster. Default to 0" -msgstr "集群容量下限。默认为0" - -#, fuzzy -msgid "Min step is only used with percentage." -msgstr "最小步骤只能使用百分数。" - -msgid "Missing 'properties' key in spec file." -msgstr "规格文件里缺少键'properties'。" - -msgid "Missing 'type' key in spec file." -msgstr "规格文件里缺少键'type'。" - -msgid "Missing 'version' key in spec file." -msgstr "规格文件里缺少键'version'。" - -msgid "Name of the cluster to create" -msgstr "要创建的集群的名称" - -msgid "Name of the node to create" -msgstr "要创建的节点的名称" - -msgid "Name of the policy to create" -msgstr "要创建的策略的名称" - -msgid "Name of the profile to create" -msgstr "要创建的样版的名称" - -msgid "Name of the receiver to create" -msgstr "要创建的receiver的名称" - -msgid "Name or ID of cluster to be updated" -msgstr "将要更新的集群的名称或ID" - -msgid "Name or ID of cluster to nodes from" -msgstr "该集群的节点的名字或ID" - -msgid "Name or ID of cluster to operate on" -msgstr "将要操作的集群的名字或ID" - -msgid "Name or ID of cluster to query on" -msgstr "将要查询的集群的名字或ID" - -msgid "Name or ID of cluster to show" -msgstr "将要显示的集群的名字或ID" - -msgid "Name or ID of cluster(s) to delete." -msgstr "将要删除的集群的名称或ID。" - -msgid "Name or ID of node to update" -msgstr "将要更新的节点的名字或ID" - -msgid "Name or ID of node(s) to delete." -msgstr "待删除的节点的名称或ID。" - -msgid "" -"Name or ID of nodes to be deleted; multiple nodes can be separated with \",\"" -msgstr "待删除的节点的名称或ID;多个节点可以用“,”分隔" - -msgid "Name or ID of policy(s) to delete" -msgstr "将要删除的策略的名称或ID" - -msgid "Name or ID of profile(s) to delete" -msgstr "将要删除的样版的名称或ID" - -msgid "Name or ID of receiver(s) to delete" -msgstr "要删除的receiver的名称或ID" - -msgid "Name or ID of the action to show the details for" -msgstr "显示action详情的名字或ID" - -msgid "Name or ID of the node to show the details for" -msgstr "显示节点详情的名字或ID。" - -msgid "Name or ID of the policy to be updated" -msgstr "将要更新的策略的名称或ID" - -msgid "Name or ID of the profile to update" -msgstr "将要更新的样版的名字或ID" - -msgid "Name or ID of the receiver to show" -msgstr "待显示的receiver的名字或ID" - -msgid "Name or Id of the policy to show" -msgstr "将要显示的策略的名字或ID" - -msgid "New lower bound of cluster size" -msgstr "集群大小的新下限值" - -msgid "New name for the cluster to update" -msgstr "将要更新的集群的新名称" - -msgid "New name for the node" -msgstr "节点的新名称" - -msgid "New name of the policy to be updated" -msgstr "将被更新的策略的新名字" - -msgid "New timeout (in seconds) value for the cluster" -msgstr "集群新的超时时间(秒)" - -msgid "" -"New upper bound of cluster size. A value of -1 indicates no upper limit on " -"cluster size" -msgstr "集群容量的上限值。默认为-1,表示集群大小无限制" - -msgid "No template found in the given spec file" -msgstr "给定的样版文件里找不到模板" - -#, python-format -msgid "Node not found: %s" -msgstr "节点没有找到:%s" - -msgid "Number of nodes to be added to the specified cluster" -msgstr "将要加入该集群中的节点的个数" - -msgid "Number of nodes to be deleted from the specified cluster" -msgstr "将要从该集群中删除的节点的个数" - -msgid "Only one of 'capacity', 'adjustment' and 'percentage' can be specified." -msgstr "只能指定'capacity', 'adjustment'和'percentage'中的一个值。" - -msgid "Only return clusters that appear after the given cluster ID" -msgstr "仅仅返回给定集群ID后出现的集群" - -msgid "Only return events that appear after the given event ID" -msgstr "仅仅返回给定事件ID后出现的事件" - -msgid "Only return nodes that appear after the given node ID" -msgstr "仅仅返回给定节点ID后出现的节点" - -#, python-format -msgid "Original error record: %s" -msgstr "初始错误记录:%s" - -msgid "Percentage cannot be zero." -msgstr "百分数不能为0。" - -#, python-format -msgid "Policy Type not found: %s" -msgstr "策略类型没找到:%s" - -#, python-format -msgid "Policy not found: %s" -msgstr "策略没找到:%s" - -msgid "Policy type to retrieve" -msgstr "将要获取的策略类型" - -msgid "Print full IDs in list" -msgstr "将全部ID打印到列表里" - -msgid "Profile Id or Name used for this node" -msgstr "用于该节点的样板的Id或名称" - -#, python-format -msgid "Profile Type not found: %s" -msgstr "找不到样版类型:%s" - -#, python-format -msgid "Profile not found: %s" -msgstr "找不到样版:%s" - -msgid "Profile type to retrieve" -msgstr "将要获取的样版类型" - -#, python-format -msgid "Receiver not found: %s" -msgstr "Receiver没找到:%s" - -msgid "Role for this node in the specific cluster" -msgstr "在给定集群里的该节点的角色" - -msgid "Role for this node in the specific cluster." -msgstr "特定集群中的这个节点的角色。" - -msgid "Skip yes/no prompt (assume yes)" -msgstr "跳过yes确认/没有提示(默认是yes)" - -msgid "" -"Sorting option which is a string containing a list of keys separated by " -"commas. Each key can be optionally appended by a sort direction (:asc or :" -"desc). The valid sort keys are: ['name', 'status', 'init_at', 'created_at', " -"'updated_at']" -msgstr "" -"排序选项是一个字符串,该字符串包含了一系列用逗号分隔的键。每个键可以附加上一" -"个排序方向值(:asc或:desc),这个排序方向值是可选的。有效的过滤键是:" -"['name', 'status', 'init_at', 'created_at', 'updated_at']" - -msgid "" -"Sorting option which is a string containing a list of keys separated by " -"commas. Each key can be optionally appended by a sort direction (:asc or :" -"desc). The valid sort keys are: ['name', 'target', 'action', 'created_at', " -"'status']" -msgstr "" -"排序选项是一个字符串,该字符串包含了一系列用逗号分隔的键。每个键可以附加上一" -"个排序方向值(:asc或:desc),这个排序方向值是可选的。有效的过滤键是:" -"['name', 'target', 'action', 'created_at', 'status']" - -msgid "" -"Sorting option which is a string containing a list of keys separated by " -"commas. Each key can be optionally appended by a sort direction (:asc or :" -"desc). The valid sort keys are: ['name', 'type', 'action', 'cluster_id', " -"'created_at']" -msgstr "" -"排序选项是一个字符串,该字符串包含了一系列用逗号分隔的键。每个键可以附加上一" -"个排序方向值(:asc或:desc),这个排序方向值是可选的。有效的过滤键是:" -"['name', 'type', 'action', 'cluster_id', 'created_at']" - -msgid "" -"Sorting option which is a string containing a list of keys separated by " -"commas. Each key can be optionally appended by a sort direction (:asc or :" -"desc). The valid sort keys are: ['type', 'name', 'created_at', 'updated_at']" -msgstr "" -"排序选项是一个字符串,该字符串包含了一系列用逗号分隔的键。每个键可以附加上一" -"个排序方向值(:asc或:desc),这个排序方向值是可选的。有效的过滤键是:" -"['type', 'name', 'created_at', 'updated_at']" - -msgid "" -"Sorting option which is a string containing a list of keys separated by " -"commas. Each key can be optionally appended by a sort direction (:asc or :" -"desc). The valid sort_keys are:['type', 'name', 'created_at', 'updated_at']" -msgstr "" -"排序选项是一个字符串,该字符串包含了一系列用逗号分隔的键。每个键可以附加上一" -"个排序方向值(:asc或:desc),这个排序方向值是可选的。有效的过滤键是['type', " -"'name', 'created_at', 'updated_at']" - -msgid "The desired number of nodes of the cluster" -msgstr "该集群中期望的节点个数" - -msgid "The new name for the profile" -msgstr "该样版的新名字" - -msgid "The spec file used to create the policy" -msgstr "用于创建策略的规格文件" - -msgid "The spec file used to create the profile" -msgstr "用于创建样版的规格文件" - -#, python-format -msgid "The specified file is not a valid YAML file: %s" -msgstr "所提供的文件不是合法的YAML文件:%s" - -#, python-format -msgid "Unknown exception: %s" -msgstr "未知异常:%s" - -msgid "" -"Whether events from all projects should be listed. Default to False. " -"Setting this to True may demand for an admin privilege" -msgstr "" -"是否所有项目的事件都应该列出来,默认是False。设置该属性为True可能需要admin权" -"限" - -msgid "Whether the policy should be enabled" -msgstr "该策略是否会使其生效" - -msgid "Whether the policy should be enabled once attached. Default to True" -msgstr "策略一旦关联是否应该设置为有效,默认是True" diff --git a/senlinclient/plugin.py b/senlinclient/plugin.py deleted file mode 100644 index 6936d1d7..00000000 --- a/senlinclient/plugin.py +++ /dev/null @@ -1,118 +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. - -"""OpenStackClient plugin for Clustering service.""" - -import logging - -from openstack.config import cloud_region -from openstack.config import defaults as config_defaults -from openstack import connection -from osc_lib import utils - -LOG = logging.getLogger(__name__) - -DEFAULT_CLUSTERING_API_VERSION = '1' -API_VERSION_OPTION = 'os_clustering_api_version' -API_NAME = 'clustering' -CURRENT_API_VERSION = '1.14' - - -def _make_key(service_type, key): - if not service_type: - return key - else: - service_type = service_type.lower().replace('-', '_') - return "_".join([service_type, key]) - - -def _get_config_from_profile(profile, **kwargs): - # Deal with clients still trying to use legacy profile objects - region_name = None - for service in profile.get_services(): - if service.region: - region_name = service.region - service_type = service.service_type - if service.interface: - key = _make_key(service_type, 'interface') - kwargs[key] = service.interface - if service.version: - version = service.version - if version.startswith('v'): - version = version[1:] - key = _make_key(service_type, 'api_version') - kwargs[key] = version - if service.api_version: - version = service.api_version - key = _make_key(service_type, 'default_microversion') - kwargs[key] = version - - config_kwargs = config_defaults.get_defaults() - config_kwargs.update(kwargs) - config = cloud_region.CloudRegion( - region_name=region_name, config=config_kwargs) - return config - - -def create_connection(prof=None, cloud_region=None, **kwargs): - version_key = _make_key(API_NAME, 'api_version') - kwargs[version_key] = CURRENT_API_VERSION - - if not cloud_region: - if prof: - cloud_region = _get_config_from_profile(prof, **kwargs) - else: - # If we got the CloudRegion from python-openstackclient and it doesn't - # already have a default microversion set, set it here. - microversion_key = _make_key(API_NAME, 'default_microversion') - cloud_region.config.setdefault(microversion_key, CURRENT_API_VERSION) - - user_agent = kwargs.pop('user_agent', None) - app_name = kwargs.pop('app_name', None) - app_version = kwargs.pop('app_version', None) - if user_agent is not None and (not app_name and not app_version): - app_name, app_version = user_agent.split('/', 1) - - return connection.Connection( - config=cloud_region, - app_name=app_name, - app_version=app_version, **kwargs) - - -def make_client(instance): - """Returns a clustering proxy""" - # TODO(mordred) the ClientManager already has an OpenStackSDK connection, - # but it only has it once setup_auth has been called. For things that - # don't require auth, this is problematic, so we have to make our own. - # Use the CloudRegion stored on the ClientManager for now. - conn = create_connection( - cloud_region=instance._cli_options, - ) - - LOG.debug('Connection: %s', conn) - LOG.debug('Clustering client initialized using OpenStackSDK: %s', - conn.clustering) - return conn.clustering - - -def build_option_parser(parser): - """Hook to add global options""" - parser.add_argument( - '--os-clustering-api-version', - metavar='', - default=utils.env( - 'OS_CLUSTERING_API_VERSION', - default=DEFAULT_CLUSTERING_API_VERSION), - help='Clustering API version, default=' + - DEFAULT_CLUSTERING_API_VERSION + - ' (Env: OS_CLUSTERING_API_VERSION)') - return parser diff --git a/senlinclient/tests/__init__.py b/senlinclient/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/senlinclient/tests/functional/__init__.py b/senlinclient/tests/functional/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/senlinclient/tests/functional/base.py b/senlinclient/tests/functional/base.py deleted file mode 100644 index c3cec988..00000000 --- a/senlinclient/tests/functional/base.py +++ /dev/null @@ -1,176 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import time - -from oslo_utils import uuidutils -from tempest.lib.cli import base -from tempest.lib.cli import output_parser -from tempest.lib import exceptions as tempest_lib_exc - - -class OpenStackClientTestBase(base.ClientTestBase): - """Command line client base functions.""" - - def setUp(self): - super(OpenStackClientTestBase, self).setUp() - self.parser = output_parser - - def _get_clients(self): - cli_dir = os.environ.get( - 'OS_SENLINCLIENT_EXEC_DIR', - os.path.join(os.path.abspath('.'), '.tox/functional/bin')) - - return base.CLIClient( - username=os.environ.get('OS_USERNAME'), - password=os.environ.get('OS_PASSWORD'), - tenant_name=os.environ.get('OS_PROJECT_NAME', - os.environ.get('OS_TENANT_NAME')), - uri=os.environ.get('OS_AUTH_URL'), - cli_dir=cli_dir) - - def openstack(self, *args, **kwargs): - return self.clients.openstack(*args, **kwargs) - - def show_to_dict(self, output): - obj = {} - items = self.parser.listing(output) - for item in items: - obj[item['Field']] = str(item['Value']) - return dict((self._key_name(k), v) for k, v in obj.items()) - - def _key_name(self, key): - return key.lower().replace(' ', '_') - - def name_generate(self): - """Generate randomized name for some entity.""" - name = uuidutils.generate_uuid()[:8] - return name - - def _get_profile_path(self, profile_name): - return os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'profiles/%s' % profile_name) - - def _get_policy_path(self, policy_name): - return os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'policies/%s' % policy_name) - - def wait_for_status(self, name, status, check_type, timeout=60, - poll_interval=5): - """Wait until name reaches given status. - - :param name: node or cluster name - :param status: expected status of node or cluster - :param timeout: timeout in seconds - :param poll_interval: poll interval in seconds - """ - if check_type == 'node': - cmd = ('cluster node show %s' % name) - elif check_type == 'cluster': - cmd = ('cluster show %s' % name) - time.sleep(poll_interval) - start_time = time.time() - while time.time() - start_time < timeout: - check_status = self.openstack(cmd) - result = self.show_to_dict(check_status) - if result['status'] == status: - break - time.sleep(poll_interval) - else: - message = ("%s %s did not reach status %s after %d s" - % (check_type, name, status, timeout)) - raise tempest_lib_exc.TimeoutException(message) - - def wait_for_delete(self, name, check_type, timeout=60, - poll_interval=5): - """Wait until delete finish""" - if check_type == 'node': - cmd = ('cluster node show %s' % name) - if check_type == 'cluster': - cmd = ('cluster show %s' % name) - time.sleep(poll_interval) - start_time = time.time() - while time.time() - start_time < timeout: - try: - self.openstack(cmd) - except tempest_lib_exc.CommandFailed as ex: - if "No Node found" or "No Cluster found" in ex.stderr: - break - time.sleep(poll_interval) - else: - - message = ("failed in deleting %s %s after %d seconds" - % (check_type, name, timeout)) - raise tempest_lib_exc.TimeoutException(message) - - def policy_create(self, name, policy='deletion_policy.yaml'): - pf = self._get_policy_path(policy) - cmd = ('cluster policy create --spec-file %s %s' - % (pf, name)) - policy_raw = self.openstack(cmd) - result = self.show_to_dict(policy_raw) - return result - - def policy_delete(self, name_or_id): - cmd = ('cluster policy delete %s --force' % name_or_id) - self.openstack(cmd) - - def profile_create(self, name, profile='cirros_basic.yaml'): - pf = self._get_profile_path(profile) - cmd = ('cluster profile create --spec-file %s %s' - % (pf, name)) - profile_raw = self.openstack(cmd) - result = self.show_to_dict(profile_raw) - return result - - def profile_delete(self, name_or_id): - cmd = ('cluster profile delete %s --force' % name_or_id) - self.openstack(cmd) - - def node_create(self, profile, name): - cmd = ('cluster node create --profile %s %s' - % (profile, name)) - node_raw = self.openstack(cmd) - result = self.show_to_dict(node_raw) - self.wait_for_status(name, 'ACTIVE', 'node', 120) - return result - - def node_delete(self, name_or_id): - cmd = ('cluster node delete %s --force' % name_or_id) - self.openstack(cmd) - self.wait_for_delete(name_or_id, 'node', 120) - - def cluster_create(self, profile, name, desired_capacity=0): - cmd = ('cluster create --profile %s --desired-capacity %d %s' - % (profile, desired_capacity, name)) - cluster_raw = self.openstack(cmd) - result = self.show_to_dict(cluster_raw) - self.wait_for_status(name, 'ACTIVE', 'cluster', 120) - return result - - def cluster_delete(self, name_or_id): - cmd = ('cluster delete %s --force' % name_or_id) - self.openstack(cmd) - self.wait_for_delete(name_or_id, 'cluster', 120) - - def receiver_create(self, name, cluster, action='CLUSTER_SCALE_OUT', - rt='webhook'): - cmd = ('cluster receiver create --cluster %s --action %s --type %s ' - '%s' % (cluster, action, rt, name)) - receiver_raw = self.openstack(cmd) - result = self.show_to_dict(receiver_raw) - return result - - def receiver_delete(self, name_or_id): - cmd = ('cluster receiver delete %s --force' % name_or_id) - self.openstack(cmd) diff --git a/senlinclient/tests/functional/policies/deletion_policy.yaml b/senlinclient/tests/functional/policies/deletion_policy.yaml deleted file mode 100644 index 464162e3..00000000 --- a/senlinclient/tests/functional/policies/deletion_policy.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Sample deletion policy that can be attached to a cluster. -type: senlin.policy.deletion -version: 1.0 -description: A policy for choosing victim node(s) from a cluster for deletion. -properties: - # The valid values include: - # OLDEST_FIRST, OLDEST_PROFILE_FIRST, YOUNGEST_FIRST, RANDOM - criteria: OLDEST_FIRST - - # Whether deleted node should be destroyed - destroy_after_deletion: True - - # Length in number of seconds before the actual deletion happens - # This param buys an instance some time before deletion - grace_period: 60 - - # Whether the deletion will reduce the desired capacity of - # the cluster as well - reduce_desired_capacity: False diff --git a/senlinclient/tests/functional/profiles/cirros_basic.yaml b/senlinclient/tests/functional/profiles/cirros_basic.yaml deleted file mode 100644 index 29ddc2eb..00000000 --- a/senlinclient/tests/functional/profiles/cirros_basic.yaml +++ /dev/null @@ -1,12 +0,0 @@ -type: os.nova.server -version: 1.0 -properties: - flavor: 1 - image: "cirros-0.4.0-x86_64-disk" - networks: - - network: private - metadata: - test_key: test_value - user_data: | - #!/bin/sh - echo 'hello, world' > /tmp/test_file diff --git a/senlinclient/tests/functional/test_actions.py b/senlinclient/tests/functional/test_actions.py deleted file mode 100644 index 5a1afbf0..00000000 --- a/senlinclient/tests/functional/test_actions.py +++ /dev/null @@ -1,25 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class ActionTest(base.OpenStackClientTestBase): - """Test for actions""" - - def test_action_list(self): - result = self.openstack('cluster action list') - action_list = self.parser.listing(result) - self.assertTableStruct(action_list, - ['id', 'name', 'action', 'status', - 'target_id', 'depends_on', 'cluster_id', - 'depended_by', 'created_at']) diff --git a/senlinclient/tests/functional/test_cluster_policy.py b/senlinclient/tests/functional/test_cluster_policy.py deleted file mode 100644 index b99d3ee2..00000000 --- a/senlinclient/tests/functional/test_cluster_policy.py +++ /dev/null @@ -1,109 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class ClusterPolicyTest(base.OpenStackClientTestBase): - """Test cluster for policy""" - - def test_cluster_policy_attach_and_detach(self): - name = self.name_generate() - po = self.policy_create(name) - self.addCleanup(self.policy_delete, po['id']) - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['id']) - - cp_raw = self.openstack('cluster policy binding list %s' - % cluster['id']) - cp_data = self.show_to_dict(cp_raw) - self.assertEqual({}, cp_data) - - # Attach policy to cluster - cmd = ('cluster policy attach --policy %s %s' % (po['id'], - cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - cmd = ('cluster policy binding show --policy %s %s' % - (po['id'], cluster['id'])) - policy_raw = self.openstack(cmd) - policy_data = self.show_to_dict(policy_raw) - self.assertEqual(po['name'], policy_data['policy_name']) - self.assertEqual(cluster['name'], policy_data['cluster_name']) - self.assertTrue(policy_data['is_enabled']) - - # Detach policy from cluster - cmd = ('cluster policy detach --policy %s %s' % (po['id'], - cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - cp_raw = self.openstack('cluster policy binding list %s' - % cluster['id']) - cp_data = self.show_to_dict(cp_raw) - self.assertEqual({}, cp_data) - - def test_cluster_policy_list(self): - name = self.name_generate() - po = self.policy_create(name) - self.addCleanup(self.policy_delete, po['id']) - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['id']) - - cmd = ('cluster policy attach --policy %s %s' % (po['id'], - cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - - # List cluster policy binding - cmd = ('cluster policy binding list --filters policy_name=%s %s' - % (po['name'], cluster['id'])) - result = self.openstack(cmd) - binding_list = self.parser.listing(result) - self.assertTableStruct(binding_list, ['policy_id', 'policy_name', - 'policy_type', 'is_enabled']) - cmd = ('cluster policy detach --policy %s %s' % (po['id'], - cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - - def test_cluster_policy_update(self): - name = self.name_generate() - po = self.policy_create(name) - self.addCleanup(self.policy_delete, po['id']) - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['id']) - - cmd = ('cluster policy attach --policy %s %s' % (po['id'], - cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - - # Update cluster policy binding - cmd = ('cluster policy binding update --policy %s --enabled false %s' - % (po['id'], cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - - cp_update = self.openstack('cluster policy binding show --policy %s %s' - % (po['id'], cluster['id'])) - cp_update_data = self.show_to_dict(cp_update) - self.assertFalse(cp_update_data['is_enabled'].isupper()) - cmd = ('cluster policy detach --policy %s %s' % (po['id'], - cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) diff --git a/senlinclient/tests/functional/test_clusters.py b/senlinclient/tests/functional/test_clusters.py deleted file mode 100644 index b44dc142..00000000 --- a/senlinclient/tests/functional/test_clusters.py +++ /dev/null @@ -1,279 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class ClusterTest(base.OpenStackClientTestBase): - """Test for clusters""" - - def test_cluster_list(self): - result = self.openstack('cluster list') - cluster_list = self.parser.listing(result) - self.assertTableStruct(cluster_list, ['id', 'name', 'status', - 'created_at', 'updated_at']) - - def test_cluster_list_filters(self): - params = {'name': 'test1', 'status': 'ACTIVE'} - for k, v in params.items(): - cmd = ('cluster list --filters %s=%s' % (k, v)) - self.openstack(cmd) - - def test_cluster_list_sort(self): - params = ['name', 'status', 'init_at', 'created_at', 'updated_at'] - for param in params: - cmd = 'cluster list --sort %s' % param - self.openstack(cmd) - - def test_cluster_full_id(self): - self.openstack('cluster list --full-id') - - def test_cluster_limit(self): - self.openstack('cluster list --limit 1') - - def test_cluster_create(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name, 1) - self.addCleanup(self.cluster_delete, cluster['id']) - cluster_raw = self.openstack('cluster show %s' % name) - cluster_data = self.show_to_dict(cluster_raw) - self.assertEqual(cluster_data['name'], name) - self.assertEqual(cluster_data['status'], 'ACTIVE') - self.assertEqual(cluster_data['desired_capacity'], '1') - - def test_cluster_update(self): - old_name = self.name_generate() - old_pf = self.profile_create(old_name) - self.addCleanup(self.profile_delete, old_pf['id']) - new_name = self.name_generate() - new_pf = self.profile_create(new_name) - self.addCleanup(self.profile_delete, new_pf['id']) - cluster = self.cluster_create(old_pf['id'], old_name, 1) - self.addCleanup(self.cluster_delete, cluster['id']) - self.assertEqual(cluster['name'], old_name) - - # cluster update - cmd = ('cluster update --name %s --profile %s --timeout 300 %s' - % (old_name, new_pf['id'], cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - - cluster_raw = self.openstack('cluster show %s' % cluster['id']) - cluster_data = self.show_to_dict(cluster_raw) - node_raw = self.openstack('cluster node show %s' % - cluster_data['node_ids']) - node_data = self.show_to_dict(node_raw) - - # if not profile-only, change all profile - self.assertEqual(cluster['name'], cluster_data['name']) - self.assertEqual(cluster_data['profile_id'], new_pf['id']) - self.assertEqual(cluster_data['timeout'], '300') - self.assertEqual(new_pf['name'], node_data['profile_name']) - - def test_cluster_update_profile_only(self): - old_name = self.name_generate() - old_pf = self.profile_create(old_name) - self.addCleanup(self.profile_delete, old_pf['id']) - new_name = self.name_generate() - new_pf = self.profile_create(new_name) - self.addCleanup(self.profile_delete, new_pf['id']) - cluster = self.cluster_create(old_pf['id'], old_name, 1) - self.addCleanup(self.cluster_delete, cluster['id']) - self.assertEqual(cluster['name'], old_name) - - cmd = ('cluster update --name %s --profile %s --profile-only true' - ' --timeout 300 %s' % (new_name, new_pf['id'], cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - - cluster_raw = self.openstack('cluster show %s' % cluster['id']) - cluster_data = self.show_to_dict(cluster_raw) - node_raw = self.openstack('cluster node show %s' % - cluster_data['node_ids']) - node_data = self.show_to_dict(node_raw) - - # if profile-only true, not change exist node profile - self.assertNotEqual(cluster['name'], cluster_data['name']) - self.assertNotEqual(cluster_data['profile_id'], cluster['profile_id']) - self.assertEqual(cluster_data['profile_id'], new_pf['id']) - self.assertEqual(cluster_data['timeout'], '300') - self.assertNotEqual(new_name, node_data['profile_name']) - - def test_cluster_show(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['id']) - cluster_raw = self.openstack('cluster show %s' % name) - cluster_data = self.show_to_dict(cluster_raw) - self.assertIn('node_ids', cluster_data) - self.assertIn('timeout', cluster_data) - - def test_cluster_expand_and_shrink(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['id']) - cluster_raw = self.openstack('cluster show %s' % name) - cluster_data = self.show_to_dict(cluster_raw) - - # cluster expand - self.openstack('cluster expand --count 1 %s' % name) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - expand_raw = self.openstack('cluster show %s' % name) - expand_data = self.show_to_dict(expand_raw) - self.assertNotEqual(cluster_data['desired_capacity'], - expand_data['desired_capacity']) - self.assertEqual(expand_data['desired_capacity'], '1') - - # cluster shrink - self.openstack('cluster shrink --count 1 %s' % name) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - shrink_raw = self.openstack('cluster show %s' % name) - shrink_data = self.show_to_dict(shrink_raw) - self.assertNotEqual(shrink_data['desired_capacity'], - expand_data['desired_capacity']) - self.assertEqual(cluster_data['desired_capacity'], - shrink_data['desired_capacity']) - - # NOTE(chenyb4): Since functional tests only focus on the client/server - # interaction without invovling other OpenStack services, it is not - # possible to mock a cluster failure and then test if the check logic - # works. Such tests would be left to integration tests instead. - def test_cluster_check(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name, 1) - self.addCleanup(self.cluster_delete, cluster['id']) - self.openstack('cluster check %s' % cluster['id']) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - check_raw = self.openstack('cluster show %s' % name) - check_data = self.show_to_dict(check_raw) - self.assertIn('CLUSTER_CHECK', check_data['status_reason']) - cluster_status = ['ACTIVE', 'WARNING'] - self.assertIn(check_data['status'], cluster_status) - - # NOTE(chenyb4): A end-to-end test of the cluster recover operation needs - # to be done with other OpenStack services involved, thus out of scope - # for functional tests. Such tests would be left to integration tests - # instead. - def test_cluster_recover(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name, 1) - self.addCleanup(self.cluster_delete, cluster['id']) - cmd = ('cluster recover --check true %s' % cluster['id']) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - recover_raw = self.openstack('cluster show %s' % name) - recover_data = self.show_to_dict(recover_raw) - self.assertIn('CLUSTER_RECOVER', recover_data['status_reason']) - self.assertEqual('ACTIVE', recover_data['status']) - - def test_cluster_resize(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['id']) - cluster_raw = self.openstack('cluster show %s' % name) - cluster_data = self.show_to_dict(cluster_raw) - self.assertEqual(cluster_data['desired_capacity'], '0') - self.assertEqual(cluster_data['max_size'], '-1') - self.assertEqual(cluster_data['min_size'], '0') - cmd = ('cluster resize --max-size 5 --min-size 1 --adjustment 2 %s' - % cluster['id']) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - resize_raw = self.openstack('cluster show %s' % name) - resize_data = self.show_to_dict(resize_raw) - self.assertEqual(resize_data['desired_capacity'], '2') - self.assertEqual(resize_data['max_size'], '5') - self.assertEqual(resize_data['min_size'], '1') - - def test_cluster_members_list(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['id']) - result = self.openstack('cluster members list --full-id %s' - % cluster['id']) - members_list = self.parser.listing(result) - self.assertTableStruct(members_list, ['id', 'name', 'index', - 'status', 'physical_id', - 'created_at']) - - def test_cluster_members_add_and_del(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['name']) - node = self.node_create(pf['id'], name) - self.addCleanup(self.node_delete, node['id']) - cluster_raw = self.openstack('cluster show %s' % name) - cluster_data = self.show_to_dict(cluster_raw) - self.assertEqual('', cluster_data['node_ids']) - - # Add exist node to cluster - cmd = ('cluster members add --nodes %s %s' % (node['name'], - cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - - mem_ad_raw = self.openstack('cluster show %s' % name) - mem_ad_data = self.show_to_dict(mem_ad_raw) - self.assertNotEqual('', mem_ad_data['node_ids']) - self.assertIn(node['id'], mem_ad_data['node_ids']) - - # Delete node from cluster - cmd = ('cluster members del --nodes %s %s' % (node['name'], - cluster['id'])) - self.openstack(cmd) - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - mem_del_raw = self.openstack('cluster show %s' % name) - mem_del_data = self.show_to_dict(mem_del_raw) - self.assertEqual('', mem_del_data['node_ids']) - self.assertNotIn(node['id'], mem_del_data['node_ids']) - - def test_cluster_members_replace(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name, 1) - self.addCleanup(self.cluster_delete, cluster['id']) - cluster_raw = self.openstack('cluster show %s' % name) - cluster_data = self.show_to_dict(cluster_raw) - - # Create replace node - new_node = self.node_create(pf['id'], name) - self.addCleanup(self.node_delete, new_node['id']) - self.assertNotIn(new_node['id'], cluster_data['node_ids']) - - # Cluster node replace - old_node = cluster_data['node_ids'] - self.addCleanup(self.node_delete, old_node) - cmd = ('cluster members replace --nodes %s=%s %s' - % (old_node, new_node['id'], cluster['id'])) - self.openstack(cmd, flags='--debug') - self.wait_for_status(cluster['id'], 'ACTIVE', 'cluster', 120) - replace_raw = self.openstack('cluster show %s' % name) - replace_data = self.show_to_dict(replace_raw) - self.assertIn(new_node['id'], replace_data['node_ids']) - self.assertNotIn(old_node, replace_data['node_ids']) diff --git a/senlinclient/tests/functional/test_events.py b/senlinclient/tests/functional/test_events.py deleted file mode 100644 index a62909cb..00000000 --- a/senlinclient/tests/functional/test_events.py +++ /dev/null @@ -1,25 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class EventTest(base.OpenStackClientTestBase): - """Test for events""" - - def test_event_list(self): - result = self.openstack('cluster event list') - event_list = self.parser.listing(result) - self.assertTableStruct(event_list, ['id', 'generated_at', 'obj_type', - 'obj_id', 'obj_name', 'action', - 'status', 'level', 'cluster_id', - 'meta_data']) diff --git a/senlinclient/tests/functional/test_help.py b/senlinclient/tests/functional/test_help.py deleted file mode 100644 index f2775f62..00000000 --- a/senlinclient/tests/functional/test_help.py +++ /dev/null @@ -1,22 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class HelpTest(base.OpenStackClientTestBase): - """Test for help commands""" - - def test_help_cmd(self): - help_text = self.openstack('help cluster list') - lines = help_text.split('\n') - self.assertFirstLineStartsWith(lines, 'usage: openstack cluster list') diff --git a/senlinclient/tests/functional/test_nodes.py b/senlinclient/tests/functional/test_nodes.py deleted file mode 100644 index 4a8559c3..00000000 --- a/senlinclient/tests/functional/test_nodes.py +++ /dev/null @@ -1,104 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class NodeTest(base.OpenStackClientTestBase): - """Test for nodes""" - - def test_node_list(self): - result = self.openstack('cluster node list') - node_list = self.parser.listing(result) - self.assertTableStruct(node_list, ['id', 'name', 'index', 'status', - 'cluster_id', 'physical_id', - 'profile_name', 'created_at', - 'updated_at', 'tainted']) - - def test_node_create(self): - name = self.name_generate() - pf = self.profile_create(name) - node = self.node_create(pf['id'], name) - self.assertEqual(node['name'], name) - self.node_delete(node['id']) - self.addCleanup(self.profile_delete, pf['id']) - - def test_node_update(self): - old_name = self.name_generate() - pf = self.profile_create(old_name) - n1 = self.node_create(pf['id'], old_name) - new_name = self.name_generate() - pf_new = self.profile_create(new_name) - role = 'master' - tainted = 'True' - cmd = ('cluster node update --name %s --role %s --profile %s ' - '--tainted %s %s' - % (new_name, role, pf_new['id'], tainted, n1['id'])) - self.openstack(cmd) - self.wait_for_status(n1['id'], 'ACTIVE', 'node', 120) - raw_node = self.openstack('cluster node show %s' % n1['id']) - node_data = self.show_to_dict(raw_node) - self.assertEqual(node_data['name'], new_name) - self.assertNotEqual(node_data['name'], old_name) - self.assertEqual(node_data['role'], role) - self.assertEqual(node_data['tainted'], tainted) - self.assertEqual(node_data['profile_id'], pf_new['id']) - self.node_delete(new_name) - self.addCleanup(self.profile_delete, pf['id']) - self.addCleanup(self.profile_delete, pf_new['id']) - - def test_node_detail(self): - name = self.name_generate() - pf = self.profile_create(name) - node = self.node_create(pf['id'], name) - cmd = ('cluster node show --details %s' % name) - raw_node = self.openstack(cmd) - node_data = self.show_to_dict(raw_node) - self.assertIn('details', node_data) - self.assertIsNotNone(node_data['details']) - self.node_delete(node['id']) - self.addCleanup(self.profile_delete, pf['id']) - - # NOTE(Qiming): Since functional tests only focus on the client/server - # interaction without invovling other OpenStack services, it is not - # possible to mock a node failure and then test if the check logic works. - # Such tests would be left to integration tests instead. - def test_node_check(self): - name = self.name_generate() - pf = self.profile_create(name) - node = self.node_create(pf['id'], name) - cmd = ('cluster node check %s' % node['id']) - self.openstack(cmd) - check_raw = self.openstack('cluster node show %s' % name) - check_data = self.show_to_dict(check_raw) - self.assertIn('Check', check_data['status_reason']) - node_status = ['ACTIVE', 'ERROR'] - self.assertIn(check_data['status'], node_status) - self.node_delete(node['id']) - self.addCleanup(self.profile_delete, pf['id']) - - # NOTE(Qiming): A end-to-end test of the node recover operation needs to - # be done with other OpenStack services involved, thus out of scope for - # functional tests. Such tests would be left to integration tests instead. - def test_node_recover(self): - name = self.name_generate() - pf = self.profile_create(name) - node = self.node_create(pf['id'], name) - cmd = ('cluster node recover --check true %s' % node['id']) - self.openstack(cmd) - self.wait_for_status(name, 'ACTIVE', 'node', 120) - recover_raw = self.openstack('cluster node show %s' % name) - recover_data = self.show_to_dict(recover_raw) - self.assertIn('Recover', recover_data['status_reason']) - self.assertEqual('ACTIVE', recover_data['status']) - self.node_delete(node['id']) - self.addCleanup(self.profile_delete, pf['id']) diff --git a/senlinclient/tests/functional/test_policies.py b/senlinclient/tests/functional/test_policies.py deleted file mode 100644 index 1b01636f..00000000 --- a/senlinclient/tests/functional/test_policies.py +++ /dev/null @@ -1,40 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class PolicyTest(base.OpenStackClientTestBase): - """Test for policies""" - - def test_policy_list(self): - result = self.openstack('cluster policy list') - policy_list = self.parser.listing(result) - self.assertTableStruct(policy_list, ['id', 'name', 'type', - 'created_at']) - - def test_policy_create(self): - name = self.name_generate() - result = self.policy_create(name, 'deletion_policy.yaml') - self.assertEqual(result['name'], name) - self.addCleanup(self.policy_delete, result['id']) - - def test_policy_update(self): - old_name = self.name_generate() - pc1 = self.policy_create(old_name, 'deletion_policy.yaml') - new_name = self.name_generate() - cmd = ('cluster policy update --name %s %s' % (new_name, pc1['id'])) - result = self.openstack(cmd) - pc2 = self.show_to_dict(result) - self.assertEqual(pc2['name'], new_name) - self.assertNotEqual(pc1['name'], pc2['name']) - self.addCleanup(self.policy_delete, pc2['id']) diff --git a/senlinclient/tests/functional/test_policy_types.py b/senlinclient/tests/functional/test_policy_types.py deleted file mode 100644 index ab239008..00000000 --- a/senlinclient/tests/functional/test_policy_types.py +++ /dev/null @@ -1,37 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class PolicyTypeTest(base.OpenStackClientTestBase): - """Test for policy types""" - - def test_policy_type_list(self): - result = self.openstack('cluster policy type list') - policy_type = self.parser.listing(result) - columns = ['name', 'version'] - if any('support_status' in i for i in policy_type): - columns.append('support_status') - self.assertTableStruct(policy_type, columns) - - def test_policy_type_show(self): - params = ['senlin.policy.affinity-1.0', - 'senlin.policy.batch-1.0', - 'senlin.policy.deletion-1.0', - 'senlin.policy.health-1.0', - 'senlin.policy.loadbalance-1.1', - 'senlin.policy.region_placement-1.0', - 'senlin.policy.zone_placement-1.0'] - for param in params: - cmd = 'cluster policy type show %s' % param - self.openstack(cmd) diff --git a/senlinclient/tests/functional/test_profile_types.py b/senlinclient/tests/functional/test_profile_types.py deleted file mode 100644 index 8d973133..00000000 --- a/senlinclient/tests/functional/test_profile_types.py +++ /dev/null @@ -1,42 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class ProfileTypeTest(base.OpenStackClientTestBase): - """Test for profile types - - Basic smoke test for the Openstack CLI commands which do not require - creating or modifying. - """ - def test_profile_type_list(self): - result = self.openstack('cluster profile type list') - profile_type = self.parser.listing(result) - columns = ['name', 'version'] - if any('support_status' in i for i in profile_type): - columns.append('support_status') - self.assertTableStruct(profile_type, columns) - - def test_profile_list_debug(self): - self.openstack('cluster profile type list', flags='--debug') - - def test_profile_type_show(self): - params = ['container.dockerinc.docker-1.0', - 'os.heat.stack-1.0', - 'os.nova.server-1.0'] - for param in params: - cmd = 'cluster profile type show %s' % param - self.openstack(cmd) - - def test_profile_type_show_json(self): - self.openstack('cluster profile type show os.nova.server-1.0 -f json') diff --git a/senlinclient/tests/functional/test_profiles.py b/senlinclient/tests/functional/test_profiles.py deleted file mode 100644 index 9d0ef9a0..00000000 --- a/senlinclient/tests/functional/test_profiles.py +++ /dev/null @@ -1,40 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class ProfileTest(base.OpenStackClientTestBase): - """Test for profiles""" - - def test_profile_list(self): - result = self.openstack('cluster profile list') - profile_list = self.parser.listing(result) - self.assertTableStruct(profile_list, ['id', 'name', 'type', - 'created_at']) - - def test_pofile_create(self): - name = self.name_generate() - result = self.profile_create(name, 'cirros_basic.yaml') - self.assertEqual(result['name'], name) - self.addCleanup(self.profile_delete, result['id']) - - def test_profile_update(self): - old_name = self.name_generate() - pf1 = self.profile_create(old_name, 'cirros_basic.yaml') - new_name = self.name_generate() - cmd = ('cluster profile update --name %s %s' % (new_name, pf1['id'])) - result = self.openstack(cmd) - pf2 = self.show_to_dict(result) - self.assertEqual(pf2['name'], new_name) - self.assertNotEqual(pf1['name'], pf2['name']) - self.addCleanup(self.profile_delete, pf2['id']) diff --git a/senlinclient/tests/functional/test_readonly_senlin.py b/senlinclient/tests/functional/test_readonly_senlin.py deleted file mode 100644 index 88019f98..00000000 --- a/senlinclient/tests/functional/test_readonly_senlin.py +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib import exceptions - -from senlinclient.tests.functional import base - - -class FakeTest(base.OpenStackClientTestBase): - """Test if fake actions can be detected""" - - def test_fake_action(self): - self.assertRaises(exceptions.CommandFailed, - self.openstack, - 'this-does-not-exist') diff --git a/senlinclient/tests/functional/test_receivers.py b/senlinclient/tests/functional/test_receivers.py deleted file mode 100644 index 27df7015..00000000 --- a/senlinclient/tests/functional/test_receivers.py +++ /dev/null @@ -1,57 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.tests.functional import base - - -class ReceiverTest(base.OpenStackClientTestBase): - """Test for receivers""" - - def test_receiver_list(self): - result = self.openstack('cluster receiver list') - receiver_list = self.parser.listing(result) - self.assertTableStruct(receiver_list, ['id', 'name', 'type', - 'cluster_id', 'action', - 'created_at']) - - def test_receiver_create(self): - name = self.name_generate() - pf = self.profile_create(name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], name) - self.addCleanup(self.cluster_delete, cluster['id']) - receiver = self.receiver_create(name, cluster['id']) - self.addCleanup(self.receiver_delete, receiver['id']) - self.assertEqual(receiver['name'], name) - self.assertEqual(receiver['type'], 'webhook') - self.assertEqual(receiver['action'], 'CLUSTER_SCALE_OUT') - - def test_receiver_update(self): - old_name = self.name_generate() - pf = self.profile_create(old_name) - self.addCleanup(self.profile_delete, pf['id']) - cluster = self.cluster_create(pf['id'], old_name) - self.addCleanup(self.cluster_delete, cluster['id']) - receiver = self.receiver_create(old_name, cluster['id']) - self.addCleanup(self.receiver_delete, receiver['id']) - new_name = self.name_generate() - - cmd = ('cluster receiver update --name %s --params count=2 ' - '--action CLUSTER_SCALE_IN %s' % (new_name, receiver['id'])) - self.openstack(cmd) - receiver_raw = self.openstack('cluster receiver show %s' - % receiver['id']) - receiver_data = self.show_to_dict(receiver_raw) - self.assertNotEqual(receiver['name'], receiver_data['name']) - self.assertEqual(receiver_data['name'], new_name) - self.assertNotEqual(receiver['action'], receiver_data['action']) - self.assertEqual(receiver_data['action'], 'CLUSTER_SCALE_IN') diff --git a/senlinclient/tests/functional/test_version.py b/senlinclient/tests/functional/test_version.py deleted file mode 100644 index fce0b1b0..00000000 --- a/senlinclient/tests/functional/test_version.py +++ /dev/null @@ -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. - -from senlinclient.tests.functional import base - - -class VersionTest(base.OpenStackClientTestBase): - """Test for versions""" - - def test_openstack_version(self): - self.openstack('', flags='--version') diff --git a/senlinclient/tests/test_specs/deletion_policy.yaml b/senlinclient/tests/test_specs/deletion_policy.yaml deleted file mode 100644 index 7255207a..00000000 --- a/senlinclient/tests/test_specs/deletion_policy.yaml +++ /dev/null @@ -1,8 +0,0 @@ -type: senlin.policy.deletion -version: 1.0 -description: A policy for choosing victim node(s) from a cluster for deletion. -properties: - criteria: OLDEST_FIRST - destroy_after_deletion: True - grace_period: 60 - reduce_desired_capacity: False \ No newline at end of file diff --git a/senlinclient/tests/test_specs/nova_server.yaml b/senlinclient/tests/test_specs/nova_server.yaml deleted file mode 100644 index 07fa0301..00000000 --- a/senlinclient/tests/test_specs/nova_server.yaml +++ /dev/null @@ -1,6 +0,0 @@ -type: os.nova.server -version: 1.0 -properties: - name: cirros_server - flavor: 1 - image: cirros-0.3.4-x86_64-uec diff --git a/senlinclient/tests/unit/__init__.py b/senlinclient/tests/unit/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/senlinclient/tests/unit/fakes.py b/senlinclient/tests/unit/fakes.py deleted file mode 100644 index 58d2035b..00000000 --- a/senlinclient/tests/unit/fakes.py +++ /dev/null @@ -1,25 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from senlinclient.common import utils - - -def do_command_foo(sc, args): - """Pydoc for command foo.""" - return - - -@utils.arg('-F', '--flag', metavar='', help='Flag desc.') -@utils.arg('arg1', metavar='', help='Arg1 desc') -def do_command_bar(sc, args): - """This is the command doc.""" - return diff --git a/senlinclient/tests/unit/test_format_utils.py b/senlinclient/tests/unit/test_format_utils.py deleted file mode 100644 index 5ff9af4b..00000000 --- a/senlinclient/tests/unit/test_format_utils.py +++ /dev/null @@ -1,91 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import yaml - -from oslo_serialization import jsonutils - -from osc_lib.tests import utils -from senlinclient.common import format_utils - - -columns = ['col1', 'col2', 'col3'] -data = ['abcde', ['fg', 'hi', 'jk'], {'lmnop': 'qrstu'}] - - -class ShowJson(format_utils.JsonFormat): - def take_action(self, parsed_args): - return columns, data - - -class ShowYaml(format_utils.YamlFormat): - def take_action(self, parsed_args): - return columns, data - - -class ShowShell(format_utils.ShellFormat): - def take_action(self, parsed_args): - return columns, data - - -class ShowValue(format_utils.ValueFormat): - def take_action(self, parsed_args): - return columns, data - - -class TestFormats(utils.TestCommand): - - def test_json_format(self): - self.cmd = ShowJson(self.app, None) - parsed_args = self.check_parser(self.cmd, [], []) - expected = jsonutils.dumps(dict(zip(columns, data)), indent=2) - - self.cmd.run(parsed_args) - - self.assertEqual(jsonutils.loads(expected), - jsonutils.loads(self.app.stdout.make_string())) - - def test_yaml_format(self): - self.cmd = ShowYaml(self.app, None) - parsed_args = self.check_parser(self.cmd, [], []) - expected = yaml.safe_dump(dict(zip(columns, data)), - default_flow_style=False) - - self.cmd.run(parsed_args) - - self.assertEqual(expected, self.app.stdout.make_string()) - - def test_shell_format(self): - self.cmd = ShowShell(self.app, None) - parsed_args = self.check_parser(self.cmd, [], []) - expected = '''\ -col1="abcde" -col2="['fg', 'hi', 'jk']" -col3="{'lmnop': 'qrstu'}" -''' - - self.cmd.run(parsed_args) - - self.assertEqual(expected, self.app.stdout.make_string()) - - def test_value_format(self): - self.cmd = ShowValue(self.app, None) - parsed_args = self.check_parser(self.cmd, [], []) - expected = '''\ -abcde -['fg', 'hi', 'jk'] -{'lmnop': 'qrstu'} -''' - - self.cmd.run(parsed_args) - - self.assertEqual(expected, self.app.stdout.make_string()) diff --git a/senlinclient/tests/unit/test_plugin.py b/senlinclient/tests/unit/test_plugin.py deleted file mode 100644 index 7ff1999f..00000000 --- a/senlinclient/tests/unit/test_plugin.py +++ /dev/null @@ -1,72 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from openstack import connection as sdk_connection -import testtools -from unittest import mock - -from senlinclient import plugin - - -class TestPlugin(testtools.TestCase): - - @mock.patch.object(sdk_connection, 'Connection') - def test_create_connection_with_profile(self, mock_connection): - class FakeService(object): - interface = 'public' - region = 'a_region' - version = '1' - api_version = None - service_type = 'clustering' - - mock_prof = mock.Mock() - mock_prof.get_services.return_value = [FakeService()] - mock_conn = mock.Mock() - mock_connection.return_value = mock_conn - kwargs = { - 'user_id': '123', - 'password': 'abc', - 'auth_url': 'test_url' - } - res = plugin.create_connection(mock_prof, **kwargs) - mock_connection.assert_called_once_with( - app_name=None, app_version=None, - config=mock.ANY, - clustering_api_version=plugin.CURRENT_API_VERSION, - **kwargs - ) - self.assertEqual(mock_conn, res) - - @mock.patch.object(sdk_connection, 'Connection') - def test_create_connection_without_profile(self, mock_connection): - mock_conn = mock.Mock() - mock_connection.return_value = mock_conn - kwargs = { - 'interface': 'public', - 'region_name': 'RegionOne', - 'user_id': '123', - 'password': 'abc', - 'auth_url': 'test_url' - } - res = plugin.create_connection(**kwargs) - - mock_connection.assert_called_once_with( - app_name=None, app_version=None, - auth_url='test_url', - clustering_api_version=plugin.CURRENT_API_VERSION, - config=None, - interface='public', - password='abc', - region_name='RegionOne', - user_id='123' - ) - self.assertEqual(mock_conn, res) diff --git a/senlinclient/tests/unit/test_utils.py b/senlinclient/tests/unit/test_utils.py deleted file mode 100644 index 425f46a4..00000000 --- a/senlinclient/tests/unit/test_utils.py +++ /dev/null @@ -1,147 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from heatclient.common import template_utils -from oslo_utils import importutils -from unittest import mock - -import testtools -import time - -from senlinclient.common import exc -from senlinclient.common.i18n import _ -from senlinclient.common import utils - - -class UtilTest(testtools.TestCase): - - def test_format_parameter(self): - params = ['status=ACTIVE;name=cluster1'] - format_params = {'status': 'ACTIVE', 'name': 'cluster1'} - self.assertEqual(format_params, - utils.format_parameters(params)) - - def test_import_versioned_module(self): - module = 'senlinclient' - version = 'v1' - submodule = '__init__' - module_name = '.'.join((module, version, submodule)) - self.assertIsNone(utils.import_versioned_module(version[-1])) - self.assertEqual(utils.import_versioned_module(version[-1], submodule), - importutils.import_module(module_name)) - - def test_format_parameter_split(self): - params = ['status=ACTIVE', 'name=cluster1'] - format_params = {'status': 'ACTIVE', 'name': 'cluster1'} - self.assertEqual(format_params, - utils.format_parameters(params)) - - def test_format_parameter_none_dict(self): - params = ['{}'] - self.assertEqual({}, utils.format_parameters(params)) - - def test_format_parameter_none(self): - self.assertEqual({}, utils.format_parameters(None)) - - def test_format_parameter_bad_format(self): - params = ['status:ACTIVE;name:cluster1'] - ex = self.assertRaises(exc.CommandError, - utils.format_parameters, - params) - msg = _('Malformed parameter(status:ACTIVE). ' - 'Use the key=value format.') - self.assertEqual(msg, str(ex)) - - @mock.patch.object(template_utils, - 'process_multiple_environments_and_files') - @mock.patch.object(template_utils, 'get_template_contents') - def test_process_stack_spec(self, mock_get_temp, mock_process): - spec = { - 'template': 'temp.yaml', - 'disable_rollback': True, - 'context': { - 'region_name': 'RegionOne' - }, - } - tpl_files = {'fake_key1': 'fake_value1'} - template = mock.Mock() - mock_get_temp.return_value = tpl_files, template - env_files = {'fake_key2': 'fake_value2'} - env = mock.Mock() - mock_process.return_value = env_files, env - new_spec = utils.process_stack_spec(spec) - stack_spec = { - 'disable_rollback': True, - 'context': { - 'region_name': 'RegionOne', - }, - 'parameters': {}, - 'timeout': 60, - 'template': template, - 'files': { - 'fake_key1': 'fake_value1', - 'fake_key2': 'fake_value2', - }, - 'environment': env - } - self.assertEqual(stack_spec, new_spec) - mock_get_temp.assert_called_once_with(template_file='temp.yaml') - mock_process.assert_called_once_with(env_paths=None) - - def test_json_formatter_with_empty_json(self): - params = {} - self.assertEqual('{}', utils.json_formatter(params)) - - def test_list_formatter_with_list(self): - params = ['foo', 'bar'] - self.assertEqual('foo\nbar', utils.list_formatter(params)) - - def test_list_formatter_with_empty_list(self): - params = [] - self.assertEqual('', utils.list_formatter(params)) - - @mock.patch.object(utils, '_check') - def test_await_cluster_action(self, mock_check): - utils.await_action('fake-client', 'test-action-id') - mock_check.assert_called_once() - - @mock.patch.object(utils, '_check') - def test_await_cluster_status(self, mock_check): - utils.await_cluster_status('fake-client', 'ACTIVE') - mock_check.assert_called_once() - - @mock.patch.object(utils, '_check') - def test_await_cluster_delete(self, mock_check): - utils.await_cluster_delete('fake-client', 'test-cluster-id') - mock_check.assert_called_once() - - def test_check(self): - check_func = mock.Mock(return_value=True) - - try: - utils._check(check_func) - except Exception: - self.fail("_check() unexpectedly raised an exception") - - check_func.assert_called() - - @mock.patch.object(time, 'sleep') - def test_check_raises(self, mock_sleep): - mock_check_func = mock.Mock(return_value=False) - - poll_count = 2 - poll_interval = 1 - - self.assertRaises(exc.PollingExceededError, utils._check, - mock_check_func, poll_count, poll_interval) - mock_check_func.assert_called() - mock_sleep.assert_called() diff --git a/senlinclient/tests/unit/v1/__init__.py b/senlinclient/tests/unit/v1/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/senlinclient/tests/unit/v1/fakes.py b/senlinclient/tests/unit/v1/fakes.py deleted file mode 100644 index fac2164f..00000000 --- a/senlinclient/tests/unit/v1/fakes.py +++ /dev/null @@ -1,176 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import sys -from unittest import mock - -from osc_lib.tests import utils -import requests - -from oslo_serialization import jsonutils - -AUTH_TOKEN = "foobar" -AUTH_URL = "http://0.0.0.0" -USERNAME = "itchy" -PASSWORD = "scratchy" - -TEST_RESPONSE_DICT_V3 = { - "token": { - "audit_ids": [ - "a" - ], - "catalog": [ - ], - "expires_at": "2034-09-29T18:27:15.978064Z", - "extras": {}, - "issued_at": "2014-09-29T17:27:15.978097Z", - "methods": [ - "password" - ], - "project": { - "domain": { - "id": "default", - "name": "Default" - }, - "id": "bbb", - "name": "project" - }, - "roles": [ - ], - "user": { - "domain": { - "id": "default", - "name": "Default" - }, - "id": "aaa", - "name": USERNAME - } - } -} -TEST_VERSIONS = { - "versions": { - "values": [ - { - "id": "v3.0", - "links": [ - { - "href": AUTH_URL, - "rel": "self" - } - ], - "media-types": [ - { - "base": "application/json", - "type": "application/vnd.openstack.identity-v3+json" - }, - { - "base": "application/xml", - "type": "application/vnd.openstack.identity-v3+xml" - } - ], - "status": "stable", - "updated": "2013-03-06T00:00:00Z" - } - ] - } -} - - -class FakeStdout(object): - def __init__(self): - self.content = [] - - def write(self, text): - self.content.append(text) - - def make_string(self): - result = '' - for line in self.content: - result = result + line - return result - - -class FakeApp(object): - def __init__(self, _stdout): - self.stdout = _stdout - self.client_manager = None - self.stdin = sys.stdin - self.stdout = _stdout or sys.stdout - self.stderr = sys.stderr - - -class FakeClient(object): - def __init__(self, **kwargs): - self.auth_url = kwargs['auth_url'] - self.token = kwargs['token'] - - -class FakeClientManager(object): - def __init__(self): - self.compute = None - self.identity = None - self.image = None - self.object_store = None - self.volume = None - self.network = None - self.session = None - self.auth_ref = None - - -class FakeModule(object): - def __init__(self, name, version): - self.name = name - self.__version__ = version - - -class FakeResource(object): - def __init__(self, manager, info, loaded=False): - self.manager = manager - self._info = info - self._add_details(info) - self._loaded = loaded - - def _add_details(self, info): - for (k, v) in info.items(): - setattr(self, k, v) - - def __repr__(self): - reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and - k != 'manager') - info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) - return "<%s %s>" % (self.__class__.__name__, info) - - -class FakeResponse(requests.Response): - def __init__(self, headers={}, status_code=200, data=None, encoding=None): - super(FakeResponse, self).__init__() - - self.status_code = status_code - - self.headers.update(headers) - self._content = jsonutils.dump_as_bytes(data) - - -class FakeClusteringv1Client(object): - def __init__(self, **kwargs): - self.http_client = mock.Mock() - self.http_client.auth_token = kwargs['token'] - self.profiles = FakeResource(None, {}) - - -class TestClusteringv1(utils.TestCommand): - def setUp(self): - super(TestClusteringv1, self).setUp() - - self.app.client_manager.clustering = FakeClusteringv1Client( - token=AUTH_TOKEN, auth_url=AUTH_URL - ) diff --git a/senlinclient/tests/unit/v1/test_action.py b/senlinclient/tests/unit/v1/test_action.py deleted file mode 100644 index 847c341d..00000000 --- a/senlinclient/tests/unit/v1/test_action.py +++ /dev/null @@ -1,222 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -from unittest import mock - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import action as osc_action - - -class TestAction(fakes.TestClusteringv1): - - def setUp(self): - super(TestAction, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestActionList(TestAction): - - columns = ['id', 'name', 'action', 'status', 'target_id', 'depends_on', - 'depended_by', 'created_at', 'cluster_id'] - defaults = { - 'global_project': False, - 'marker': None, - 'limit': None, - 'sort': None, - } - - def setUp(self): - super(TestActionList, self).setUp() - self.cmd = osc_action.ListAction(self.app, None) - fake_action = mock.Mock( - action="NODE_CREATE", - cluster_id="FAKE_CLUSTER_ID", - cause="RPC Request", - created_at="2015-12-04T04:54:41", - depended_by=[], - depends_on=[], - end_time=1425550000.0, - id="2366d440-c73e-4961-9254-6d1c3af7c167", - inputs={}, - interval=-1, - name="node_create_0df0931b", - outputs={}, - owner=None, - start_time=1425550000.0, - status="SUCCEEDED", - status_reason="Action completed successfully.", - target_id="0df0931b-e251-4f2e-8719-4ebfda3627ba", - timeout=3600, - updated_at=None - ) - fake_action.to_dict = mock.Mock(return_value={}) - self.mock_client.actions = mock.Mock(return_value=[fake_action]) - - def test_action_list_defaults(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.actions.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_action_list_full_id(self): - arglist = ['--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.actions.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_action_list_limit(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['limit'] = '3' - arglist = ['--limit', '3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.actions.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_action_list_sort(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:asc' - arglist = ['--sort', 'name:asc'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.actions.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_action_list_sort_invalid_key(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'bad_key' - arglist = ['--sort', 'bad_key'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.actions.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_action_list_sort_invalid_direction(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:bad_direction' - arglist = ['--sort', 'name:bad_direction'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.actions.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_action_list_filter(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['name'] = 'my_action' - arglist = ['--filter', 'name=my_action'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.actions.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_action_list_marker(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['marker'] = 'a9448bf6' - arglist = ['--marker', 'a9448bf6'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.actions.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - -class TestActionShow(TestAction): - - def setUp(self): - super(TestActionShow, self).setUp() - self.cmd = osc_action.ShowAction(self.app, None) - fake_action = mock.Mock( - action="NODE_CREATE", - cluster_id="FAKE_CLUSTER_ID", - cause="RPC Request", - created_at="2015-12-04T04:54:41", - depended_by=[], - depends_on=[], - end_time=1425550000.0, - id="2366d440-c73e-4961-9254-6d1c3af7c167", - inputs={}, - interval=-1, - name="node_create_0df0931b", - outputs={}, - owner=None, - start_time=1425550000.0, - status="SUCCEEDED", - status_reason="Action completed successfully.", - target_id="0df0931b-e251-4f2e-8719-4ebfda3627ba", - timeout=3600, - updated_at=None - ) - fake_action.to_dict = mock.Mock(return_value={}) - self.mock_client.get_action = mock.Mock(return_value=fake_action) - - def test_action_show(self): - arglist = ['my_action'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_action.assert_called_with('my_action') - - def test_action_show_not_found(self): - arglist = ['my_action'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_action.side_effect = sdk_exc.ResourceNotFound() - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertEqual('Action not found: my_action', str(error)) - - -class TestActionUpdate(TestAction): - - def setUp(self): - super(TestActionUpdate, self).setUp() - self.cmd = osc_action.UpdateAction(self.app, None) - fake_action = mock.Mock( - action="NODE_CREATE", - cluster_id="FAKE_CLUSTER_ID", - cause="RPC Request", - created_at="2015-12-04T04:54:41", - depended_by=[], - depends_on=[], - end_time=1425550000.0, - id="2366d440-c73e-4961-9254-6d1c3af7c167", - inputs={}, - interval=-1, - name="node_create_0df0931b", - outputs={}, - owner=None, - start_time=1425550000.0, - status="INIT", - status_reason="Action completed successfully.", - target_id="0df0931b-e251-4f2e-8719-4ebfda3627ba", - timeout=3600, - updated_at=None - ) - fake_action.to_dict = mock.Mock(return_value={}) - self.mock_client.get_action = mock.Mock(return_value=fake_action) - self.mock_client.update_action = mock.Mock(return_value=fake_action) - - def test_action_update(self): - arglist = ['--status', 'CANCELLED', - '2366d440-c73e-4961-9254-6d1c3af7c167'] - parsed_args = self.check_parser(self.cmd, arglist, []) - defaults = { - "status": "CANCELLED" - } - - self.cmd.take_action(parsed_args) - - self.mock_client.update_action.assert_called_with( - "2366d440-c73e-4961-9254-6d1c3af7c167", **defaults) diff --git a/senlinclient/tests/unit/v1/test_build_info.py b/senlinclient/tests/unit/v1/test_build_info.py deleted file mode 100644 index 04298cf4..00000000 --- a/senlinclient/tests/unit/v1/test_build_info.py +++ /dev/null @@ -1,35 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import build_info as osc_build_info - - -class TestBuildInfo(fakes.TestClusteringv1): - - def setUp(self): - super(TestBuildInfo, self).setUp() - self.cmd = osc_build_info.BuildInfo(self.app, None) - self.mock_client = self.app.client_manager.clustering - fake_bi = mock.Mock( - api={"revision": "1.0"}, - engine={"revision": "1.0"} - ) - self.mock_client.get_build_info = mock.Mock(return_value=fake_bi) - - def test_build_info(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_build_info.assert_called_with() diff --git a/senlinclient/tests/unit/v1/test_client.py b/senlinclient/tests/unit/v1/test_client.py deleted file mode 100644 index b0918e91..00000000 --- a/senlinclient/tests/unit/v1/test_client.py +++ /dev/null @@ -1,488 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools -from unittest import mock - -from senlinclient import plugin -from senlinclient.v1 import client - - -@mock.patch.object(plugin, 'create_connection') -class ClientTest(testtools.TestCase): - - def setUp(self): - super(ClientTest, self).setUp() - self.conn = mock.Mock() - self.service = mock.Mock() - self.conn.cluster = self.service - - def test_init_default(self, mock_conn): - mock_conn.return_value = self.conn - - sc = client.Client() - - self.assertEqual(self.conn, sc.conn) - self.assertEqual(self.service, sc.service) - mock_conn.assert_called_once_with(prof=None, user_agent=None) - - def test_init_with_params(self, mock_conn): - mock_conn.return_value = self.conn - - sc = client.Client(prof='FOO', user_agent='BAR', zoo='LARR') - - self.assertEqual(self.conn, sc.conn) - self.assertEqual(self.service, sc.service) - mock_conn.assert_called_once_with(prof='FOO', user_agent='BAR', - zoo='LARR') - - def test_profile_types(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.profile_types(foo='bar') - self.assertEqual(self.service.profile_types.return_value, res) - self.service.profile_types.assert_called_once_with(foo='bar') - - def test_get_profile_type(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_profile_type('FOOBAR') - self.assertEqual(self.service.get_profile_type.return_value, res) - self.service.get_profile_type.assert_called_once_with('FOOBAR') - - def test_profiles(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.profiles(foo='bar') - self.assertEqual(self.service.profiles.return_value, res) - self.service.profiles.assert_called_once_with(foo='bar') - - def test_get_profile(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_profile('FOOBAR') - self.assertEqual(self.service.get_profile.return_value, res) - self.service.get_profile.assert_called_once_with('FOOBAR') - - def test_update_profile(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.update_profile('FAKE_ID', foo='bar') - self.assertEqual(self.service.update_profile.return_value, res) - self.service.update_profile.assert_called_once_with('FAKE_ID', - foo='bar') - - def test_delete_profile(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_profile('FAKE_ID') - self.assertEqual(self.service.delete_profile.return_value, res) - self.service.delete_profile.assert_called_once_with( - 'FAKE_ID', True) - - def test_delete_profile_ignore_missing(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_profile('FAKE_ID', False) - self.assertEqual(self.service.delete_profile.return_value, res) - self.service.delete_profile.assert_called_once_with( - 'FAKE_ID', False) - - def test_policy_types(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.policy_types(foo='bar') - self.assertEqual(self.service.policy_types.return_value, res) - self.service.policy_types.assert_called_once_with(foo='bar') - - def test_get_policy_type(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_policy_type('FOOBAR') - self.assertEqual(self.service.get_policy_type.return_value, res) - self.service.get_policy_type.assert_called_once_with('FOOBAR') - - def test_policies(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.policies(foo='bar') - self.assertEqual(self.service.policies.return_value, res) - self.service.policies.assert_called_once_with(foo='bar') - - def test_get_policy(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_policy('FOOBAR') - self.assertEqual(self.service.get_policy.return_value, res) - self.service.get_policy.assert_called_once_with('FOOBAR') - - def test_update_policy(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.update_policy('FAKE_ID', foo='bar') - self.assertEqual(self.service.update_policy.return_value, res) - self.service.update_policy.assert_called_once_with( - 'FAKE_ID', foo='bar') - - def test_delete_policy(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_policy('FAKE_ID') - self.assertEqual(self.service.delete_policy.return_value, res) - self.service.delete_policy.assert_called_once_with( - 'FAKE_ID', True) - - def test_delete_policy_ignore_missing(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_policy('FAKE_ID', False) - self.assertEqual(self.service.delete_policy.return_value, res) - self.service.delete_policy.assert_called_once_with( - 'FAKE_ID', False) - - def test_clusters(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.clusters(foo='bar') - self.assertEqual(self.service.clusters.return_value, res) - self.service.clusters.assert_called_once_with(foo='bar') - - def test_get_cluster(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_cluster('FOOBAR') - self.assertEqual(self.service.get_cluster.return_value, res) - self.service.get_cluster.assert_called_once_with('FOOBAR') - - def test_create_cluster(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.create_cluster(name='FOO', bar='zoo') - self.assertEqual(self.service.create_cluster.return_value, res) - self.service.create_cluster.assert_called_once_with( - name='FOO', bar='zoo') - - def test_update_cluster(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.update_cluster('FAKE_ID', foo='bar') - self.assertEqual(self.service.update_cluster.return_value, res) - self.service.update_cluster.assert_called_once_with( - 'FAKE_ID', foo='bar') - - def test_delete_cluster(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_cluster('FAKE_ID', True) - self.assertEqual(self.service.delete_cluster.return_value, res) - self.service.delete_cluster.assert_called_once_with( - 'FAKE_ID', True, False) - - def test_delete_cluster_ignore_missing(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_cluster('FAKE_ID', True, False) - self.assertEqual(self.service.delete_cluster.return_value, res) - self.service.delete_cluster.assert_called_once_with( - 'FAKE_ID', True, False) - - def test_cluster_add_nodes(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_add_nodes('FAKE_ID', ['NODE1', 'NODE2']) - self.assertEqual(self.service.add_nodes_to_cluster.return_value, res) - self.service.add_nodes_to_cluster.assert_called_once_with( - 'FAKE_ID', ['NODE1', 'NODE2']) - - def test_cluster_del_nodes(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_del_nodes('FAKE_ID', ['NODE1', 'NODE2']) - self.assertEqual(self.service.remove_nodes_from_cluster.return_value, - res) - self.service.remove_nodes_from_cluster.assert_called_once_with( - 'FAKE_ID', ['NODE1', 'NODE2']) - - def test_cluster_resize(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_resize('FAKE_ID', foo='bar', zoo=1) - self.assertEqual(self.service.resize_cluster.return_value, res) - self.service.resize_cluster.assert_called_once_with( - 'FAKE_ID', foo='bar', zoo=1) - - def test_cluster_scale_in(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_scale_in('FAKE_ID', 3) - self.assertEqual(self.service.scale_in_cluster.return_value, res) - self.service.scale_in_cluster.assert_called_once_with( - 'FAKE_ID', 3) - - def test_cluster_scale_out(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_scale_out('FAKE_ID', 3) - self.assertEqual(self.service.scale_out_cluster.return_value, res) - self.service.scale_out_cluster.assert_called_once_with( - 'FAKE_ID', 3) - - def test_cluster_policies(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_policies('CLUSTER', foo='bar') - self.assertEqual(self.service.cluster_policies.return_value, res) - self.service.cluster_policies.assert_called_once_with( - 'CLUSTER', foo='bar') - - def test_get_cluster_policy(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_cluster_policy('PID', 'CID') - self.assertEqual(self.service.get_cluster_policy.return_value, res) - self.service.get_cluster_policy.assert_called_once_with( - 'PID', 'CID') - - def test_cluster_attach_policy(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_attach_policy('FOO', 'BAR', zoo='car') - self.assertEqual(self.service.attach_policy_to_cluster.return_value, - res) - self.service.attach_policy_to_cluster.assert_called_once_with( - 'FOO', 'BAR', zoo='car') - - def test_cluster_detach_policy(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_detach_policy('FOO', 'BAR') - self.assertEqual(self.service.detach_policy_from_cluster.return_value, - res) - self.service.detach_policy_from_cluster.assert_called_once_with( - 'FOO', 'BAR') - - def test_cluster_update_policy(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.cluster_update_policy('FOO', 'BAR', foo='bar') - self.assertEqual(self.service.update_cluster_policy.return_value, res) - self.service.update_cluster_policy.assert_called_once_with( - 'FOO', 'BAR', foo='bar') - - def test_check_cluster(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.check_cluster('FAKE_CLUSTER_ID') - self.assertEqual(self.service.check_cluster.return_value, res) - self.service.check_cluster.assert_called_once_with('FAKE_CLUSTER_ID') - - def test_recover_cluster(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.recover_cluster('FAKE_CLUSTER_ID') - self.assertEqual(self.service.recover_cluster.return_value, res) - self.service.recover_cluster.assert_called_once_with( - 'FAKE_CLUSTER_ID') - - def test_nodes(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.nodes(foo='bar') - self.assertEqual(self.service.nodes.return_value, res) - self.service.nodes.assert_called_once_with(foo='bar') - - def test_get_node(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_node('FOOBAR') - self.assertEqual(self.service.get_node.return_value, res) - self.service.get_node.assert_called_once_with('FOOBAR', details=False) - - def test_get_node_with_details(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_node('FOOBAR', details=True) - self.assertEqual(self.service.get_node.return_value, res) - self.service.get_node.assert_called_once_with( - 'FOOBAR', details=True) - - def test_create_node(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.create_node(name='FAKE_NAME', foo='bar') - self.assertEqual(self.service.create_node.return_value, res) - self.service.create_node.assert_called_once_with( - name='FAKE_NAME', foo='bar') - - def test_update_node(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.update_node('FAKE_ID', foo='bar') - self.assertEqual(self.service.update_node.return_value, res) - self.service.update_node.assert_called_once_with( - 'FAKE_ID', foo='bar') - - def test_delete_node(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_node('FAKE_ID', True) - self.assertEqual(self.service.delete_node.return_value, res) - self.service.delete_node.assert_called_once_with( - 'FAKE_ID', True, False) - - def test_check_node(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.check_node('FAKE_ID') - self.assertEqual(self.service.check_node.return_value, res) - self.service.check_node.assert_called_once_with('FAKE_ID') - - def test_recover_node(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.recover_node('FAKE_ID') - self.assertEqual(self.service.recover_node.return_value, res) - self.service.recover_node.assert_called_once_with( - 'FAKE_ID') - - def test_delete_node_ignore_missing(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_node('FAKE_ID', True, False) - self.assertEqual(self.service.delete_node.return_value, res) - self.service.delete_node.assert_called_once_with( - 'FAKE_ID', True, False) - - def test_receivers(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.receivers(foo='bar') - self.assertEqual(self.service.receivers.return_value, res) - self.service.receivers.assert_called_once_with(foo='bar') - - def test_get_receiver(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_receiver('FOOBAR') - self.assertEqual(self.service.get_receiver.return_value, res) - self.service.get_receiver.assert_called_once_with('FOOBAR') - - def test_create_receiver(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.create_receiver(name='FAKE_NAME', foo='bar') - self.assertEqual(self.service.create_receiver.return_value, res) - self.service.create_receiver.assert_called_once_with( - name='FAKE_NAME', foo='bar') - - def test_delete_receiver(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_receiver('FAKE_ID') - self.assertEqual(self.service.delete_receiver.return_value, res) - self.service.delete_receiver.assert_called_once_with( - 'FAKE_ID', True) - - def test_delete_receiver_ignore_missing(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.delete_receiver('FAKE_ID', False) - self.assertEqual(self.service.delete_receiver.return_value, res) - self.service.delete_receiver.assert_called_once_with( - 'FAKE_ID', False) - - def test_actions(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.actions(foo='bar') - self.assertEqual(self.service.actions.return_value, res) - self.service.actions.assert_called_once_with(foo='bar') - - def test_get_action(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_action('FOOBAR') - self.assertEqual(self.service.get_action.return_value, res) - self.service.get_action.assert_called_once_with('FOOBAR') - - def test_update_action(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.update_action('FAKE_ID', status='CANCELLED') - self.assertEqual(self.service.update_action.return_value, res) - self.service.update_action.assert_called_once_with( - 'FAKE_ID', status='CANCELLED') - - def test_events(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.events(foo='bar') - self.assertEqual(self.service.events.return_value, res) - self.service.events.assert_called_once_with(foo='bar') - - def test_get_event(self, mock_conn): - mock_conn.return_value = self.conn - sc = client.Client() - - res = sc.get_event('FOOBAR') - self.assertEqual(self.service.get_event.return_value, res) - self.service.get_event.assert_called_once_with('FOOBAR') diff --git a/senlinclient/tests/unit/v1/test_cluster.py b/senlinclient/tests/unit/v1/test_cluster.py deleted file mode 100644 index c8aeebc0..00000000 --- a/senlinclient/tests/unit/v1/test_cluster.py +++ /dev/null @@ -1,1520 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import io -import subprocess -from unittest import mock - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc - -from senlinclient.common import utils as senlin_utils -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import cluster as osc_cluster - - -class TestCluster(fakes.TestClusteringv1): - def setUp(self): - super(TestCluster, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestClusterList(TestCluster): - - columns = ['id', 'name', 'status', 'created_at', 'updated_at'] - defaults = { - 'global_project': False, - 'marker': None, - 'limit': None, - 'sort': None, - } - - def setUp(self): - super(TestClusterList, self).setUp() - self.cmd = osc_cluster.ListCluster(self.app, None) - fake_cluster = mock.Mock( - created_at="2015-02-10T14:26:14", - data={}, - desired_capacity=4, - domain_id=None, - id="7d85f602-a948-4a30-afd4-e84f47471c15", - init_time="2015-02-10T14:26:11", - max_size=-1, - metadata={}, - min_size=0, - node_ids=[ - "b07c57c8-7ab2-47bf-bdf8-e894c0c601b9", - "ecc23d3e-bb68-48f8-8260-c9cf6bcb6e61", - "da1e9c87-e584-4626-a120-022da5062dac" - ], - policies=[], - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - status="ACTIVE", - status_reason="Cluster scale-in succeeded", - timeout=3600, - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_cluster.name = "cluster1" - fake_cluster.to_dict = mock.Mock(return_value={}) - - self.mock_client.clusters = mock.Mock(return_value=[fake_cluster]) - - def test_cluster_list_defaults(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.clusters.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_cluster_list_full_id(self): - arglist = ['--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.clusters.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_cluster_list_limit(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['limit'] = '3' - arglist = ['--limit', '3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.clusters.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_cluster_list_sort(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:asc' - arglist = ['--sort', 'name:asc'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.clusters.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_cluster_list_sort_invalid_key(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'bad_key' - arglist = ['--sort', 'bad_key'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.clusters.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_cluster_list_sort_invalid_direction(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:bad_direction' - arglist = ['--sort', 'name:bad_direction'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.clusters.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_cluster_list_filter(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['name'] = 'my_cluster' - arglist = ['--filter', 'name=my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.clusters.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_cluster_list_marker(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['marker'] = 'a9448bf6' - arglist = ['--marker', 'a9448bf6'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.clusters.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - -class TestClusterShow(TestCluster): - - def setUp(self): - super(TestClusterShow, self).setUp() - self.cmd = osc_cluster.ShowCluster(self.app, None) - fake_cluster = mock.Mock( - config={}, - created_at="2015-02-11T15:13:20", - data={}, - desired_capacity=0, - domain_id=None, - id="7d85f602-a948-4a30-afd4-e84f47471c15", - init_time="2015-02-10T14:26:11", - max_size=-1, - metadata={}, - min_size=0, - node_ids=[], - policies=[], - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - status="ACTIVE", - status_reason="Cluster scale-in succeeded", - timeout=3600, - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_cluster.name = "my_cluster" - fake_cluster.to_dict = mock.Mock(return_value={}) - self.mock_client.get_cluster = mock.Mock(return_value=fake_cluster) - - def test_cluster_show(self): - arglist = ['my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_cluster.assert_called_with('my_cluster') - - def test_cluster_show_not_found(self): - arglist = ['my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_cluster.side_effect = sdk_exc.ResourceNotFound() - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertEqual('Cluster not found: my_cluster', str(error)) - - -class TestClusterCreate(TestCluster): - - defaults = { - "config": {}, - "desired_capacity": 0, - "max_size": -1, - "metadata": {}, - "min_size": 0, - "name": "test_cluster", - "profile_id": "mystack", - "timeout": None - } - - def setUp(self): - super(TestClusterCreate, self).setUp() - self.cmd = osc_cluster.CreateCluster(self.app, None) - self.cluster_id = '7d85f602-a948-4a30-afd4-e84f47471c15' - fake_cluster = mock.Mock( - config={}, - created_at="2015-02-11T15:13:20", - data={}, - desired_capacity=0, - domain_id=None, - id=self.cluster_id, - init_time="2015-02-10T14:26:11", - max_size=-1, - metadata={}, - min_size=0, - node_ids=[], - policies=[], - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - status="ACTIVE", - status_reason="Cluster scale-in succeeded", - timeout=3600, - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_cluster.name = "my_cluster" - fake_cluster.to_dict = mock.Mock(return_value={}) - self.mock_client.create_cluster = mock.Mock(return_value=fake_cluster) - self.mock_client.get_cluster = mock.Mock(return_value=fake_cluster) - - def test_cluster_create_defaults(self): - arglist = ['test_cluster', '--profile', 'mystack'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_cluster.assert_called_with(**self.defaults) - - def test_cluster_create_with_metadata(self): - arglist = ['test_cluster', '--profile', 'mystack', - '--metadata', 'key1=value1;key2=value2'] - kwargs = copy.deepcopy(self.defaults) - kwargs['metadata'] = {'key1': 'value1', 'key2': 'value2'} - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_cluster.assert_called_with(**kwargs) - - def test_cluster_create_with_config(self): - arglist = ['test_cluster', '--profile', 'mystack', - '--config', 'key1=value1;key2=value2'] - kwargs = copy.deepcopy(self.defaults) - kwargs['config'] = {'key1': 'value1', 'key2': 'value2'} - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_cluster.assert_called_with(**kwargs) - - def test_cluster_create_with_size(self): - arglist = ['test_cluster', '--profile', 'mystack', - '--min-size', '1', '--max-size', '10', - '--desired-capacity', '2'] - kwargs = copy.deepcopy(self.defaults) - kwargs['min_size'] = '1' - kwargs['max_size'] = '10' - kwargs['desired_capacity'] = '2' - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_cluster.assert_called_with(**kwargs) - - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_create_with_wait(self, mock_await): - arglist = ['test_cluster', '--profile', 'mystack', - '--min-size', '1', '--max-size', '10', - '--desired-capacity', '2', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await.assert_called_once_with(self.mock_client, self.cluster_id) - - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_create_without_wait(self, mock_await): - arglist = ['test_cluster', '--profile', 'mystack', - '--min-size', '1', '--max-size', '10', - '--desired-capacity', '2'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await.assert_not_called() - - -class TestClusterUpdate(TestCluster): - - defaults = { - "metadata": { - "nk1": "nv1", - "nk2": "nv2", - }, - "config": { - "cluster.stop_node_before_delete": "true", - }, - "name": 'new_cluster', - "profile_id": 'new_profile', - "profile_only": False, - "timeout": "30" - } - - def setUp(self): - super(TestClusterUpdate, self).setUp() - self.cmd = osc_cluster.UpdateCluster(self.app, None) - self.fake_cluster = mock.Mock( - created_at="2015-02-11T15:13:20", - data={}, - desired_capacity=0, - domain_id=None, - id="7d85f602-a948-4a30-afd4-e84f47471c15", - init_time="2015-02-10T14:26:11", - max_size=-1, - metadata={}, - min_size=0, - node_ids=[], - policies=[], - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - status="ACTIVE", - status_reason="Cluster scale-in succeeded", - timeout=3600, - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - self.fake_cluster.name = "my_cluster" - self.fake_cluster.to_dict = mock.Mock(return_value={}) - self.mock_client.update_cluster = mock.Mock( - return_value=self.fake_cluster) - self.mock_client.get_cluster = mock.Mock( - return_value=self.fake_cluster) - self.mock_client.find_cluster = mock.Mock( - return_value=self.fake_cluster) - - def test_cluster_update_defaults(self): - arglist = ['--name', 'new_cluster', '--metadata', 'nk1=nv1;nk2=nv2', - '--config', 'cluster.stop_node_before_delete=true', - '--profile', 'new_profile', '--timeout', '30', '45edadcb'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.update_cluster.assert_called_with( - self.fake_cluster, **self.defaults) - - def test_cluster_update_not_found(self): - arglist = ['--name', 'new_cluster', '--metadata', 'nk1=nv1;nk2=nv2', - '--profile', 'new_profile', 'c6b8b252'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.find_cluster.return_value = None - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertIn('Cluster not found: c6b8b252', str(error)) - - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_update_with_wait(self, mock_await): - arglist = ['--name', 'new_cluster', '--metadata', 'nk1=nv1;nk2=nv2', - '--profile', 'new_profile', '--timeout', '30', '45edadcb', - '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await.assert_called_once_with(self.mock_client, - self.fake_cluster.id) - - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_update_without_wait(self, mock_await): - arglist = ['--name', 'new_cluster', '--metadata', 'nk1=nv1;nk2=nv2', - '--profile', 'new_profile', '--timeout', '30', '45edadcb'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await.assert_not_called() - - -class TestClusterDelete(TestCluster): - def setUp(self): - super(TestClusterDelete, self).setUp() - self.cmd = osc_cluster.DeleteCluster(self.app, None) - mock_cluster = mock.Mock(location='abc/fake_action_id') - self.mock_client.delete_cluster = mock.Mock(return_value=mock_cluster) - - def test_cluster_delete(self): - arglist = ['cluster1', 'cluster2', 'cluster3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_cluster.assert_has_calls( - [mock.call('cluster1', False, False), - mock.call('cluster2', False, False), - mock.call('cluster3', False, False)] - ) - - def test_cluster_delete_force(self): - arglist = ['cluster1', 'cluster2', 'cluster3', '--force'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_cluster.assert_has_calls( - [mock.call('cluster1', False, False), - mock.call('cluster2', False, False), - mock.call('cluster3', False, False)] - ) - - def test_cluster_delete_force_delete(self): - arglist = ['cluster1', 'cluster2', 'cluster3', '--force-delete'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_cluster.assert_has_calls( - [mock.call('cluster1', False, True), - mock.call('cluster2', False, True), - mock.call('cluster3', False, True)] - ) - - def test_cluster_delete_not_found(self): - arglist = ['my_cluster'] - self.mock_client.delete_cluster.side_effect = sdk_exc.ResourceNotFound - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.delete_cluster.assert_has_calls( - [mock.call('my_cluster', False, False)] - ) - - def test_cluster_delete_one_found_one_not_found(self): - arglist = ['cluster1', 'cluster2'] - self.mock_client.delete_cluster.side_effect = ( - [None, sdk_exc.ResourceNotFound] - ) - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.delete_cluster.assert_has_calls( - [mock.call('cluster1', False, False), - mock.call('cluster2', False, False)] - ) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_cluster_delete_prompt_yes(self, mock_stdin): - arglist = ['my_cluster'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'y' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_cluster.assert_called_with( - 'my_cluster', False, False) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_cluster_delete_prompt_no(self, mock_stdin): - arglist = ['my_cluster'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'n' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_cluster.assert_not_called() - - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_delete') - def test_cluster_delete_with_wait(self, mock_await_cluster, - mock_await_action): - fake_action = {'id': 'fake-action-id'} - self.mock_client.delete_cluster = mock.Mock(return_value=fake_action) - arglist = ['my_cluster', '--force', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_called_once_with(self.mock_client, - fake_action['id']) - mock_await_cluster.assert_called_once_with(self.mock_client, - 'my_cluster') - - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_delete') - def test_cluster_delete_without_wait(self, mock_await_cluster, - mock_await_action): - fake_action = {'id': 'fake-action-id'} - self.mock_client.delete_cluster = mock.Mock(return_value=fake_action) - arglist = ['my_cluster', '--force'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_cluster.assert_not_called() - - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_delete') - def test_cluster_delete_with_wait_bad_action(self, mock_await_cluster, - mock_await_action): - self.mock_client.delete_cluster.side_effect = ( - Exception('test exception') - ) - arglist = ['my_cluster', '--force', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_cluster.assert_not_called() - - -class TestClusterResize(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - defaults = { - "min_step": None, - "adjustment_type": "EXACT_CAPACITY", - "number": 2, - "min_size": 1, - "strict": True, - "max_size": 20} - - def setUp(self): - super(TestClusterResize, self).setUp() - self.cmd = osc_cluster.ResizeCluster(self.app, None) - self.mock_client.resize_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_resize_no_params(self): - arglist = ['my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual(("At least one parameter of 'capacity', " - "'adjustment', 'percentage', 'min_size' and " - "'max_size' should be specified."), str(error)) - - def test_cluster_resize_multi_params(self): - arglist = ['--capacity', '2', '--percentage', '50.0', '--adjustment', - '1', '--min-size', '1', '--max-size', '20', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual("Only one of 'capacity', 'adjustment' " - "and 'percentage' can be specified.", str(error)) - - def test_cluster_resize_capacity(self): - arglist = ['--capacity', '2', '--min-size', '1', '--max-size', '20', - 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.resize_cluster.assert_called_with('my_cluster', - **self.defaults) - - def test_cluster_resize_invalid_capacity(self): - arglist = ['--capacity', '-1', '--min-size', '1', '--max-size', '20', - 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual('Cluster capacity must be larger than or equal to' - ' zero.', str(error)) - - def test_cluster_resize_adjustment(self): - arglist = ['--adjustment', '1', '--min-size', '1', '--max-size', '20', - 'my_cluster', '--strict'] - kwargs = copy.deepcopy(self.defaults) - kwargs['adjustment_type'] = 'CHANGE_IN_CAPACITY' - kwargs['number'] = 1 - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.resize_cluster.assert_called_with('my_cluster', - **kwargs) - - def test_cluster_resize_invalid_adjustment(self): - arglist = ['--adjustment', '0', '--min-size', '1', '--max-size', '20', - 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual('Adjustment cannot be zero.', str(error)) - - def test_cluster_resize_percentage(self): - arglist = ['--percentage', '50.0', '--min-size', '1', '--max-size', - '20', 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - kwargs = copy.deepcopy(self.defaults) - kwargs['adjustment_type'] = 'CHANGE_IN_PERCENTAGE' - kwargs['number'] = 50.0 - self.cmd.take_action(parsed_args) - self.mock_client.resize_cluster.assert_called_with('my_cluster', - **kwargs) - - def test_cluster_resize_invalid_percentage(self): - arglist = ['--percentage', '0', '--min-size', '1', '--max-size', '20', - 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual('Percentage cannot be zero.', str(error)) - - def test_cluster_resize_invalid_min_step_capacity(self): - arglist = ['--capacity', '2', '--min-size', '1', '--max-size', '20', - 'my_cluster', '--strict', '--min-step', '1'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual('Min step is only used with percentage.', str(error)) - - def test_cluster_resize_invalid_min_size_capacity(self): - arglist = ['--capacity', '2', '--min-size', '-1', '--max-size', '20', - 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual('Min size cannot be less than zero.', str(error)) - - def test_cluster_resize_invalid_max_size_capacity(self): - arglist = ['--capacity', '2', '--min-size', '5', '--max-size', '3', - 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual('Min size cannot be larger than max size.', - str(error)) - - def test_cluster_resize_min_size_larger_than_capacity(self): - arglist = ['--capacity', '3', '--min-size', '5', '--max-size', '10', - 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual('Min size cannot be larger than the specified ' - 'capacity', str(error)) - - def test_cluster_resize_invalid_max_size_less_capacity(self): - arglist = ['--capacity', '15', '--min-size', '5', '--max-size', '10', - 'my_cluster', '--strict'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertEqual('Max size cannot be less than the specified ' - 'capacity.', str(error)) - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_resize_with_wait(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--capacity', '2', 'my_cluster', "--wait"] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_called_once_with(self.mock_client, - self.response['action']) - mock_await_status.assert_called_once_with(self.mock_client, - 'my_cluster') - mock_show.assert_called_once() - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_resize_without_wait(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--capacity', '2', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_show.assert_not_called() - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_resize_with_wait_no_action(self, mock_await_status, - mock_await_action, mock_show): - error = 'test error' - self.mock_client.resize_cluster = mock.Mock(return_value=error) - arglist = ['--capacity', '2', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_show.assert_not_called() - - -class TestClusterScaleIn(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestClusterScaleIn, self).setUp() - self.cmd = osc_cluster.ScaleInCluster(self.app, None) - self.mock_client.scale_in_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_scale_in(self): - arglist = ['--count', '2', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.scale_in_cluster.assert_called_with('my_cluster', - '2') - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_scale_in_with_wait(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--count', '2', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_called_once_with(self.mock_client, - self.response['action']) - mock_await_status.assert_called_once_with(self.mock_client, - 'my_cluster') - mock_show.assert_called_once() - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_scale_in_without_wait(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--count', '2', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_show.assert_not_called() - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_scale_in_with_wait_no_action(self, mock_await_status, - mock_await_action, - mock_show): - arglist = ['--count', '2', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.scale_in_cluster = mock.Mock(return_value=error) - - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_show.assert_not_called() - - -class TestClusterScaleOut(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestClusterScaleOut, self).setUp() - self.cmd = osc_cluster.ScaleOutCluster(self.app, None) - self.mock_client.scale_out_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_scale_out(self): - arglist = ['--count', '2', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.scale_out_cluster.assert_called_with('my_cluster', - '2') - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_scale_out_with_wait(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--count', '2', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_called_once_with(self.mock_client, - self.response['action']) - mock_await_status.assert_called_once_with(self.mock_client, - 'my_cluster') - mock_show.assert_called_once() - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_scale_out_without_wait(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--count', '2', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_show.assert_not_called() - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_scale_out_with_wait_no_action(self, mock_await_status, - mock_await_action, - mock_show): - arglist = ['--count', '2', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.scale_out_cluster = mock.Mock(return_value=error) - - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_show.assert_not_called() - - -class TestClusterPolicyAttach(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestClusterPolicyAttach, self).setUp() - self.cmd = osc_cluster.ClusterPolicyAttach(self.app, None) - self.mock_client.attach_policy_to_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_policy_attach(self): - arglist = ['--policy', 'my_policy', '--enabled', 'True', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.attach_policy_to_cluster.assert_called_with( - 'my_cluster', - 'my_policy', - enabled=True) - - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_policy_attach_with_wait(self, mock_await_action): - arglist = ['--policy', 'my_policy', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_called_once_with(self.mock_client, - self.response['action']) - - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_policy_attach_without_wait(self, mock_await_action): - arglist = ['--policy', 'my_policy', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_policy_attach_with_wait_no_action(self, - mock_await_action): - arglist = ['--policy', 'my_policy', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.attach_policy_to_cluster = \ - mock.Mock(return_value=error) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - - -class TestClusterPolicyDetach(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestClusterPolicyDetach, self).setUp() - self.cmd = osc_cluster.ClusterPolicyDetach(self.app, None) - self.mock_client.detach_policy_from_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_policy_detach(self): - arglist = ['--policy', 'my_policy', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.detach_policy_from_cluster.assert_called_with( - 'my_cluster', - 'my_policy') - - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_policy_dettach_with_wait(self, mock_await_action): - arglist = ['--policy', 'my_policy', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_called_once_with(self.mock_client, - self.response['action']) - - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_policy_dettach_without_wait(self, mock_await_action): - arglist = ['--policy', 'my_policy', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_policy_dettach_with_wait_no_action(self, - mock_await_action): - arglist = ['--policy', 'my_policy', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.detach_policy_from_cluster = \ - mock.Mock(return_value=error) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - - -class TestClusterNodeList(TestCluster): - columns = ['id', 'name', 'index', 'status', 'physical_id', 'created_at'] - args = { - 'cluster_id': 'my_cluster', - 'marker': 'a9448bf6', - 'limit': '3', - 'sort': None, - } - - def setUp(self): - super(TestClusterNodeList, self).setUp() - self.cmd = osc_cluster.ClusterNodeList(self.app, None) - fake_node = mock.Mock( - cluster_id="", - created_at="2015-02-11T15:13:20", - data={}, - details={}, - domain_id=None, - id="7d85f602-a948-4a30-afd4-e84f47471c15", - index=-1, - init_at="2015-02-10T14:26:11", - metadata={}, - phyiscal_id="cc028275-d078-4729-bf3e-154b7359814b", - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - status="ACTIVE", - status_reason="Creation succeeded", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_node.name = "node001" - fake_node.to_dict = mock.Mock(return_value={}) - self.mock_client.nodes = mock.Mock(return_value=[fake_node]) - - def test_cluster_node_list(self): - arglist = ['--limit', '3', '--marker', 'a9448bf6', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**self.args) - self.assertEqual(self.columns, columns) - - def test_cluster_node_list_full_id(self): - arglist = ['--limit', '3', '--marker', 'a9448bf6', 'my_cluster', - '--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**self.args) - self.assertEqual(self.columns, columns) - - def test_cluster_node_list_filter(self): - kwargs = copy.deepcopy(self.args) - kwargs['name'] = 'my_node' - arglist = ['--limit', '3', '--marker', 'a9448bf6', 'my_cluster', - '--filter', 'name=my_node'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_cluster_node_list_sort(self): - kwargs = copy.deepcopy(self.args) - kwargs['name'] = 'my_node' - kwargs['sort'] = 'name:asc' - arglist = ['--limit', '3', '--marker', 'a9448bf6', 'my_cluster', - '--filter', 'name=my_node', '--sort', 'name:asc'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - -class TestClusterNodeAdd(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestClusterNodeAdd, self).setUp() - self.cmd = osc_cluster.ClusterNodeAdd(self.app, None) - self.mock_client.add_nodes_to_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_node_add(self): - arglist = ['--nodes', 'node1', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.add_nodes_to_cluster.assert_called_with( - 'my_cluster', - ['node1']) - - def test_cluster_node_add_multi(self): - arglist = ['--nodes', 'node1,node2', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.add_nodes_to_cluster.assert_called_with( - 'my_cluster', - ['node1', 'node2']) - - @mock.patch.object(osc_cluster, "_show_cluster") - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_node_add_with_wait(self, mock_await_action, mock_show): - arglist = ['--nodes', 'node1', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_called_once_with(self.mock_client, - self.response['action']) - mock_show.assert_called_once_with(self.mock_client, 'my_cluster') - - @mock.patch.object(osc_cluster, "_show_cluster") - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_node_add_without_wait(self, mock_await_action, mock_show): - arglist = ['--nodes', 'node1', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_not_called() - mock_show.assert_not_called() - - @mock.patch.object(osc_cluster, "_show_cluster") - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_node_add_with_wait_no_action(self, mock_await_action, - mock_show): - arglist = ['--nodes', 'node1', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.add_nodes_to_cluster = mock.Mock(return_value=error) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_not_called() - mock_show.assert_not_called() - - -class TestClusterNodeDel(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestClusterNodeDel, self).setUp() - self.cmd = osc_cluster.ClusterNodeDel(self.app, None) - self.mock_client.remove_nodes_from_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_node_delete(self): - arglist = ['-d', 'True', '--nodes', 'node1', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.remove_nodes_from_cluster.assert_called_with( - 'my_cluster', - ['node1'], - destroy_after_deletion=True) - - def test_cluster_node_delete_without_destroy(self): - arglist = ['-d', 'False', '--nodes', 'node1', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.remove_nodes_from_cluster.assert_called_with( - 'my_cluster', - ['node1'], - destroy_after_deletion=False) - - def test_cluster_node_delete_multi(self): - arglist = ['--nodes', 'node1,node2', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.remove_nodes_from_cluster.assert_called_with( - 'my_cluster', - ['node1', 'node2'], - destroy_after_deletion=False) - - @mock.patch.object(osc_cluster, "_show_cluster") - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_node_delete_with_wait(self, mock_await_action, mock_show): - arglist = ['--nodes', 'node1', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_called_once_with(self.mock_client, - self.response['action']) - mock_show.assert_called_once_with(self.mock_client, 'my_cluster') - - @mock.patch.object(osc_cluster, "_show_cluster") - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_node_delete_without_wait(self, mock_await_action, - mock_show): - arglist = ['--nodes', 'node1', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_not_called() - mock_show.assert_not_called() - - @mock.patch.object(osc_cluster, "_show_cluster") - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_node_delete_with_wait_no_action(self, mock_await_action, - mock_show): - arglist = ['--nodes', 'node1', 'my_cluster', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.remove_nodes_from_cluster = \ - mock.Mock(return_value=error) - - self.cmd.take_action(parsed_args) - - mock_await_action.assert_not_called() - mock_show.assert_not_called() - - -class TestClusterCheck(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestClusterCheck, self).setUp() - self.cmd = osc_cluster.CheckCluster(self.app, None) - self.mock_client.check_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_check(self): - arglist = ['cluster1', 'cluster2', 'cluster3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.check_cluster.assert_has_calls( - [mock.call('cluster1'), mock.call('cluster2'), - mock.call('cluster3')] - ) - - def test_cluster_check_not_found(self): - arglist = ['cluster1'] - self.mock_client.check_cluster.side_effect = sdk_exc.ResourceNotFound - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Cluster not found: cluster1', str(error)) - - @mock.patch.object(osc_cluster, "_list_cluster_summaries") - @mock.patch.object(senlin_utils, 'await_cluster_status') - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_check_with_wait(self, mock_await_action, - mock_await_status, mock_list): - arglist = ['cluster1', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_called_with(self.mock_client, - self.response['action']) - mock_await_status.assert_called_with(self.mock_client, 'cluster1') - mock_list.assert_called_with(self.mock_client, {'cluster1'}) - - @mock.patch.object(osc_cluster, "_list_cluster_summaries") - @mock.patch.object(senlin_utils, 'await_cluster_status') - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_check_without_wait(self, mock_await_action, - mock_await_status, mock_list): - arglist = ['cluster1'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_list.assert_not_called() - - @mock.patch.object(osc_cluster, "_list_cluster_summaries") - @mock.patch.object(senlin_utils, 'await_cluster_status') - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_check_with_wait_no_action(self, mock_await_action, - mock_await_status, mock_list): - arglist = ['cluster1', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.check_cluster = mock.Mock(return_value=error) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_list.assert_not_called() - - -class TestClusterRecover(TestCluster): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestClusterRecover, self).setUp() - self.cmd = osc_cluster.RecoverCluster(self.app, None) - self.mock_client.recover_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_recover(self): - arglist = ['cluster1', 'cluster2', 'cluster3', '--check', 'false'] - kwargs = {'check': False} - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.recover_cluster.assert_has_calls( - [mock.call('cluster1', **kwargs), mock.call('cluster2', **kwargs), - mock.call('cluster3', **kwargs)] - ) - - def test_cluster_recover_not_found(self): - arglist = ['cluster1'] - self.mock_client.recover_cluster.side_effect = sdk_exc.ResourceNotFound - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Cluster not found: cluster1', str(error)) - - @mock.patch.object(osc_cluster, "_list_cluster_summaries") - @mock.patch.object(senlin_utils, 'await_cluster_status') - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_recover_with_wait(self, mock_await_action, - mock_await_status, mock_list): - arglist = ['cluster1', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_called_with(self.mock_client, - self.response['action']) - mock_await_status.assert_called_with(self.mock_client, 'cluster1') - mock_list.assert_called_with(self.mock_client, {'cluster1'}) - - @mock.patch.object(osc_cluster, "_list_cluster_summaries") - @mock.patch.object(senlin_utils, 'await_cluster_status') - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_recover_without_wait(self, mock_await_action, - mock_await_status, mock_list): - arglist = ['cluster1'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_list.assert_not_called() - - @mock.patch.object(osc_cluster, "_list_cluster_summaries") - @mock.patch.object(senlin_utils, 'await_cluster_status') - @mock.patch.object(senlin_utils, 'await_action') - def test_cluster_recover_with_wait_no_action(self, mock_await_action, - mock_await_status, mock_list): - arglist = ['cluster1', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.recover_cluster = mock.Mock(return_value=error) - self.cmd.take_action(parsed_args) - - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_list.assert_not_called() - - -class TestClusterOp(TestCluster): - - response = {"action": "a3c6d04c-3fca-4e4a-b0b3-c0522ef711f1"} - - def setUp(self): - super(TestClusterOp, self).setUp() - self.cmd = osc_cluster.ClusterOp(self.app, None) - self.mock_client.perform_operation_on_cluster = mock.Mock( - return_value=self.response) - - def test_cluster_op(self): - arglist = ['--operation', 'dance', '--params', 'style=tango', - 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.perform_operation_on_cluster.assert_called_once_with( - 'my_cluster', - 'dance', - style='tango') - - def test_cluster_op_not_found(self): - arglist = ['--operation', 'dance', 'cluster1'] - ex = sdk_exc.ResourceNotFound - self.mock_client.perform_operation_on_cluster.side_effect = ex - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Cluster not found: cluster1', str(error)) - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_op_with_wait(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--operation', 'dance', 'cluster1', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_called_once_with(self.mock_client, - self.response['action']) - mock_await_status.assert_called_once_with(self.mock_client, - 'cluster1') - mock_show.assert_called_once() - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_op_without_wait(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--operation', 'dance', 'cluster1'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_show.assert_not_called() - - @mock.patch.object(osc_cluster, '_show_cluster') - @mock.patch.object(senlin_utils, 'await_action') - @mock.patch.object(senlin_utils, 'await_cluster_status') - def test_cluster_op_with_wait_no_action(self, mock_await_status, - mock_await_action, mock_show): - arglist = ['--operation', 'dance', 'cluster1', '--wait'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = {'error': 'test-error'} - self.mock_client.perform_operation_on_cluster = \ - mock.Mock(return_value=error) - - self.cmd.take_action(parsed_args) - mock_await_action.assert_not_called() - mock_await_status.assert_not_called() - mock_show.assert_not_called() - - -class TestClusterCollect(TestCluster): - response = [ - { - "node_id": "8bb476c3-0f4c-44ee-9f64-c7b0260814de", - "attr_value": "value 1", - }, - { - "node_id": "7d85f602-a948-4a30-afd4-e84f47471c15", - "attr_value": "value 2", - } - ] - - def setUp(self): - super(TestClusterCollect, self).setUp() - self.cmd = osc_cluster.ClusterCollect(self.app, None) - self.mock_client.collect_cluster_attrs = mock.Mock( - return_value=self.response) - - def test_cluster_collect(self): - arglist = ['--path', 'path.to.attr', 'cluster1'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.collect_cluster_attrs.assert_called_once_with( - 'cluster1', 'path.to.attr') - self.assertEqual(['node_id', 'attr_value'], columns) - - def test_cluster_collect_with_full_id(self): - arglist = ['--path', 'path.to.attr', '--full-id', 'cluster1'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.collect_cluster_attrs.assert_called_once_with( - 'cluster1', 'path.to.attr') - self.assertEqual(['node_id', 'attr_value'], columns) - - -class TestClusterRun(TestCluster): - attrs = [ - mock.Mock(node_id="NODE_ID1", - attr_value={"addresses": 'ADDRESS CONTENT 1'}), - mock.Mock(node_id="NODE_ID2", - attr_value={"addresses": 'ADDRESS CONTENT 2'}) - ] - - def setUp(self): - super(TestClusterRun, self).setUp() - self.cmd = osc_cluster.ClusterRun(self.app, None) - self.mock_client.collect_cluster_attrs = mock.Mock( - return_value=self.attrs) - - @mock.patch('subprocess.Popen') - def test__run_script(self, mock_proc): - x_proc = mock.Mock(returncode=0) - x_stdout = 'OUTPUT' - x_stderr = 'ERROR' - x_proc.communicate.return_value = (x_stdout, x_stderr) - mock_proc.return_value = x_proc - - addr = { - 'private': [ - { - 'OS-EXT-IPS:type': 'floating', - 'version': 4, - 'addr': '1.2.3.4', - } - ] - } - output = {} - - self.cmd._run_script('NODE_ID', addr, 'private', 'floating', 22, - 'john', False, 'identity_path', 'echo foo', - '-f bar', - output=output) - mock_proc.assert_called_once_with( - ['ssh', '-4', '-p22', '-i identity_path', '-f bar', 'john@1.2.3.4', - 'echo foo'], - stdout=subprocess.PIPE) - self.assertEqual( - {'status': 'SUCCEEDED (0)', 'output': 'OUTPUT', 'error': 'ERROR'}, - output) - - def test__run_script_network_not_found(self): - addr = {'foo': 'bar'} - output = {} - - self.cmd._run_script('NODE_ID', addr, 'private', 'floating', 22, - 'john', False, 'identity_path', 'echo foo', - '-f bar', - output=output) - self.assertEqual( - {'status': 'FAILED', - 'error': "Node 'NODE_ID' is not attached to network 'private'." - }, - output) - - def test__run_script_more_than_one_network(self): - addr = {'foo': 'bar', 'koo': 'tar'} - output = {} - - self.cmd._run_script('NODE_ID', addr, '', 'floating', 22, 'john', - False, 'identity_path', 'echo foo', '-f bar', - output=output) - self.assertEqual( - {'status': 'FAILED', - 'error': "Node 'NODE_ID' is attached to more than one " - "network. Please pick the network to use."}, - output) - - def test__run_script_no_network(self): - addr = {} - output = {} - - self.cmd._run_script('NODE_ID', addr, '', 'floating', 22, 'john', - False, 'identity_path', 'echo foo', '-f bar', - output=output) - - self.assertEqual( - {'status': 'FAILED', - 'error': "Node 'NODE_ID' is not attached to any network."}, - output) - - def test__run_script_no_matching_address(self): - addr = { - 'private': [ - { - 'OS-EXT-IPS:type': 'fixed', - 'version': 4, - 'addr': '1.2.3.4', - } - ] - } - output = {} - - self.cmd._run_script('NODE_ID', addr, 'private', 'floating', 22, - 'john', False, 'identity_path', 'echo foo', - '-f bar', - output=output) - self.assertEqual( - {'status': 'FAILED', - 'error': "No address that matches network 'private' and " - "type 'floating' of IPv4 has been found for node " - "'NODE_ID'."}, - output) - - def test__run_script_more_than_one_address(self): - addr = { - 'private': [ - { - 'OS-EXT-IPS:type': 'fixed', - 'version': 4, - 'addr': '1.2.3.4', - }, - { - 'OS-EXT-IPS:type': 'fixed', - 'version': 4, - 'addr': '5.6.7.8', - }, - ] - } - - output = {} - - self.cmd._run_script('NODE_ID', addr, 'private', 'fixed', 22, 'john', - False, 'identity_path', 'echo foo', '-f bar', - output=output) - self.assertEqual( - {'status': 'FAILED', - 'error': "More than one IPv4 fixed address found."}, - output) - - @mock.patch('threading.Thread') - @mock.patch.object(osc_cluster.ClusterRun, '_run_script') - def test_cluster_run(self, mock_script, mock_thread): - arglist = [ - '--port', '22', - '--address-type', 'fixed', - '--network', 'private', - '--user', 'root', - '--identity-file', 'path-to-identity', - '--ssh-options', '-f boo', - '--script', 'script-file', - 'cluster1' - ] - parsed_args = self.check_parser(self.cmd, arglist, []) - - th1 = mock.Mock() - th2 = mock.Mock() - mock_thread.side_effect = [th1, th2] - fake_script = 'blah blah' - with mock.patch('senlinclient.v1.cluster.open', - mock.mock_open(read_data=fake_script)) as mock_open: - self.cmd.take_action(parsed_args) - - self.mock_client.collect_cluster_attrs.assert_called_once_with( - 'cluster1', 'details') - mock_open.assert_called_once_with('script-file', 'r') - mock_thread.assert_has_calls([ - mock.call(target=mock_script, - args=('NODE_ID1', 'ADDRESS CONTENT 1', 'private', - 'fixed', 22, 'root', False, 'path-to-identity', - 'blah blah', '-f boo'), - kwargs={'output': {}}), - mock.call(target=mock_script, - args=('NODE_ID2', 'ADDRESS CONTENT 2', 'private', - 'fixed', 22, 'root', False, 'path-to-identity', - 'blah blah', '-f boo'), - kwargs={'output': {}}) - ]) - th1.start.assert_called_once_with() - th2.start.assert_called_once_with() - th1.join.assert_called_once_with() - th2.join.assert_called_once_with() diff --git a/senlinclient/tests/unit/v1/test_cluster_policy.py b/senlinclient/tests/unit/v1/test_cluster_policy.py deleted file mode 100644 index 57da3589..00000000 --- a/senlinclient/tests/unit/v1/test_cluster_policy.py +++ /dev/null @@ -1,100 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import cluster_policy as osc_cluster_policy - - -class TestClusterPolicy(fakes.TestClusteringv1): - def setUp(self): - super(TestClusterPolicy, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestClusterPolicyList(TestClusterPolicy): - - def setUp(self): - super(TestClusterPolicyList, self).setUp() - self.cmd = osc_cluster_policy.ClusterPolicyList(self.app, None) - fake_cluster = mock.Mock(id='C1') - self.mock_client.get_cluster = mock.Mock(return_value=fake_cluster) - fake_binding = mock.Mock( - cluster_id="7d85f602-a948-4a30-afd4-e84f47471c15", - cluster_name="my_cluster", - is_enabled=True, - id="06be3a1f-b238-4a96-a737-ceec5714087e", - policy_id="714fe676-a08f-4196-b7af-61d52eeded15", - policy_name="my_policy", - policy_type="senlin.policy.deletion-1.0" - ) - fake_binding.to_dict = mock.Mock(return_value={}) - self.mock_client.cluster_policies = mock.Mock( - return_value=[fake_binding]) - - def test_cluster_policy_list(self): - arglist = ['--sort', 'name:asc', '--filter', 'name=my_policy', - 'my_cluster', '--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - expected_columns = ['policy_id', 'policy_name', 'policy_type', - 'is_enabled'] - - columns, data = self.cmd.take_action(parsed_args) - - self.mock_client.get_cluster.assert_called_with('my_cluster') - self.mock_client.cluster_policies.assert_called_with( - 'C1', name="my_policy", sort="name:asc") - self.assertEqual(expected_columns, columns) - - -class TestClusterPolicyShow(TestClusterPolicy): - - def setUp(self): - super(TestClusterPolicyShow, self).setUp() - self.cmd = osc_cluster_policy.ClusterPolicyShow(self.app, None) - fake_binding = mock.Mock( - cluster_id="7d85f602-a948-4a30-afd4-e84f47471c15", - cluster_name="my_cluster", - is_enabled=True, - id="06be3a1f-b238-4a96-a737-ceec5714087e", - policy_id="714fe676-a08f-4196-b7af-61d52eeded15", - policy_name="my_policy", - policy_type="senlin.policy.deletion-1.0" - ) - fake_binding.to_dict = mock.Mock(return_value={}) - self.mock_client.get_cluster_policy = mock.Mock( - return_value=fake_binding) - - def test_cluster_policy_show(self): - arglist = ['--policy', 'my_policy', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_cluster_policy.assert_called_with('my_policy', - 'my_cluster') - - -class TestClusterPolicyUpdate(TestClusterPolicy): - - def setUp(self): - super(TestClusterPolicyUpdate, self).setUp() - self.cmd = osc_cluster_policy.ClusterPolicyUpdate(self.app, None) - fake_resp = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - self.mock_client.update_cluster_policy = mock.Mock( - return_value=fake_resp) - - def test_cluster_policy_update(self): - arglist = ['--policy', 'my_policy', '--enabled', 'true', 'my_cluster'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.update_cluster_policy.assert_called_with( - 'my_cluster', 'my_policy', enabled=True) diff --git a/senlinclient/tests/unit/v1/test_event.py b/senlinclient/tests/unit/v1/test_event.py deleted file mode 100644 index 92345d28..00000000 --- a/senlinclient/tests/unit/v1/test_event.py +++ /dev/null @@ -1,165 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -from unittest import mock - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import event as osc_event - - -class TestEvent(fakes.TestClusteringv1): - def setUp(self): - super(TestEvent, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestEventList(TestEvent): - - columns = ['id', 'generated_at', 'obj_type', 'obj_id', 'obj_name', - 'action', 'status', 'level', 'cluster_id', 'meta_data'] - defaults = { - 'global_project': False, - 'marker': None, - 'limit': None, - 'sort': None, - } - - def setUp(self): - super(TestEventList, self).setUp() - self.cmd = osc_event.ListEvent(self.app, None) - fake_event = mock.Mock( - action="CREATE", - cluster_id=None, - id="2d255b9c-8f36-41a2-a137-c0175ccc29c3", - level="20", - obj_id="0df0931b-e251-4f2e-8719-4ebfda3627ba", - obj_name="node009", - obj_type="NODE", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - status="CREATING", - generated_at="2015-03-05T08:53:15", - user_id="a21ded6060534d99840658a777c2af5a" - ) - fake_event.to_dict = mock.Mock(return_value={}) - self.mock_client.events = mock.Mock(return_value=[fake_event]) - - def test_event_list_defaults(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.events.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_event_list_full_id(self): - arglist = ['--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.events.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_event_list_limit(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['limit'] = '3' - arglist = ['--limit', '3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.events.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_event_list_sort(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:asc' - arglist = ['--sort', 'name:asc'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.events.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_event_list_sort_invalid_key(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'bad_key' - arglist = ['--sort', 'bad_key'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.events.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_event_list_sort_invalid_direction(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:bad_direction' - arglist = ['--sort', 'name:bad_direction'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.events.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_event_list_filter(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['name'] = 'my_event' - arglist = ['--filter', 'name=my_event'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.events.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_event_list_marker(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['marker'] = 'a9448bf6' - arglist = ['--marker', 'a9448bf6'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.events.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - -class TestEventShow(TestEvent): - - def setUp(self): - super(TestEventShow, self).setUp() - self.cmd = osc_event.ShowEvent(self.app, None) - fake_event = mock.Mock( - action="CREATE", - cluster_id=None, - id="2d255b9c-8f36-41a2-a137-c0175ccc29c3", - level="20", - obj_id="0df0931b-e251-4f2e-8719-4ebfda3627ba", - obj_name="node009", - obj_type="NODE", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - status="CREATING", - generated_at="2015-03-05T08:53:15", - user_id="a21ded6060534d99840658a777c2af5a" - ) - fake_event.to_dict = mock.Mock(return_value={}) - self.mock_client.get_event = mock.Mock(return_value=fake_event) - - def test_event_show(self): - arglist = ['my_event'] - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.get_event.assert_called_with('my_event') - - def test_event_show_not_found(self): - arglist = ['my_event'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_event.side_effect = sdk_exc.ResourceNotFound() - - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - - self.assertEqual('Event not found: my_event', str(error)) diff --git a/senlinclient/tests/unit/v1/test_node.py b/senlinclient/tests/unit/v1/test_node.py deleted file mode 100644 index 971ac5f3..00000000 --- a/senlinclient/tests/unit/v1/test_node.py +++ /dev/null @@ -1,658 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import io -from unittest import mock - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import node as osc_node - - -class TestNode(fakes.TestClusteringv1): - def setUp(self): - super(TestNode, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestNodeList(TestNode): - - columns = ['id', 'name', 'index', 'status', 'cluster_id', - 'physical_id', 'profile_name', 'created_at', 'updated_at', - 'tainted'] - - defaults = { - 'cluster_id': None, - 'global_project': False, - 'marker': None, - 'limit': None, - 'sort': None, - } - - def setUp(self): - super(TestNodeList, self).setUp() - self.cmd = osc_node.ListNode(self.app, None) - fake_node = mock.Mock( - cluster_id=None, - created_at="2015-02-27T04:39:21", - data={}, - details={}, - domain=None, - id="573aa1ba-bf45-49fd-907d-6b5d6e6adfd3", - index=-1, - init_at="2015-02-27T04:39:18", - metadata={}, - physical_id="cc028275-d078-4729-bf3e-154b7359814b", - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - role=None, - status="ACTIVE", - status_reason="Creation succeeded", - tainted=True, - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_node.name = "node00a" - fake_node.to_dict = mock.Mock(return_value={}) - self.mock_client.nodes = mock.Mock(return_value=[fake_node]) - - def test_node_list_defaults(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_node_list_full_id(self): - arglist = ['--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_node_list_limit(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['limit'] = '3' - arglist = ['--limit', '3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_node_list_sort(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:asc' - arglist = ['--sort', 'name:asc'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_node_list_sort_invalid_key(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'bad_key' - arglist = ['--sort', 'bad_key'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.nodes.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_node_list_sort_invalid_direction(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:bad_direction' - arglist = ['--sort', 'name:bad_direction'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.nodes.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_node_list_filter(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['name'] = 'my_node' - arglist = ['--filter', 'name=my_node'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_node_list_marker(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['marker'] = 'a9448bf6' - arglist = ['--marker', 'a9448bf6'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.nodes.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - -class TestNodeShow(TestNode): - response = {"node": { - }} - - def setUp(self): - super(TestNodeShow, self).setUp() - self.cmd = osc_node.ShowNode(self.app, None) - fake_node = mock.Mock( - cluster_id=None, - created_at="2015-02-10T12:03:16", - data={}, - details={"OS-DCF:diskConfig": "MANUAL"}, - domain_id=None, - id="d5779bb0-f0a0-49c9-88cc-6f078adb5a0b", - index=-1, - init_at="2015-02-10T12:03:13", - metadata={}, - physical_id="f41537fa-22ab-4bea-94c0-c874e19d0c80", - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - role=None, - status="ACTIVE", - status_reason="Creation succeeded", - tainted=True, - updated_at="2015-03-04T04:58:27", - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_node.name = "my_node" - fake_node.to_dict = mock.Mock( - return_value={'details': {'key': 'value'}} - ) - self.mock_client.get_node = mock.Mock(return_value=fake_node) - - def test_node_show(self): - arglist = ['my_node'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_node.assert_called_with('my_node', details=False) - - def test_node_show_with_details(self): - arglist = ['my_node', '--details'] - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.get_node.assert_called_with( - 'my_node', details=True) - - def test_node_show_not_found(self): - arglist = ['my_node'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_node.side_effect = sdk_exc.ResourceNotFound() - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertEqual('Node not found: my_node', str(error)) - - -class TestNodeCreate(TestNode): - - defaults = { - "cluster_id": None, - "metadata": {}, - "name": "my_node", - "profile_id": "mystack", - "role": None - } - - def setUp(self): - super(TestNodeCreate, self).setUp() - self.cmd = osc_node.CreateNode(self.app, None) - fake_node = mock.Mock( - action="2366d440-c73e-4961-9254-6d1c3af7c167", - cluster_id="", - created_at=None, - data={}, - domain=None, - id="0df0931b-e251-4f2e-8719-4ebfda3627ba", - index=-1, - init_time="2015-03-05T08:53:15", - metadata={}, - physical_id=None, - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - role="master", - status="INIT", - status_reason="Initializing", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_node.name = "my_node" - fake_node.to_dict = mock.Mock(return_value={}) - - self.mock_client.create_node = mock.Mock(return_value=fake_node) - self.mock_client.get_node = mock.Mock(return_value=fake_node) - - def test_node_create_defaults(self): - arglist = ['my_node', '--profile', 'mystack'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_node.assert_called_with(**self.defaults) - - def test_node_create_with_metadata(self): - arglist = ['my_node', '--profile', 'mystack', - '--metadata', 'key1=value1;key2=value2'] - kwargs = copy.deepcopy(self.defaults) - kwargs['metadata'] = {'key1': 'value1', 'key2': 'value2'} - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_node.assert_called_with(**kwargs) - - def test_node_create_with_cluster(self): - arglist = ['my_node', '--profile', 'mystack', - '--cluster', 'mycluster'] - kwargs = copy.deepcopy(self.defaults) - kwargs['cluster_id'] = 'mycluster' - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_node.assert_called_with(**kwargs) - - def test_node_create_with_role(self): - arglist = ['my_node', '--profile', 'mystack', - '--role', 'master'] - kwargs = copy.deepcopy(self.defaults) - kwargs['role'] = 'master' - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_node.assert_called_with(**kwargs) - - -class TestNodeUpdate(TestNode): - - defaults = { - "name": "new_node", - "metadata": { - "nk1": "nv1", - "nk2": "nv2", - }, - "profile_id": "new_profile", - "role": "new_role", - "tainted": True - } - - def setUp(self): - super(TestNodeUpdate, self).setUp() - self.cmd = osc_node.UpdateNode(self.app, None) - fake_node = mock.Mock( - action="2366d440-c73e-4961-9254-6d1c3af7c167", - cluster_id="", - created_at=None, - data={}, - domain=None, - id="0df0931b-e251-4f2e-8719-4ebfda3627ba", - index=-1, - init_time="2015-03-05T08:53:15", - metadata={}, - physical_id=None, - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - role="master", - status="INIT", - status_reason="Initializing", - tainted=False, - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_node.name = "my_node" - fake_node.to_dict = mock.Mock(return_value={}) - self.mock_client.update_node = mock.Mock(return_value=fake_node) - self.mock_client.get_node = mock.Mock(return_value=fake_node) - self.mock_client.find_node = mock.Mock(return_value=fake_node) - - def test_node_update_defaults(self): - arglist = ['--name', 'new_node', '--metadata', 'nk1=nv1;nk2=nv2', - '--profile', 'new_profile', '--role', 'new_role', - '--tainted', 'True', '0df0931b'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.update_node.assert_called_with( - '0df0931b-e251-4f2e-8719-4ebfda3627ba', **self.defaults) - - def test_node_update_not_found(self): - arglist = ['--name', 'new_node', '--metadata', 'nk1=nv1;nk2=nv2', - '--profile', 'new_profile', '--role', 'new_role', - 'c6b8b252'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.find_node.return_value = None - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Node not found: c6b8b252', str(error)) - - -class TestNodeDelete(TestNode): - def setUp(self): - super(TestNodeDelete, self).setUp() - self.cmd = osc_node.DeleteNode(self.app, None) - mock_node = mock.Mock(location='loc/fake_action_id') - self.mock_client.delete_node = mock.Mock(return_value=mock_node) - - def test_node_delete(self): - arglist = ['node1', 'node2', 'node3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_node.assert_has_calls( - [mock.call('node1', False, False), - mock.call('node2', False, False), - mock.call('node3', False, False)] - ) - - def test_node_delete_force(self): - arglist = ['node1', 'node2', 'node3', '--force'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_node.assert_has_calls( - [mock.call('node1', False, False), - mock.call('node2', False, False), - mock.call('node3', False, False)] - ) - - def test_node_delete_force_delete(self): - arglist = ['node1', 'node2', 'node3', '--force-delete'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_node.assert_has_calls( - [mock.call('node1', False, True), - mock.call('node2', False, True), - mock.call('node3', False, True)] - ) - - def test_node_delete_not_found(self): - arglist = ['my_node'] - self.mock_client.delete_node.side_effect = sdk_exc.ResourceNotFound - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.delete_node.assert_has_calls( - [mock.call('my_node', False, False)] - ) - - def test_node_delete_one_found_one_not_found(self): - arglist = ['node1', 'node2'] - self.mock_client.delete_node.side_effect = ( - [None, sdk_exc.ResourceNotFound] - ) - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.delete_node.assert_has_calls( - [mock.call('node1', False, False), - mock.call('node2', False, False)] - ) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_node_delete_prompt_yes(self, mock_stdin): - arglist = ['my_node'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'y' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_node.assert_called_with( - 'my_node', False, False) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_node_delete_prompt_no(self, mock_stdin): - arglist = ['my_node'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'n' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_node.assert_not_called() - - -class TestNodeCheck(TestNode): - response = {"action": "8bb476c3-0f4c-44ee-9f64-c7b0260814de"} - - def setUp(self): - super(TestNodeCheck, self).setUp() - self.cmd = osc_node.CheckNode(self.app, None) - self.mock_client.check_node = mock.Mock( - return_value=self.response) - - def test_node_check(self): - arglist = ['node1', 'node2', 'node3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.check_node.assert_has_calls( - [mock.call('node1'), mock.call('node2'), - mock.call('node3')] - ) - - def test_node_check_not_found(self): - arglist = ['node1'] - self.mock_client.check_node.side_effect = sdk_exc.ResourceNotFound - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Node not found: node1', str(error)) - - -class TestNodeRecover(TestNode): - - action_id = "8bb476c3-0f4c-44ee-9f64-c7b0260814de" - - def setUp(self): - super(TestNodeRecover, self).setUp() - self.cmd = osc_node.RecoverNode(self.app, None) - fake_res = {'action': self.action_id} - self.mock_client.recover_node = mock.Mock(return_value=fake_res) - - def test_node_recover(self): - arglist = ['node1', 'node2', 'node3', '--check', 'false'] - kwargs = {'check': False} - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.recover_node.assert_has_calls( - [mock.call('node1', **kwargs), mock.call('node2', **kwargs), - mock.call('node3', **kwargs)] - ) - - def test_node_recover_not_found(self): - arglist = ['node1'] - self.mock_client.recover_node.side_effect = sdk_exc.ResourceNotFound - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Node not found: node1', str(error)) - - -class TestNodeAdopt(TestNode): - defaults = { - "identity": "fake-resource-id", - "metadata": {}, - "name": "my_node", - "overrides": {}, - "role": None, - "snapshot": False, - "type": "os.nova.server-1.0" - } - - def setUp(self): - super(TestNodeAdopt, self).setUp() - self.cmd = osc_node.AdoptNode(self.app, None) - fake_node = mock.Mock( - action="2366d440-c73e-4961-9254-6d1c3af7c167", - cluster_id="", - created_at=None, - data={}, - domain=None, - id="0df0931b-e251-4f2e-8719-4ebfda3627ba", - index=-1, - init_time="2015-03-05T08:53:15", - metadata={}, - physical_id=None, - profile_id="edc63d0a-2ca4-48fa-9854-27926da76a4a", - profile_name="mystack", - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - role="master", - status="INIT", - status_reason="Initializing", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_node.name = "my_node" - fake_node.to_dict = mock.Mock(return_value={}) - - self.mock_client.adopt_node = mock.Mock(return_value=fake_node) - self.mock_client.get_node = mock.Mock(return_value=fake_node) - - def test_node_adopt_defaults(self): - arglist = ['--identity', 'fake-resource-id', - '--type', 'os.nova.server-1.0', - '--name', 'my_node'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.adopt_node.assert_called_with(False, **self.defaults) - - def test_node_adopt_with_metadata(self): - arglist = ['--identity', 'fake-resource-id', - '--type', 'os.nova.server-1.0', - '--metadata', 'key1=value1;key2=value2', - '--name', 'my_node'] - kwargs = copy.deepcopy(self.defaults) - kwargs['metadata'] = {'key1': 'value1', 'key2': 'value2'} - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.adopt_node.assert_called_with(False, **kwargs) - - def test_node_adopt_with_override(self): - arglist = ['--identity', 'fake-resource-id', - '--type', 'os.nova.server-1.0', - '--overrides', - '{"networks": [{"network": "fake-net-name"}]}', - '--name', 'my_node'] - kwargs = copy.deepcopy(self.defaults) - kwargs['overrides'] = {'networks': [{'network': 'fake-net-name'}]} - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.adopt_node.assert_called_with(False, **kwargs) - - def test_node_adopt_with_role(self): - arglist = ['--identity', 'fake-resource-id', - '--type', 'os.nova.server-1.0', - '--role', 'master', - '--name', 'my_node'] - kwargs = copy.deepcopy(self.defaults) - kwargs['role'] = 'master' - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.adopt_node.assert_called_with(False, **kwargs) - - def test_node_adopt_with_snapshot(self): - arglist = ['--identity', 'fake-resource-id', - '--type', 'os.nova.server-1.0', - '--snapshot', - '--name', 'my_node'] - parsed_args = self.check_parser(self.cmd, arglist, []) - kwargs = copy.deepcopy(self.defaults) - kwargs['snapshot'] = True - self.cmd.take_action(parsed_args) - self.mock_client.adopt_node.assert_called_with(False, **kwargs) - - -class TestNodeAdoptPreview(TestNode): - defaults = { - "identity": "fake-resource-id", - "overrides": {}, - "snapshot": False, - "type": "os.nova.server-1.0" - } - - def setUp(self): - super(TestNodeAdoptPreview, self).setUp() - self.cmd = osc_node.AdoptNode(self.app, None) - self.fake_node_preview = { - "node_profile": { - "node_preview": { - "properties": { - - }, - "type": "os.nova.server", - "version": "1.0"} - } - } - - self.mock_client.adopt_node = mock.Mock( - return_value=self.fake_node_preview) - self.mock_client.get_node = mock.Mock( - return_value=self.fake_node_preview) - - def test_node_adopt_preview_default(self): - arglist = ['--identity', 'fake-resource-id', - '--type', 'os.nova.server-1.0', - '--preview'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.adopt_node.assert_called_with(True, **self.defaults) - - def test_node_adopt_preview_with_overrides(self): - arglist = ['--identity', 'fake-resource-id', - '--type', 'os.nova.server-1.0', - '--overrides', - '{"networks": [{"network": "fake-net-name"}]}', - '--preview'] - parsed_args = self.check_parser(self.cmd, arglist, []) - kwargs = copy.deepcopy(self.defaults) - kwargs['overrides'] = {'networks': [{'network': 'fake-net-name'}]} - self.cmd.take_action(parsed_args) - self.mock_client.adopt_node.assert_called_with(True, **kwargs) - - def test_node_adopt_preview_with_snapshot(self): - arglist = ['--identity', 'fake-resource-id', - '--type', 'os.nova.server-1.0', - '--snapshot', '--preview'] - parsed_args = self.check_parser(self.cmd, arglist, []) - kwargs = copy.deepcopy(self.defaults) - kwargs['snapshot'] = True - self.cmd.take_action(parsed_args) - self.mock_client.adopt_node.assert_called_with(True, **kwargs) - - -class TestNodeOp(TestNode): - - response = {"action": "1db0f5c5-9183-4c47-9ef1-a5a97402a2c1"} - - def setUp(self): - super(TestNodeOp, self).setUp() - self.cmd = osc_node.NodeOp(self.app, None) - self.mock_client.perform_operation_on_node = mock.Mock( - return_value=self.response) - - def test_node_op(self): - arglist = ['--operation', 'dance', '--params', 'style=tango', - 'my_node'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.perform_operation_on_node.assert_called_once_with( - 'my_node', - 'dance', - style='tango') - - def test_node_op_not_found(self): - arglist = ['--operation', 'dance', 'node1'] - ex = sdk_exc.ResourceNotFound - self.mock_client.perform_operation_on_node.side_effect = ex - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Node not found: node1', str(error)) diff --git a/senlinclient/tests/unit/v1/test_policy.py b/senlinclient/tests/unit/v1/test_policy.py deleted file mode 100644 index 27b4b189..00000000 --- a/senlinclient/tests/unit/v1/test_policy.py +++ /dev/null @@ -1,441 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import io -from unittest import mock - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import policy as osc_policy - - -class TestPolicy(fakes.TestClusteringv1): - def setUp(self): - super(TestPolicy, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestPolicyList(TestPolicy): - columns = ['id', 'name', 'type', 'created_at'] - response = {"policies": [ - { - } - ]} - defaults = { - 'global_project': False, - 'marker': None, - 'limit': None, - 'sort': None, - } - - def setUp(self): - super(TestPolicyList, self).setUp() - self.cmd = osc_policy.ListPolicy(self.app, None) - fake_policy = mock.Mock( - created_at="2015-02-15T08:33:13.000000", - data={}, - domain=None, - id="7192d8df-73be-4e98-ab99-1cf6d5066729", - project_id="42d9e9663331431f97b75e25136307ff", - spec={ - "description": "A test policy", - "properties": { - "criteria": "OLDEST_FIRST", - "destroy_after_deletion": True, - "grace_period": 60, - "reduce_desired_capacity": False - }, - "type": "senlin.policy.deletion", - "version": "1.0" - }, - type="senlin.policy.deletion-1.0", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_policy.name = "test_policy_1" - fake_policy.to_dict = mock.Mock(return_value={}) - self.mock_client.policies = mock.Mock( - return_value=self.response) - - def test_policy_list_defaults(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.policies.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_policy_list_full_id(self): - arglist = ['--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.policies.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_policy_list_limit(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['limit'] = '3' - arglist = ['--limit', '3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.policies.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_policy_list_sort(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:asc' - arglist = ['--sort', 'name:asc'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.policies.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_policy_list_sort_invalid_key(self): - self.mock_client.policies = mock.Mock( - return_value=self.response) - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'bad_key' - arglist = ['--sort', 'bad_key'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.policies.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_policy_list_sort_invalid_direction(self): - self.mock_client.policies = mock.Mock( - return_value=self.response) - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:bad_direction' - arglist = ['--sort', 'name:bad_direction'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.policies.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_policy_list_marker(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['marker'] = 'a9448bf6' - arglist = ['--marker', 'a9448bf6'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.policies.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_policy_list_filter(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['name'] = 'my_policy' - arglist = ['--filter', 'name=my_policy'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.policies.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - -class TestPolicyShow(TestPolicy): - response = {"policy": { - }} - - def setUp(self): - super(TestPolicyShow, self).setUp() - self.cmd = osc_policy.ShowPolicy(self.app, None) - fake_policy = mock.Mock( - created_at="2015-03-02T07:40:31", - data={}, - domain_id=None, - id="02f62195-2198-4797-b0a9-877632208527", - project_id="42d9e9663331431f97b75e25136307ff", - spec={ - "properties": { - "adjustment": { - "best_effort": True, - "min_step": 1, - "number": 1, - "type": "CHANGE_IN_CAPACITY" - }, - "event": "CLUSTER_SCALE_IN" - }, - "type": "senlin.policy.scaling", - "version": "1.0" - }, - type="senlin.policy.scaling-1.0", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_policy.name = "sp001" - fake_policy.to_dict = mock.Mock(return_value={}) - self.mock_client.get_policy = mock.Mock(return_value=fake_policy) - - def test_policy_show(self): - arglist = ['sp001'] - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.get_policy.assert_called_with('sp001') - policy = self.mock_client.get_policy('sp001') - self.assertEqual("2015-03-02T07:40:31", policy.created_at) - self.assertEqual({}, policy.data) - self.assertEqual("02f62195-2198-4797-b0a9-877632208527", policy.id) - self.assertEqual("sp001", policy.name) - self.assertEqual("42d9e9663331431f97b75e25136307ff", policy.project_id) - self.assertEqual("senlin.policy.scaling-1.0", policy.type) - self.assertIsNone(policy.updated_at) - - def test_policy_show_not_found(self): - arglist = ['sp001'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_policy.side_effect = sdk_exc.ResourceNotFound() - self.assertRaises(exc.CommandError, self.cmd.take_action, parsed_args) - - -class TestPolicyCreate(TestPolicy): - spec_path = 'senlinclient/tests/test_specs/deletion_policy.yaml' - defaults = { - "name": "my_policy", - "spec": { - "version": 1, - "type": "senlin.policy.deletion", - "description": "A policy for choosing victim node(s) from a " - "cluster for deletion.", - "properties": { - "destroy_after_deletion": True, - "grace_period": 60, - "reduce_desired_capacity": False, - "criteria": "OLDEST_FIRST" - } - } - } - - def setUp(self): - super(TestPolicyCreate, self).setUp() - self.cmd = osc_policy.CreatePolicy(self.app, None) - fake_policy = mock.Mock( - created_at="2016-02-21T02:38:36", - data={}, - domain_id=None, - id="9f779ddf-744e-48bd-954c-acef7e11116c", - project_id="5f1cc92b578e4e25a3b284179cf20a9b", - spec={ - "description": "A policy for choosing victim node(s) from a " - "cluster for deletion.", - "properties": { - "criteria": "OLDEST_FIRST", - "destroy_after_deletion": True, - "grace_period": 60, - "reduce_desired_capacity": False - }, - "type": "senlin.policy.deletion", - "version": 1.0 - }, - type="senlin.policy.deletion-1.0", - updated_at=None, - user_id="2d7aca950f3e465d8ef0c81720faf6ff" - ) - fake_policy.name = "my_policy" - fake_policy.to_dict = mock.Mock(return_value={}) - self.mock_client.create_policy = mock.Mock(return_value=fake_policy) - self.mock_client.get_policy = mock.Mock(return_value=fake_policy) - - def test_policy_create_defaults(self): - arglist = ['my_policy', '--spec-file', self.spec_path] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_policy.assert_called_with(**self.defaults) - - -class TestPolicyUpdate(TestPolicy): - - def setUp(self): - super(TestPolicyUpdate, self).setUp() - self.cmd = osc_policy.UpdatePolicy(self.app, None) - fake_policy = mock.Mock( - created_at="2016-02-21T02:38:36", - data={}, - domain_id=None, - id="9f779ddf-744e-48bd-954c-acef7e11116c", - project_id="5f1cc92b578e4e25a3b284179cf20a9b", - spec={ - "description": "A policy for choosing victim node(s) from a " - "cluster for deletion.", - "properties": { - "criteria": "OLDEST_FIRST", - "destroy_after_deletion": True, - "grace_period": 60, - "reduce_desired_capacity": False - }, - "type": "senlin.policy.deletion", - "version": 1.0 - }, - type="senlin.policy.deletion-1.0", - updated_at=None, - user_id="2d7aca950f3e465d8ef0c81720faf6ff" - ) - fake_policy.name = "new_policy" - fake_policy.to_dict = mock.Mock(return_value={}) - self.mock_client.update_policy = mock.Mock(return_value=fake_policy) - self.mock_client.get_policy = mock.Mock(return_value=fake_policy) - self.mock_client.find_policy = mock.Mock(return_value=fake_policy) - - def test_policy_update_defaults(self): - arglist = ['--name', 'new_policy', '9f779ddf'] - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.update_policy.assert_called_with( - '9f779ddf-744e-48bd-954c-acef7e11116c', name="new_policy") - - def test_policy_update_not_found(self): - arglist = ['--name', 'new_policy', 'c6b8b252'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.find_policy.return_value = None - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertIn('Policy not found: c6b8b252', str(error)) - - -class TestPolicyDelete(TestPolicy): - def setUp(self): - super(TestPolicyDelete, self).setUp() - self.cmd = osc_policy.DeletePolicy(self.app, None) - self.mock_client.delete_policy = mock.Mock() - - def test_policy_delete(self): - arglist = ['policy1', 'policy2', 'policy3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_policy.assert_has_calls( - [mock.call('policy1', False), mock.call('policy2', False), - mock.call('policy3', False)] - ) - - def test_policy_delete_force(self): - arglist = ['policy1', 'policy2', 'policy3', '--force'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_policy.assert_has_calls( - [mock.call('policy1', False), mock.call('policy2', False), - mock.call('policy3', False)] - ) - - def test_policy_delete_not_found(self): - arglist = ['my_policy'] - self.mock_client.delete_policy.side_effect = sdk_exc.ResourceNotFound - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Failed to delete 1 of the 1 specified policy(s).', - str(error)) - - def test_policy_delete_one_found_one_not_found(self): - arglist = ['policy1', 'policy2'] - self.mock_client.delete_policy.side_effect = ( - [None, sdk_exc.ResourceNotFound] - ) - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, parsed_args) - self.mock_client.delete_policy.assert_has_calls( - [mock.call('policy1', False), mock.call('policy2', False)] - ) - self.assertEqual('Failed to delete 1 of the 2 specified policy(s).', - str(error)) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_policy_delete_prompt_yes(self, mock_stdin): - arglist = ['my_policy'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'y' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_policy.assert_called_with('my_policy', - False) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_policy_delete_prompt_no(self, mock_stdin): - arglist = ['my_policy'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'n' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_policy.assert_not_called() - - -class TestPolicyValidate(TestPolicy): - spec_path = 'senlinclient/tests/test_specs/deletion_policy.yaml' - defaults = { - "spec": { - "version": 1, - "type": "senlin.policy.deletion", - "description": "A policy for choosing victim node(s) from a " - "cluster for deletion.", - "properties": { - "destroy_after_deletion": True, - "grace_period": 60, - "reduce_desired_capacity": False, - "criteria": "OLDEST_FIRST" - } - } - } - - def setUp(self): - super(TestPolicyValidate, self).setUp() - self.cmd = osc_policy.ValidatePolicy(self.app, None) - fake_policy = mock.Mock( - created_at=None, - data={}, - domain_id=None, - id=None, - project_id="5f1cc92b578e4e25a3b284179cf20a9b", - spec={ - "description": "A policy for choosing victim node(s) from a " - "cluster for deletion.", - "properties": { - "criteria": "OLDEST_FIRST", - "destroy_after_deletion": True, - "grace_period": 60, - "reduce_desired_capacity": False - }, - "type": "senlin.policy.deletion", - "version": 1.0 - }, - type="senlin.policy.deletion-1.0", - updated_at=None, - user_id="2d7aca950f3e465d8ef0c81720faf6ff" - ) - fake_policy.name = "validated_policy" - fake_policy.to_dict = mock.Mock(return_value={}) - self.mock_client.validate_policy = mock.Mock(return_value=fake_policy) - - def test_policy_validate(self): - arglist = ['--spec-file', self.spec_path] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.validate_policy.assert_called_with(**self.defaults) - - policy = self.mock_client.validate_policy(**self.defaults) - - self.assertEqual("5f1cc92b578e4e25a3b284179cf20a9b", policy.project_id) - self.assertEqual({}, policy.data) - self.assertIsNone(policy.id) - self.assertEqual("validated_policy", policy.name) - self.assertEqual("senlin.policy.deletion-1.0", policy.type) - self.assertIsNone(policy.updated_at) diff --git a/senlinclient/tests/unit/v1/test_policy_type.py b/senlinclient/tests/unit/v1/test_policy_type.py deleted file mode 100644 index 02508111..00000000 --- a/senlinclient/tests/unit/v1/test_policy_type.py +++ /dev/null @@ -1,96 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc -from unittest import mock - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import policy_type as osc_policy_type - - -class TestPolicyType(fakes.TestClusteringv1): - def setUp(self): - super(TestPolicyType, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestPolicyTypeList(TestPolicyType): - expected_columns = ['name', 'version', 'support_status'] - pt1 = mock.Mock( - schema={'foo': 'bar'}, - support_status={ - "1.0": [{"status": "SUPPORTED", "since": "2016.10"}] - } - ) - pt1.name = 'BBB' - pt2 = mock.Mock( - schema={'foo': 'bar'}, - support_status={ - "1.0": [{"status": "DEPRECATED", "since": "2016.01"}] - } - ) - pt2.name = 'AAA' - list_response = [pt1, pt2] - expected_rows = [ - ('AAA', '1.0', 'DEPRECATED since 2016.01'), - ('BBB', '1.0', 'SUPPORTED since 2016.10') - ] - - def setUp(self): - super(TestPolicyTypeList, self).setUp() - self.cmd = osc_policy_type.PolicyTypeList(self.app, None) - self.mock_client.policy_types = mock.Mock( - return_value=self.list_response) - - def test_policy_type_list(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - expected_columns = self.expected_columns - expected_rows = self.expected_rows - columns, rows = self.cmd.take_action(parsed_args) - if len(columns) == 2: - expected_columns = ['name', 'version'] - expected_rows = [ - ('CCC', '1.0') - ] - - self.mock_client.policy_types.assert_called_with() - self.assertEqual(expected_columns, columns) - self.assertEqual(expected_rows, rows) - - -class TestPolicyTypeShow(TestPolicyType): - - def setUp(self): - super(TestPolicyTypeShow, self).setUp() - self.cmd = osc_policy_type.PolicyTypeShow(self.app, None) - fake_pt = mock.Mock(schema={'foo': 'bar'}) - fake_pt.name = 'senlin.policy.deletion-1.0' - self.mock_client.get_policy_type = mock.Mock(return_value=fake_pt) - - def test_policy_type_show(self): - arglist = ['os.heat.stack-1.0'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_policy_type.assert_called_once_with( - 'os.heat.stack-1.0') - - def test_policy_type_show_not_found(self): - arglist = ['senlin.policy.deletion-1.0'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_policy_type.side_effect = ( - sdk_exc.ResourceNotFound()) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertEqual('Policy Type not found: senlin.policy.deletion-1.0', - str(error)) diff --git a/senlinclient/tests/unit/v1/test_profile.py b/senlinclient/tests/unit/v1/test_profile.py deleted file mode 100644 index 6b334a5a..00000000 --- a/senlinclient/tests/unit/v1/test_profile.py +++ /dev/null @@ -1,449 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import io -from unittest import mock - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc -from osc_lib import utils - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import profile as osc_profile - - -class TestProfile(fakes.TestClusteringv1): - def setUp(self): - super(TestProfile, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestProfileShow(TestProfile): - response = {"profile": { - "created_at": "2015-03-01T14:28:25", - "domain": 'false', - "id": "7fa885cd-fa39-4531-a42d-780af95c84a4", - "metadata": {}, - "name": "test_prof1", - "project": "42d9e9663331431f97b75e25136307ff", - "spec": { - "disable_rollback": 'false', - "environment": { - "resource_registry": { - "os.heat.server": "OS::Heat::Server" - } - }, - "files": { - "file:///opt/stack/senlin/examples/profiles/test_script.sh": - "#!/bin/bash\n\necho \"this is a test script file\"\n" - }, - "parameters": {}, - "template": { - "heat_template_version": "2014-10-16", - "outputs": { - "result": { - "value": { - "get_attr": [ - "random", - "value" - ] - } - } - }, - "parameters": { - "file": { - "default": { - "get_file": "file:///opt/stack/senlin/" - "examples/profiles/test_script.sh" - }, - "type": "string" - } - }, - "resources": { - "random": { - "properties": { - "length": 64 - }, - "type": "OS::Heat::RandomString" - } - }, - "timeout": 60 - }, - "type": "os.heat.stack", - "version": "1.0" - }, - "type": "os.heat.stack-1.0", - "updated_at": 'null', - "user": "5e5bf8027826429c96af157f68dc9072" - }} - - def setUp(self): - super(TestProfileShow, self).setUp() - self.cmd = osc_profile.ShowProfile(self.app, None) - fake_profile = mock.Mock( - created_at="2015-03-01T14:28:25", - domain_id=None, - id="7fa885cd-fa39-4531-a42d-780af95c84a4", - metadata={}, - project_id="42d9e9663331431f97b75e25136307ff", - spec={"foo": 'bar'}, - type="os.heat.stack-1.0", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_profile.name = "test_prof1" - fake_profile.to_dict = mock.Mock(return_value={}) - self.mock_client.get_profile = mock.Mock(return_value=fake_profile) - utils.get_dict_properties = mock.Mock(return_value='') - - def test_profile_show(self): - arglist = ['my_profile'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_profile.assert_called_with('my_profile') - profile = self.mock_client.get_profile('my_profile') - self.assertEqual("42d9e9663331431f97b75e25136307ff", - profile.project_id) - self.assertEqual("7fa885cd-fa39-4531-a42d-780af95c84a4", profile.id) - self.assertEqual({}, profile.metadata) - self.assertEqual("test_prof1", profile.name) - self.assertEqual("os.heat.stack-1.0", profile.type) - - def test_profile_show_not_found(self): - arglist = ['my_profile'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_profile.side_effect = sdk_exc.ResourceNotFound() - self.assertRaises( - exc.CommandError, - self.cmd.take_action, - parsed_args) - - -class TestProfileList(TestProfile): - - def setUp(self): - super(TestProfileList, self).setUp() - self.cmd = osc_profile.ListProfile(self.app, None) - fake_profile = mock.Mock( - created_at="2015-03-01T14:28:25", - domain_id=None, - id="7fa885cd-fa39-4531-a42d-780af95c84a4", - metadata={}, - project_id="42d9e9663331431f97b75e25136307ff", - spec={"foo": 'bar'}, - type="os.heat.stack-1.0", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_profile.name = "test_profile" - fake_profile.to_dict = mock.Mock(return_value={}) - self.mock_client.profiles = mock.Mock(return_value=[fake_profile]) - self.defaults = { - 'limit': None, - 'marker': None, - 'sort': None, - 'global_project': False, - } - self.columns = ['id', 'name', 'type', 'created_at'] - - def test_profile_list_defaults(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.profiles.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_profile_list_full_id(self): - arglist = ['--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.profiles.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_profile_list_limit(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['limit'] = '3' - arglist = ['--limit', '3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.profiles.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_profile_list_sort(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'id:asc' - arglist = ['--sort', 'id:asc'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.profiles.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_profile_list_sort_invalid_key(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'bad_key' - arglist = ['--sort', 'bad_key'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.profiles.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_profile_list_sort_invalid_direction(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'id:bad_direction' - arglist = ['--sort', 'id:bad_direction'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.profiles.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_profile_list_filter(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['name'] = 'my_profile' - arglist = ['--filter', 'name=my_profile'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.profiles.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - -class TestProfileDelete(TestProfile): - - def setUp(self): - super(TestProfileDelete, self).setUp() - self.cmd = osc_profile.DeleteProfile(self.app, None) - self.mock_client.delete_profile = mock.Mock() - - def test_profile_delete(self): - arglist = ['profile1', 'profile2', 'profile3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_profile.assert_has_calls( - [mock.call('profile1', False), mock.call('profile2', False), - mock.call('profile3', False)] - ) - - def test_profile_delete_force(self): - arglist = ['profile1', 'profile2', 'profile3', '--force'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_profile.assert_has_calls( - [mock.call('profile1', False), mock.call('profile2', False), - mock.call('profile3', False)] - ) - - def test_profile_delete_not_found(self): - arglist = ['my_profile'] - self.mock_client.delete_profile.side_effect = sdk_exc.ResourceNotFound - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Failed to delete 1 of the 1 specified profile(s).', - str(error)) - - def test_profile_delete_one_found_one_not_found(self): - arglist = ['profile1', 'profile2'] - self.mock_client.delete_profile.side_effect = ( - [None, sdk_exc.ResourceNotFound] - ) - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, parsed_args) - self.mock_client.delete_profile.assert_has_calls( - [mock.call('profile1', False), mock.call('profile2', False)] - ) - self.assertEqual('Failed to delete 1 of the 2 specified profile(s).', - str(error)) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_profile_delete_prompt_yes(self, mock_stdin): - arglist = ['my_profile'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'y' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_profile.assert_called_with('my_profile', - False) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_profile_delete_prompt_no(self, mock_stdin): - arglist = ['my_profile'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'n' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_profile.assert_not_called() - - -class TestProfileCreate(TestProfile): - - spec_path = 'senlinclient/tests/test_specs/nova_server.yaml' - - def setUp(self): - super(TestProfileCreate, self).setUp() - self.cmd = osc_profile.CreateProfile(self.app, None) - fake_profile = mock.Mock( - created_at="2015-03-01T14:28:25", - domain_id=None, - id="7fa885cd-fa39-4531-a42d-780af95c84a4", - metadata={}, - project_id="42d9e9663331431f97b75e25136307ff", - spec={"foo": 'bar'}, - type="os.heat.stack-1.0", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_profile.name = "test_profile" - fake_profile.to_dict = mock.Mock(return_value={}) - self.mock_client.create_profile = mock.Mock(return_value=fake_profile) - self.mock_client.get_profile = mock.Mock(return_value=fake_profile) - utils.get_dict_properties = mock.Mock(return_value='') - self.defaults = { - "spec": { - "version": 1.0, - "type": "os.nova.server", - "properties": { - "flavor": 1, - "name": "cirros_server", - "image": "cirros-0.3.4-x86_64-uec" - }, - }, - "name": "my_profile", - "metadata": {} - } - - def test_profile_create_defaults(self): - arglist = ['my_profile', '--spec-file', self.spec_path] - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.create_profile.assert_called_with(**self.defaults) - - def test_profile_create_metadata(self): - arglist = ['my_profile', '--spec-file', self.spec_path, - '--metadata', 'key1=value1'] - kwargs = copy.deepcopy(self.defaults) - kwargs['metadata'] = {'key1': 'value1'} - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_profile.assert_called_with(**kwargs) - - -class TestProfileUpdate(TestProfile): - - def setUp(self): - super(TestProfileUpdate, self).setUp() - self.cmd = osc_profile.UpdateProfile(self.app, None) - fake_profile = mock.Mock( - created_at="2015-03-01T14:28:25", - domain_id=None, - id="7fa885cd-fa39-4531-a42d-780af95c84a4", - metadata={}, - project_id="42d9e9663331431f97b75e25136307ff", - spec={"foo": 'bar'}, - type="os.heat.stack-1.0", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_profile.name = "test_profile" - fake_profile.to_dict = mock.Mock(return_value={}) - self.mock_client.update_profile = mock.Mock(return_value=fake_profile) - self.mock_client.get_profile = mock.Mock(return_value=fake_profile) - self.mock_client.find_profile = mock.Mock(return_value=fake_profile) - utils.get_dict_properties = mock.Mock(return_value='') - - def test_profile_update_defaults(self): - arglist = ['--name', 'new_profile', '--metadata', 'nk1=nv1;nk2=nv2', - 'e3057c77'] - parsed_args = self.check_parser(self.cmd, arglist, []) - defaults = { - "name": "new_profile", - "metadata": { - "nk1": "nv1", - "nk2": "nv2", - } - } - - self.cmd.take_action(parsed_args) - - self.mock_client.update_profile.assert_called_with( - "7fa885cd-fa39-4531-a42d-780af95c84a4", **defaults) - - def test_profile_update_not_found(self): - arglist = ['--name', 'new_profile', '--metadata', 'nk1=nv1;nk2=nv2', - 'c6b8b252'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.find_profile.return_value = None - error = self.assertRaises( - exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertIn('Profile not found: c6b8b252', str(error)) - - -class TestProfileValidate(TestProfile): - - spec_path = 'senlinclient/tests/test_specs/nova_server.yaml' - defaults = { - "spec": { - "version": 1.0, - "type": "os.nova.server", - "properties": { - "flavor": 1, - "name": "cirros_server", - "image": "cirros-0.3.4-x86_64-uec" - }, - } - } - - def setUp(self): - super(TestProfileValidate, self).setUp() - self.cmd = osc_profile.ValidateProfile(self.app, None) - fake_profile = mock.Mock( - created_at=None, - domain_id=None, - id=None, - metadata={}, - project_id="42d9e9663331431f97b75e25136307ff", - spec={"foo": 'bar'}, - type="os.heat.stack-1.0", - updated_at=None, - user_id="5e5bf8027826429c96af157f68dc9072" - ) - fake_profile.name = "test_profile" - fake_profile.to_dict = mock.Mock(return_value={}) - self.mock_client.validate_profile = mock.Mock( - return_value=fake_profile) - utils.get_dict_properties = mock.Mock(return_value='') - - def test_profile_validate(self): - arglist = ['--spec-file', self.spec_path] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.validate_profile.assert_called_with(**self.defaults) - - profile = self.mock_client.validate_profile(**self.defaults) - - self.assertEqual("42d9e9663331431f97b75e25136307ff", - profile.project_id) - self.assertEqual("5e5bf8027826429c96af157f68dc9072", profile.user_id) - self.assertIsNone(profile.id) - self.assertEqual({}, profile.metadata) - self.assertEqual("test_profile", profile.name) - self.assertEqual("os.heat.stack-1.0", profile.type) diff --git a/senlinclient/tests/unit/v1/test_profile_type.py b/senlinclient/tests/unit/v1/test_profile_type.py deleted file mode 100644 index 5b81a9bd..00000000 --- a/senlinclient/tests/unit/v1/test_profile_type.py +++ /dev/null @@ -1,137 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc -from unittest import mock - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import profile_type as osc_profile_type - - -class TestProfileType(fakes.TestClusteringv1): - def setUp(self): - super(TestProfileType, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestProfileTypeList(TestProfileType): - - def setUp(self): - super(TestProfileTypeList, self).setUp() - self.cmd = osc_profile_type.ProfileTypeList(self.app, None) - pt1 = mock.Mock( - schema={'foo': 'bar'}, - support_status={ - "1.0": [{"status": "SUPPORTED", "since": "2016.10"}] - } - ) - pt1.name = "BBB" - pt2 = mock.Mock( - schema={'foo': 'bar'}, - support_status={ - "1.0": [{"status": "DEPRECATED", "since": "2016.01"}] - } - ) - pt2.name = "AAA" - self.mock_client.profile_types = mock.Mock(return_value=[pt1, pt2]) - - def test_profile_type_list(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - expected_rows = [ - ('AAA', '1.0', 'DEPRECATED since 2016.01'), - ('BBB', '1.0', 'SUPPORTED since 2016.10') - ] - expected_columns = ['name', 'version', 'support_status'] - - columns, rows = self.cmd.take_action(parsed_args) - if len(columns) == 2: - expected_columns = ['name', 'version'] - expected_rows = [ - ('CCC', '1.0') - ] - - self.mock_client.profile_types.assert_called_with() - self.assertEqual(expected_columns, columns) - self.assertEqual(expected_rows, rows) - - -class TestProfileTypeShow(TestProfileType): - - def setUp(self): - super(TestProfileTypeShow, self).setUp() - self.cmd = osc_profile_type.ProfileTypeShow(self.app, None) - fake_profile_type = mock.Mock( - schema={'foo': 'bar'}, - support_status={ - "1.0": [{"status": "DEPRECATED", "since": "2016.01"}] - } - ) - fake_profile_type.name = "os.heat.stack-1.0" - fake_profile_type.to_dict = mock.Mock(return_value={}) - self.mock_client.get_profile_type = mock.Mock( - return_value=fake_profile_type) - - def test_profile_type_show(self): - arglist = ['os.heat.stack-1.0'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_profile_type.assert_called_once_with( - 'os.heat.stack-1.0') - - def test_profile_type_show_not_found(self): - arglist = ['os.heat.stack-1.1'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_profile_type.side_effect = ( - sdk_exc.ResourceNotFound()) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertEqual('Profile Type not found: os.heat.stack-1.1', - str(error)) - - -class TestProfileTypeOperations(TestProfileType): - def setUp(self): - super(TestProfileTypeOperations, self).setUp() - self.cmd = osc_profile_type.ProfileTypeOperations(self.app, None) - fake_profile_type_ops = mock.Mock( - { - 'options': { - 'abandon': { - 'required': False, - 'type': 'Map', - 'description': 'Abandon a heat stack node.', - 'updatable': False - } - } - } - ) - self.mock_client.list_profile_type_operations = mock.Mock( - return_value=fake_profile_type_ops) - - def test_profile_type_operations(self): - arglist = ['os.heat.stack-1.0'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.list_profile_type_operations.assert_called_once_with( - 'os.heat.stack-1.0') - - def test_profile_type_operations_not_found(self): - arglist = ['os.heat.stack-1.1'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.list_profile_type_operations.side_effect = ( - sdk_exc.ResourceNotFound()) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertEqual('Profile Type not found: os.heat.stack-1.1', - str(error)) diff --git a/senlinclient/tests/unit/v1/test_receiver.py b/senlinclient/tests/unit/v1/test_receiver.py deleted file mode 100644 index a8dd9047..00000000 --- a/senlinclient/tests/unit/v1/test_receiver.py +++ /dev/null @@ -1,373 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import io -from unittest import mock - -from openstack import exceptions as sdk_exc -from osc_lib import exceptions as exc -from osc_lib import utils - -from senlinclient.common.i18n import _ -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import receiver as osc_receiver - - -class TestReceiver(fakes.TestClusteringv1): - def setUp(self): - super(TestReceiver, self).setUp() - self.mock_client = self.app.client_manager.clustering - - -class TestReceiverList(TestReceiver): - columns = ['id', 'name', 'type', 'cluster_id', 'action', 'created_at'] - defaults = { - 'global_project': False, - 'marker': None, - 'limit': None, - 'sort': None, - } - - def setUp(self): - super(TestReceiverList, self).setUp() - self.cmd = osc_receiver.ListReceiver(self.app, None) - fake_receiver = mock.Mock( - action="CLUSTER_SCALE_OUT", - actor={}, - channel={ - "alarm_url": "http://node1:8778/v1/webhooks/e03dd2e5-8f2e-4ec1" - "-8c6a-74ba891e5422/trigger?V=1&count=1" - }, - cluster_id="ae63a10b-4a90-452c-aef1-113a0b255ee3", - created_at="2015-06-27T05:09:43", - domain_id="Default", - id="573aa1ba-bf45-49fd-907d-6b5d6e6adfd3", - name="cluster_inflate", - params={"count": "1"}, - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - type="webhook", - updated_at=None, - user_id="b4ad2d6e18cc2b9c48049f6dbe8a5b3c" - ) - fake_receiver.to_dict = mock.Mock(return_value={}) - self.mock_client.receivers = mock.Mock(return_value=[fake_receiver]) - - def test_receiver_list_defaults(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.receivers.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_receiver_list_full_id(self): - arglist = ['--full-id'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.receivers.assert_called_with(**self.defaults) - self.assertEqual(self.columns, columns) - - def test_receiver_list_limit(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['limit'] = '3' - arglist = ['--limit', '3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.receivers.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_receiver_list_sort(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:asc' - arglist = ['--sort', 'name:asc'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.receivers.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_receiver_list_sort_invalid_key(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'bad_key' - arglist = ['--sort', 'bad_key'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.receivers.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_receiver_list_sort_invalid_direction(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['sort'] = 'name:bad_direction' - arglist = ['--sort', 'name:bad_direction'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.receivers.side_effect = sdk_exc.HttpException() - self.assertRaises(sdk_exc.HttpException, - self.cmd.take_action, parsed_args) - - def test_receiver_list_filter(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['name'] = 'my_receiver' - arglist = ['--filter', 'name=my_receiver'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.receivers.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - def test_receiver_list_marker(self): - kwargs = copy.deepcopy(self.defaults) - kwargs['marker'] = 'a9448bf6' - arglist = ['--marker', 'a9448bf6'] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.receivers.assert_called_with(**kwargs) - self.assertEqual(self.columns, columns) - - -class TestReceiverShow(TestReceiver): - - def setUp(self): - super(TestReceiverShow, self).setUp() - self.cmd = osc_receiver.ShowReceiver(self.app, None) - fake_receiver = mock.Mock( - action="CLUSTER_SCALE_OUT", - actor={}, - channel={ - "alarm_url": "http://node1:8778/v1/webhooks/e03dd2e5-8f2e-4ec1" - "-8c6a-74ba891e5422/trigger?V=1&count=1" - }, - cluster_id="ae63a10b-4a90-452c-aef1-113a0b255ee3", - created_at="2015-06-27T05:09:43", - domain_id="Default", - id="573aa1ba-bf45-49fd-907d-6b5d6e6adfd3", - name="cluster_inflate", - params={"count": "1"}, - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - type="webhook", - updated_at=None, - user_id="b4ad2d6e18cc2b9c48049f6dbe8a5b3c" - ) - fake_receiver.to_dict = mock.Mock(return_value={}) - self.mock_client.get_receiver = mock.Mock(return_value=fake_receiver) - - def test_receiver_show(self): - arglist = ['my_receiver'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.get_receiver.assert_called_with('my_receiver') - - def test_receiver_show_not_found(self): - arglist = ['my_receiver'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.get_receiver.side_effect = sdk_exc.ResourceNotFound() - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertEqual('Receiver not found: my_receiver', str(error)) - - -class TestReceiverCreate(TestReceiver): - - args = { - "action": "CLUSTER_SCALE_OUT", - "cluster_id": "my_cluster", - "name": "my_receiver", - "params": { - "count": "1" - }, - "type": "webhook" - } - - def setUp(self): - super(TestReceiverCreate, self).setUp() - self.cmd = osc_receiver.CreateReceiver(self.app, None) - fake_receiver = mock.Mock( - action="CLUSTER_SCALE_OUT", - actor={}, - channel={ - "alarm_url": "http://node1:8778/v1/webhooks/e03dd2e5-8f2e-4ec1" - "-8c6a-74ba891e5422/trigger?V=1&count=1" - }, - cluster_id="ae63a10b-4a90-452c-aef1-113a0b255ee3", - created_at="2015-06-27T05:09:43", - domain_id="Default", - id="573aa1ba-bf45-49fd-907d-6b5d6e6adfd3", - name="cluster_inflate", - params={"count": "1"}, - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - type="webhook", - updated_at=None, - user_id="b4ad2d6e18cc2b9c48049f6dbe8a5b3c" - ) - fake_receiver.to_dict = mock.Mock(return_value={}) - self.mock_client.create_receiver = mock.Mock( - return_value=fake_receiver) - self.mock_client.get_receiver = mock.Mock( - return_value=fake_receiver) - - def test_receiver_create_webhook(self): - arglist = ['my_receiver', '--action', 'CLUSTER_SCALE_OUT', - '--cluster', 'my_cluster', '--params', 'count=1', - '--type', 'webhook'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.create_receiver.assert_called_with(**self.args) - - def test_receiver_create_webhook_failed(self): - arglist = ['my_receiver', '--action', 'CLUSTER_SCALE_OUT', - '--params', 'count=1', '--type', 'webhook'] - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn(_('cluster and action parameters are required to create ' - 'webhook type of receiver'), str(error)) - - def test_receiver_create_non_webhook(self): - arglist = ['my_receiver', '--params', 'count=1', - '--type', 'foo'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - args = copy.deepcopy(self.args) - args['type'] = 'foo' - args['cluster_id'] = None - args['action'] = None - self.mock_client.create_receiver.assert_called_with(**args) - - -class TestReceiverUpdate(TestReceiver): - args = { - "action": "CLUSTER_SCALE_OUT", - "name": "test_receiver", - "params": { - "count": "2" - }, - } - - def setUp(self): - super(TestReceiverUpdate, self).setUp() - self.cmd = osc_receiver.UpdateReceiver(self.app, None) - fake_receiver = mock.Mock( - action="CLUSTER_SCALE_IN", - actor={}, - channel={ - "alarm_url": "http://node1:8778/v1/webhooks/e03dd2e5-8f2e-4ec1" - "-8c6a-74ba891e5422/trigger?V=1&count=1" - }, - created_at="2015-06-27T05:09:43", - domain_id="Default", - id="573aa1ba-bf45-49fd-907d-6b5d6e6adfd3", - params={"count": "1"}, - project_id="6e18cc2bdbeb48a5b3cad2dc499f6804", - updated_at=None, - user_id="b4ad2d6e18cc2b9c48049f6dbe8a5b3c" - ) - fake_receiver.name = "cluster_inflate" - fake_receiver.action = "CLUSTER_SCALE_IN" - fake_receiver.params = {"count": "1"} - fake_receiver.to_dict = mock.Mock(return_value={}) - self.mock_client.update_receiver = mock.Mock( - return_value=fake_receiver) - self.mock_client.get_receiver = mock.Mock(return_value=fake_receiver) - self.mock_client.find_receiver = mock.Mock(return_value=fake_receiver) - utils.get_dict_properties = mock.Mock(return_value='') - - def test_receiver_update_defaults(self): - arglist = ['--name', 'test_receiver', '--action', 'CLUSTER_SCALE_OUT', - '--params', 'count=2', '573aa1ba'] - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - self.mock_client.update_receiver.assert_called_with( - "573aa1ba-bf45-49fd-907d-6b5d6e6adfd3", **self.args) - - def test_receiver_update_not_found(self): - arglist = ['--name', 'test_receiver', '--action', 'CLUSTER_SCALE_OUT', - '--params', 'count=2', '573aa1b2'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.mock_client.find_receiver.return_value = None - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, - parsed_args) - self.assertIn('Receiver not found: 573aa1b2', str(error)) - - -class TestReceiverDelete(TestReceiver): - - def setUp(self): - super(TestReceiverDelete, self).setUp() - self.cmd = osc_receiver.DeleteReceiver(self.app, None) - self.mock_client.delete_receiver = mock.Mock() - - def test_receiver_delete(self): - arglist = ['receiver1', 'receiver2', 'receiver3'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_receiver.assert_has_calls( - [mock.call('receiver1', False), mock.call('receiver2', False), - mock.call('receiver3', False)] - ) - - def test_receiver_delete_force(self): - arglist = ['receiver1', 'receiver2', 'receiver3', '--force'] - parsed_args = self.check_parser(self.cmd, arglist, []) - self.cmd.take_action(parsed_args) - self.mock_client.delete_receiver.assert_has_calls( - [mock.call('receiver1', False), mock.call('receiver2', False), - mock.call('receiver3', False)] - ) - - def test_receiver_delete_not_found(self): - arglist = ['my_receiver'] - self.mock_client.delete_receiver.side_effect = ( - sdk_exc.ResourceNotFound) - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, self.cmd.take_action, - parsed_args) - self.assertIn('Failed to delete 1 of the 1 specified receiver(s).', - str(error)) - - def test_receiver_delete_one_found_one_not_found(self): - arglist = ['receiver1', 'receiver2'] - self.mock_client.delete_receiver.side_effect = ( - [None, sdk_exc.ResourceNotFound] - ) - parsed_args = self.check_parser(self.cmd, arglist, []) - error = self.assertRaises(exc.CommandError, - self.cmd.take_action, parsed_args) - self.mock_client.delete_receiver.assert_has_calls( - [mock.call('receiver1', False), mock.call('receiver2', False)] - ) - self.assertEqual('Failed to delete 1 of the 2 specified receiver(s).', - str(error)) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_receiver_delete_prompt_yes(self, mock_stdin): - arglist = ['my_receiver'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'y' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_receiver.assert_called_with('my_receiver', - False) - - @mock.patch('sys.stdin', spec=io.StringIO) - def test_receiver_delete_prompt_no(self, mock_stdin): - arglist = ['my_receiver'] - mock_stdin.isatty.return_value = True - mock_stdin.readline.return_value = 'n' - parsed_args = self.check_parser(self.cmd, arglist, []) - - self.cmd.take_action(parsed_args) - - mock_stdin.readline.assert_called_with() - self.mock_client.delete_receiver.assert_not_called() diff --git a/senlinclient/tests/unit/v1/test_service.py b/senlinclient/tests/unit/v1/test_service.py deleted file mode 100644 index b43ffc4b..00000000 --- a/senlinclient/tests/unit/v1/test_service.py +++ /dev/null @@ -1,43 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from unittest import mock - -from senlinclient.tests.unit.v1 import fakes -from senlinclient.v1 import service as osc_service - - -class TestServiceList(fakes.TestClusteringv1): - columns = ['binary', 'host', 'status', 'state', 'updated_at', - 'disabled_reason'] - - def setUp(self): - super(TestServiceList, self).setUp() - self.mock_client = self.app.client_manager.clustering - self.cmd = osc_service.ListService(self.app, None) - fake_service = mock.Mock( - Binary='senlin-engine', - Host='Host1', - Status='enabled', - State='up', - Updated_at=None, - Disabled_Reason=None, - ) - fake_service.name = 'test_service' - fake_service.to_dict = mock.Mock(return_value={}) - self.mock_client.services = mock.Mock(return_value=[fake_service]) - - def test_service(self): - arglist = [] - parsed_args = self.check_parser(self.cmd, arglist, []) - columns, data = self.cmd.take_action(parsed_args) - self.mock_client.services.assert_called_with() - self.assertEqual(self.columns, columns) diff --git a/senlinclient/v1/__init__.py b/senlinclient/v1/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/senlinclient/v1/action.py b/senlinclient/v1/action.py deleted file mode 100644 index e0244242..00000000 --- a/senlinclient/v1/action.py +++ /dev/null @@ -1,187 +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. - -"""Clustering v1 action implementations""" - -import logging - -from openstack import exceptions as sdk_exc -from osc_lib.command import command -from osc_lib import exceptions as exc -from osc_lib import utils - -from senlinclient.common.i18n import _ -from senlinclient.common import utils as senlin_utils - - -class ListAction(command.Lister): - """List actions.""" - - log = logging.getLogger(__name__ + ".ListAction") - - def get_parser(self, prog_name): - parser = super(ListAction, self).get_parser(prog_name) - parser.add_argument( - '--filters', - metavar='<"key1=value1;key2=value2...">', - help=_("Filter parameters to apply on returned actions. " - "This can be specified multiple times, or once with " - "parameters separated by a semicolon. The valid filter " - "keys are: ['name', 'target', 'action', 'status']. " - "NOTICE: The value of 'target', if provided, " - "must be a full ID."), - action='append' - ) - parser.add_argument( - '--sort', - metavar='[:]', - help=_("Sorting option which is a string containing a list of " - "keys separated by commas. Each key can be optionally " - "appended by a sort direction (:asc or :desc). The valid " - "sort keys are: ['name', 'target', 'action', 'created_at'," - " 'status']") - ) - parser.add_argument( - '--limit', - metavar='', - help=_('Limit the number of actions returned') - ) - parser.add_argument( - '--marker', - metavar='', - help=_('Only return actions that appear after the given action ID') - ) - parser.add_argument( - '--global-project', - default=False, - action="store_true", - help=_('Whether actions from all projects should be listed. ' - ' Default to False. Setting this to True may demand ' - 'for an admin privilege') - ) - parser.add_argument( - '--full-id', - default=False, - action="store_true", - help=_('Print full IDs in list') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - senlin_client = self.app.client_manager.clustering - - columns = ['id', 'name', 'action', 'status', 'target_id', 'depends_on', - 'depended_by', 'created_at', 'cluster_id'] - - queries = { - 'sort': parsed_args.sort, - 'limit': parsed_args.limit, - 'marker': parsed_args.marker, - 'global_project': parsed_args.global_project, - } - - if parsed_args.filters: - queries.update(senlin_utils.format_parameters(parsed_args.filters)) - - actions = senlin_client.actions(**queries) - - formatters = {} - s = None - if not parsed_args.full_id: - s = 8 - formatters['id'] = lambda x: x[:s] - formatters['target_id'] = lambda x: x[:s] - - formatters['depends_on'] = lambda x: '\n'.join(a[:s] for a in x) - formatters['depended_by'] = lambda x: '\n'.join(a[:s] for a in x) - - return ( - columns, - (utils.get_item_properties(a, columns, - formatters=formatters) - for a in actions) - ) - - -def _show_action(senlin_client, action_id): - try: - action = senlin_client.get_action(action_id) - except sdk_exc.ResourceNotFound: - raise exc.CommandError(_('Action not found: %s') - % action_id) - - formatters = { - 'inputs': senlin_utils.json_formatter, - 'outputs': senlin_utils.json_formatter, - 'metadata': senlin_utils.json_formatter, - 'data': senlin_utils.json_formatter, - 'depends_on': senlin_utils.list_formatter, - 'depended_by': senlin_utils.list_formatter, - } - data = action.to_dict() - columns = sorted(data.keys()) - return columns, utils.get_dict_properties(data, columns, - formatters=formatters) - - -class ShowAction(command.ShowOne): - """Show detailed info about the specified action.""" - - log = logging.getLogger(__name__ + ".ShowAction") - - def get_parser(self, prog_name): - parser = super(ShowAction, self).get_parser(prog_name) - parser.add_argument( - 'action', - metavar='', - help=_('Name or ID of the action to show the details for') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - senlin_client = self.app.client_manager.clustering - return _show_action(senlin_client, parsed_args.action) - - -class UpdateAction(command.ShowOne): - """Update an action.""" - - log = logging.getLogger(__name__ + ".UpdateAction") - - def get_parser(self, prog_name): - parser = super(UpdateAction, self).get_parser(prog_name) - parser.add_argument( - '--status', - metavar='', - help=_('The new status for the action') - ) - parser.add_argument( - 'action', - metavar='', - help=_('ID of the action to update') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - - params = { - 'status': parsed_args.status, - } - - senlin_client.update_action(parsed_args.action, **params) - return _show_action(senlin_client, parsed_args.action) diff --git a/senlinclient/v1/build_info.py b/senlinclient/v1/build_info.py deleted file mode 100644 index 9c6dbb55..00000000 --- a/senlinclient/v1/build_info.py +++ /dev/null @@ -1,48 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Clustering v1 build_info action implementations""" - -import logging - -from osc_lib.command import command -from osc_lib import utils - -from senlinclient.common import utils as senlin_utils - - -class BuildInfo(command.ShowOne): - """Retrieve build information.""" - - log = logging.getLogger(__name__ + ".BuildInfo") - - def get_parser(self, prog_name): - parser = super(BuildInfo, self).get_parser(prog_name) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - senlin_client = self.app.client_manager.clustering - result = senlin_client.get_build_info() - - formatters = { - 'api': senlin_utils.json_formatter, - 'engine': senlin_utils.json_formatter, - } - data = { - 'api': result.api, - 'engine': result.engine, - } - columns = ['api', 'engine'] - return columns, utils.get_dict_properties(data, columns, - formatters=formatters) diff --git a/senlinclient/v1/client.py b/senlinclient/v1/client.py deleted file mode 100644 index 119f4205..00000000 --- a/senlinclient/v1/client.py +++ /dev/null @@ -1,512 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from openstack import exceptions - -from senlinclient.common import exc -from senlinclient import plugin - - -class Client(object): - def __init__(self, prof=None, user_agent=None, **kwargs): - try: - conn = plugin.create_connection(prof=prof, - user_agent=user_agent, - **kwargs) - except exceptions.HttpException as ex: - exc.parse_exception(ex.details) - - self.conn = conn - self.service = self.conn.cluster - - ###################################################################### - # The following operations are interfaces exposed to other software - # which invokes senlinclient today. - # These methods form a temporary translation layer. This layer will be - # useless when OpenStackSDK has been adopted all senlin resources. - ###################################################################### - - def profile_types(self, **query): - """List profile types - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-profile-types - """ - return self.service.profile_types(**query) - - def get_profile_type(self, profile_type): - """Show profile type details - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #show-profile-type-details - """ - return self.service.get_profile_type(profile_type) - - def list_profile_type_operations(self, profile_type): - """Show profile type operations - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #show-profile-type-details - """ - return self.service.list_profile_type_operations(profile_type) - - def profiles(self, **query): - """List profiles - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-profiles - """ - return self.service.profiles(**query) - - def create_profile(self, **attrs): - """Create a profile - - Doc link: - https://docs.openstack.org/api-ref/clustering/#create-profile - """ - return self.service.create_profile(**attrs) - - def get_profile(self, profile): - """Show profile details - - Doc link: - https://docs.openstack.org/api-ref/clustering/#show-profile-details - """ - return self.service.get_profile(profile) - - def update_profile(self, profile, **attrs): - """Update a profile - - Doc link: - https://docs.openstack.org/api-ref/clustering/#update-profile - """ - return self.service.update_profile(profile, **attrs) - - def delete_profile(self, profile, ignore_missing=True): - """Delete a profile - - Doc link: - https://docs.openstack.org/api-ref/clustering/#delete-profile - """ - return self.service.delete_profile(profile, ignore_missing) - - def validate_profile(self, **attrs): - """Validate a profile spec - - Doc link: - https://docs.openstack.org/api-ref/clustering/#validate-profile - """ - return self.service.validate_profile(**attrs) - - def policy_types(self, **query): - """List policy types - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-policy-types - """ - return self.service.policy_types(**query) - - def get_policy_type(self, policy_type): - """Show policy type details - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #show-policy-type-details - """ - return self.service.get_policy_type(policy_type) - - def policies(self, **query): - """List policies - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-policies - """ - return self.service.policies(**query) - - def create_policy(self, **attrs): - """Create a policy - - Doc link: - https://docs.openstack.org/api-ref/clustering/#create-policy - """ - return self.service.create_policy(**attrs) - - def get_policy(self, policy): - """Show policy details - - Doc link: - https://docs.openstack.org/api-ref/clustering/#show-policy-details - """ - return self.service.get_policy(policy) - - def update_policy(self, policy, **attrs): - """Update policy - - Doc link: - https://docs.openstack.org/api-ref/clustering/#update-policy - """ - return self.service.update_policy(policy, **attrs) - - def delete_policy(self, policy, ignore_missing=True): - """Delete policy - - Doc link: - https://docs.openstack.org/api-ref/clustering/#delete-policy - """ - return self.service.delete_policy(policy, ignore_missing) - - def validate_policy(self, **attrs): - """validate a policy spec - - Doc link: - https://docs.openstack.org/api-ref/clustering/#validate-policy - """ - return self.service.validate_policy(**attrs) - - def clusters(self, **queries): - """List clusters - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-clusters - """ - return self.service.clusters(**queries) - - def create_cluster(self, **attrs): - """Create a cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/#create-cluster - """ - return self.service.create_cluster(**attrs) - - def get_cluster(self, cluster): - """Show cluster details - - Doc link: - https://docs.openstack.org/api-ref/clustering/#show-cluster-details - """ - return self.service.get_cluster(cluster) - - def update_cluster(self, cluster, **attrs): - """Update cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/#update-cluster - """ - return self.service.update_cluster(cluster, **attrs) - - def delete_cluster(self, cluster, ignore_missing=True, force_delete=False): - """Delete cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/#delete-cluster - """ - return self.service.delete_cluster(cluster, ignore_missing, - force_delete) - - def cluster_add_nodes(self, cluster, nodes): - """Add a node to cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #add-nodes-to-a-cluster - """ - return self.service.add_nodes_to_cluster(cluster, nodes) - - def cluster_del_nodes(self, cluster, nodes): - """Delete a node belongs to cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #remove-nodes-from-a-cluster - """ - return self.service.remove_nodes_from_cluster(cluster, nodes) - - def cluster_replace_nodes(self, cluster, nodes): - """Replace the nodes in a cluster with specified nodes - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #replace-nodes-in-a-cluster - """ - return self.service.replace_nodes_in_cluster(cluster, nodes) - - def cluster_resize(self, cluster, **params): - """Resize cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/#resize-a-cluster - """ - return self.service.resize_cluster(cluster, **params) - - def cluster_scale_out(self, cluster, count): - """Scale out cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/#scale-out-a-cluster - """ - return self.service.scale_out_cluster(cluster, count) - - def cluster_scale_in(self, cluster, count): - """Scale in cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/#scale-in-a-cluster - """ - return self.service.scale_in_cluster(cluster, count) - - def cluster_policies(self, cluster, **queries): - """List all policies attached to cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #list-all-cluster-policies - """ - return self.service.cluster_policies(cluster, **queries) - - def get_cluster_policy(self, policy, cluster): - """Show details of a policy attached to cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #show-cluster-policy-details - """ - return self.service.get_cluster_policy(policy, cluster) - - def cluster_attach_policy(self, cluster, policy, **attrs): - """Attach a policy to cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #attach-a-policy-to-a-cluster - """ - return self.service.attach_policy_to_cluster(cluster, policy, **attrs) - - def cluster_detach_policy(self, cluster, policy): - """Detach a policy from cluster - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #detach-a-policy-from-a-cluster - """ - return self.service.detach_policy_from_cluster(cluster, policy) - - def cluster_update_policy(self, cluster, policy, **attrs): - """Update the policy attachment - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #update-a-policy-on-a-cluster - """ - return self.service.update_cluster_policy(cluster, policy, **attrs) - - def collect_cluster_attrs(self, cluster, path): - """Collect cluster attributes - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #collect-attributes-across-a-cluster - """ - return self.service.collect_cluster_attrs(cluster, path) - - def check_cluster(self, cluster, **params): - """Check cluster's health status - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #check-a-cluster-s-health-status - """ - return self.service.check_cluster(cluster, **params) - - def recover_cluster(self, cluster, **params): - """Recover cluster from failure state - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #recover-a-cluster-to-a-healthy-status - """ - return self.service.recover_cluster(cluster, **params) - - def perform_operation_on_cluster(self, cluster, operation, **params): - """Perform an operation on a cluster. - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #perform-an-operation-on-a-cluster - """ - return self.service.perform_operation_on_cluster(cluster, operation, - **params) - - def nodes(self, **queries): - """List nodes - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-nodes - """ - return self.service.nodes(**queries) - - def create_node(self, **attrs): - """Create a node - - Doc link: - https://docs.openstack.org/api-ref/clustering/#create-node - """ - return self.service.create_node(**attrs) - - def adopt_node(self, preview=False, **attrs): - """Adopt a node - - Doc link: - https://docs.openstack.org/api-ref/clustering/#adopt-node - https://docs.openstack.org/api-ref/clustering/#adopt-node-preview - """ - return self.service.adopt_node(preview, **attrs) - - def get_node(self, node, details=False): - """Show node details - - Doc link: - https://docs.openstack.org/api-ref/clustering/#show-node-details - """ - return self.service.get_node(node, details=details) - - def update_node(self, node, **attrs): - """Update node - - Doc link: - https://docs.openstack.org/api-ref/clustering/#update-node - """ - return self.service.update_node(node, **attrs) - - def delete_node(self, node, ignore_missing=True, force_delete=False): - """Delete node - - Doc link: - https://docs.openstack.org/api-ref/clustering/#delete-node - """ - return self.service.delete_node(node, ignore_missing, force_delete) - - def check_node(self, node, **params): - """Check node's health status - - Doc link: - https://docs.openstack.org/api-ref/clustering/#check-a-node-s-health - """ - return self.service.check_node(node, **params) - - def recover_node(self, node, **params): - """Recover node from failure state - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #recover-a-node-to-healthy-status - """ - return self.service.recover_node(node, **params) - - def perform_operation_on_node(self, node, operation, **params): - """Perform an operation on a node. - - Doc link: - https://docs.openstack.org/api-ref/clustering/ - #perform-an-operation-on-a-node - """ - return self.service.perform_operation_on_node(node, operation, - **params) - - def receivers(self, **queries): - """List receivers - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-receivers - """ - return self.service.receivers(**queries) - - def create_receiver(self, **attrs): - """Creare a receiver - - Doc link: - https://docs.openstack.org/api-ref/clustering/#create-receiver - """ - return self.service.create_receiver(**attrs) - - def get_receiver(self, receiver): - """Show receiver details - - Doc link: - https://docs.openstack.org/api-ref/clustering/#show-receiver-details - """ - return self.service.get_receiver(receiver) - - def update_receiver(self, receiver, **attrs): - """Update receiver - - Doc link: - https://docs.openstack.org/api-ref-clustering-v1.html#updateReceiver - """ - return self.service.update_receiver(receiver, **attrs) - - def delete_receiver(self, receiver, ignore_missing=True): - """Delete receiver - - Doc link: - https://docs.openstack.org/api-ref/clustering/#delete-receiver - """ - return self.service.delete_receiver(receiver, ignore_missing) - - def events(self, **queries): - """List events - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-events - """ - return self.service.events(**queries) - - def get_event(self, event): - """Show event details - - Doc link: - https://docs.openstack.org/api-ref/clustering/#shows-event-details - """ - return self.service.get_event(event) - - def actions(self, **queries): - """List actions - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-actions - """ - return self.service.actions(**queries) - - def get_action(self, action): - """Show action details - - Doc link: - https://docs.openstack.org/api-ref/clustering/#show-action-details - """ - return self.service.get_action(action) - - def update_action(self, action, **attrs): - """Update an action - - Doc link: - https://docs.openstack.org/api-ref/clustering/#update-action - """ - return self.service.update_action(action, **attrs) - - def services(self, **queries): - """List services - - Doc link: - https://docs.openstack.org/api-ref/clustering/#list-services - """ - return self.service.services(**queries) diff --git a/senlinclient/v1/cluster.py b/senlinclient/v1/cluster.py deleted file mode 100644 index 45115f95..00000000 --- a/senlinclient/v1/cluster.py +++ /dev/null @@ -1,1390 +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. - -"""Clustering v1 cluster action implementations""" - -import logging -import subprocess -import sys -import threading -import time - -from openstack import exceptions as sdk_exc -from osc_lib.command import command -from osc_lib import exceptions as exc -from osc_lib import utils -from oslo_utils import strutils - -from senlinclient.common.i18n import _ -from senlinclient.common import utils as senlin_utils - - -class ListCluster(command.Lister): - """List clusters.""" - - log = logging.getLogger(__name__ + ".ListCluster") - - def get_parser(self, prog_name): - parser = super(ListCluster, self).get_parser(prog_name) - parser.add_argument( - '--filters', - metavar='<"key1=value1;key2=value2...">', - help=_("Filter parameters to apply on returned clusters. " - "This can be specified multiple times, or once with " - "parameters separated by a semicolon. The valid filter" - " keys are: ['status', 'name']"), - action='append' - ) - parser.add_argument( - '--sort', - metavar='[:]', - help=_("Sorting option which is a string containing a list of " - "keys separated by commas. Each key can be optionally " - "appended by a sort direction (:asc or :desc). The valid " - "sort keys are: ['name', 'status', 'init_at', " - "'created_at', 'updated_at']")) - parser.add_argument( - '--limit', - metavar='', - help=_('Limit the number of clusters returned') - ) - parser.add_argument( - '--marker', - metavar='', - help=_('Only return clusters that appear after the given cluster ' - 'ID') - ) - parser.add_argument( - '--global-project', - default=False, - action="store_true", - help=_('Indicate that the cluster list should include clusters ' - 'from all projects. This option is subject to access ' - 'policy checking. Default is False') - ) - parser.add_argument( - '--full-id', - default=False, - action="store_true", - help=_('Print full IDs in list') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - senlin_client = self.app.client_manager.clustering - columns = ['id', 'name', 'status', 'created_at', 'updated_at'] - queries = { - 'limit': parsed_args.limit, - 'marker': parsed_args.marker, - 'sort': parsed_args.sort, - 'global_project': parsed_args.global_project, - } - if parsed_args.filters: - queries.update(senlin_utils.format_parameters(parsed_args.filters)) - - clusters = senlin_client.clusters(**queries) - formatters = {} - if parsed_args.global_project: - columns.append('project_id') - if not parsed_args.full_id: - formatters = { - 'id': lambda x: x[:8] - } - if 'project_id' in columns: - formatters['project_id'] = lambda x: x[:8] - - return ( - columns, - (utils.get_item_properties(c, columns, formatters=formatters) - for c in clusters) - ) - - -class ShowCluster(command.ShowOne): - """Show details of the cluster.""" - - log = logging.getLogger(__name__ + ".ShowCluster") - - def get_parser(self, prog_name): - parser = super(ShowCluster, self).get_parser(prog_name) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to show') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - senlin_client = self.app.client_manager.clustering - return _show_cluster(senlin_client, parsed_args.cluster) - - -def _show_cluster(senlin_client, cluster_id): - try: - cluster = senlin_client.get_cluster(cluster_id) - except sdk_exc.ResourceNotFound: - raise exc.CommandError(_('Cluster not found: %s') % cluster_id) - - formatters = { - 'config': senlin_utils.json_formatter, - 'metadata': senlin_utils.json_formatter, - 'node_ids': senlin_utils.list_formatter - } - data = cluster.to_dict() - if 'is_profile_only' in data: - data.pop('is_profile_only') - columns = sorted(data.keys()) - return columns, utils.get_dict_properties(data, columns, - formatters=formatters) - - -class CreateCluster(command.ShowOne): - """Create the cluster.""" - - log = logging.getLogger(__name__ + ".CreateCluster") - - def get_parser(self, prog_name): - parser = super(CreateCluster, self).get_parser(prog_name) - parser.add_argument( - '--config', - metavar='<"key1=value1;key2=value2...">', - help=_('Configuration of the cluster. Default to {}. ' - 'This can be specified multiple times, or once with ' - 'key-value pairs separated by a semicolon.'), - action='append' - ) - parser.add_argument( - '--min-size', - metavar='', - default=0, - help=_('Min size of the cluster. Default to 0') - ) - parser.add_argument( - '--max-size', - metavar='', - default=-1, - help=_('Max size of the cluster. Default to -1, means unlimited') - ) - parser.add_argument( - '--desired-capacity', - metavar='', - default=0, - help=_('Desired capacity of the cluster. Default to min_size if ' - 'min_size is specified else 0.') - ) - parser.add_argument( - '--timeout', - metavar='', - type=int, - help=_('Cluster creation timeout in seconds') - ) - parser.add_argument( - '--metadata', - metavar='<"key1=value1;key2=value2...">', - help=_('Metadata values to be attached to the cluster. ' - 'This can be specified multiple times, or once with ' - 'key-value pairs separated by a semicolon.'), - action='append' - ) - parser.add_argument( - '--profile', - metavar='', - required=True, - help=_('Default profile Id or name used for this cluster') - ) - parser.add_argument( - 'name', - metavar='', - help=_('Name of the cluster to create') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster creation to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - - senlin_client = self.app.client_manager.clustering - if parsed_args.min_size and not parsed_args.desired_capacity: - parsed_args.desired_capacity = parsed_args.min_size - attrs = { - 'config': senlin_utils.format_parameters(parsed_args.config), - 'name': parsed_args.name, - 'profile_id': parsed_args.profile, - 'min_size': parsed_args.min_size, - 'max_size': parsed_args.max_size, - 'desired_capacity': parsed_args.desired_capacity, - 'metadata': senlin_utils.format_parameters(parsed_args.metadata), - 'timeout': parsed_args.timeout - } - - cluster = senlin_client.create_cluster(**attrs) - if parsed_args.wait: - senlin_utils.await_cluster_status(senlin_client, cluster.id) - return _show_cluster(senlin_client, cluster.id) - - -class UpdateCluster(command.ShowOne): - """Update the cluster.""" - - log = logging.getLogger(__name__ + ".UpdateCluster") - - def get_parser(self, prog_name): - parser = super(UpdateCluster, self).get_parser(prog_name) - parser.add_argument( - '--config', - metavar='<"key1=value1;key2=value2...">', - help=_('Configuration of the cluster. ' - 'This can be specified multiple times, or once with ' - 'key-value pairs separated by a semicolon. ' - 'Any existing configuration values on the cluster are ' - 'wiped out when using this option.'), - action='append' - ) - parser.add_argument( - '--profile', - metavar='', - help=_('ID or name of new profile to use') - ) - parser.add_argument( - '--profile-only', - default=False, metavar='', - help=_("Whether the cluster should be updated profile only. " - "If false, it will be applied to all existing nodes. " - "If true, any newly created nodes will use the new profile," - "but existing nodes will not be changed. Default is False.") - ) - parser.add_argument( - '--timeout', - metavar='', - help=_('New timeout (in seconds) value for the cluster') - ) - parser.add_argument( - '--metadata', - metavar='<"key1=value1;key2=value2...">', - help=_("Metadata values to be attached to the cluster. " - "This can be specified multiple times, or once with " - "key-value pairs separated by a semicolon. Use '{}' " - "can clean metadata "), - action='append' - ) - parser.add_argument( - '--name', - metavar='', - help=_('New name for the cluster to update') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to be updated') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster update to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - cluster = senlin_client.find_cluster(parsed_args.cluster) - if cluster is None: - raise exc.CommandError(_('Cluster not found: %s') % - parsed_args.cluster) - attrs = { - 'name': parsed_args.name, - 'profile_id': parsed_args.profile, - 'profile_only': strutils.bool_from_string( - parsed_args.profile_only, - strict=True, - ), - 'timeout': parsed_args.timeout, - } - - if parsed_args.config is not None: - attrs['config'] = senlin_utils.format_parameters( - parsed_args.config) - if parsed_args.metadata is not None: - attrs['metadata'] = senlin_utils.format_parameters( - parsed_args.metadata) - - senlin_client.update_cluster(cluster, **attrs) - if parsed_args.wait: - # PATCH operations do not currently return an action to await. - # introducing a delay to allow the cluster to transition state - # out of ACTIVE before inspection. - time.sleep(1) - senlin_utils.await_cluster_status(senlin_client, cluster.id) - return _show_cluster(senlin_client, cluster.id) - - -class DeleteCluster(command.Command): - """Delete the cluster(s).""" - - log = logging.getLogger(__name__ + ".DeleteCluster") - - def get_parser(self, prog_name): - parser = super(DeleteCluster, self).get_parser(prog_name) - parser.add_argument( - 'cluster', - metavar='', - nargs='+', - help=_('Name or ID of cluster(s) to delete.') - ) - parser.add_argument( - '--force-delete', - action='store_true', - help=_('Force to delete cluster(s).') - ) - parser.add_argument( - '--force', - action='store_true', - help=_('Skip yes/no prompt (assume yes).') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster delete to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - - try: - if not parsed_args.force and sys.stdin.isatty(): - sys.stdout.write( - _("Are you sure you want to delete this cluster(s)" - " [y/N]?")) - sys.stdout.flush() - prompt_response = sys.stdin.readline().lower() - if not prompt_response.startswith('y'): - return - except KeyboardInterrupt: # Ctrl-c - self.log.info('Ctrl-c detected.') - return - except EOFError: # Ctrl-d - self.log.info('Ctrl-d detected') - return - - result = {} - for cid in parsed_args.cluster: - try: - action = senlin_client.delete_cluster( - cid, False, parsed_args.force_delete) - result[cid] = ('OK', action['id']) - except Exception as ex: - result[cid] = ('ERROR', str(ex)) - - for cid, a in result.items(): - senlin_utils.print_action_result(cid, a) - if parsed_args.wait: - if a[0] == 'OK': - senlin_utils.await_action(senlin_client, a[1]) - senlin_utils.await_cluster_delete(senlin_client, cid) - - -class ResizeCluster(command.ShowOne): - """Resize a cluster.""" - - log = logging.getLogger(__name__ + ".ResizeCluster") - - def get_parser(self, prog_name): - parser = super(ResizeCluster, self).get_parser(prog_name) - parser.add_argument( - '--capacity', - metavar='', - type=int, - help=_('The desired number of nodes of the cluster') - ) - parser.add_argument( - '--adjustment', - metavar='', - type=int, - help=_('A positive integer meaning the number of nodes to add, ' - 'or a negative integer indicating the number of nodes to ' - 'remove') - ) - parser.add_argument( - '--percentage', - metavar='', - type=float, - help=_('A value that is interpreted as the percentage of size ' - 'adjustment. This value can be positive or negative') - ) - parser.add_argument( - '--min-step', - metavar='', - type=int, - help=_('An integer specifying the number of nodes for adjustment ' - 'when is specified') - ) - parser.add_argument( - '--strict', - action='store_true', - default=False, - help=_('A boolean specifying whether the resize should be ' - 'performed on a best-effort basis when the new capacity ' - 'may go beyond size constraints') - ) - parser.add_argument( - '--min-size', - metavar='min', - type=int, - help=_('New lower bound of cluster size') - ) - parser.add_argument( - '--max-size', - metavar='max', - type=int, - help=_('New upper bound of cluster size. A value of -1 indicates ' - 'no upper limit on cluster size') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to operate on') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster resize to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - - action_args = {} - - capacity = parsed_args.capacity - adjustment = parsed_args.adjustment - percentage = parsed_args.percentage - min_size = parsed_args.min_size - max_size = parsed_args.max_size - min_step = parsed_args.min_step - wait = parsed_args.wait - - if sum(v is not None for v in (capacity, adjustment, percentage, - min_size, max_size)) == 0: - raise exc.CommandError(_("At least one parameter of 'capacity', " - "'adjustment', 'percentage', 'min_size' " - "and 'max_size' should be specified.")) - - if sum(v is not None for v in (capacity, adjustment, percentage)) > 1: - raise exc.CommandError(_("Only one of 'capacity', 'adjustment' and" - " 'percentage' can be specified.")) - - action_args['adjustment_type'] = None - action_args['number'] = None - - if capacity is not None: - if capacity < 0: - raise exc.CommandError(_('Cluster capacity must be larger than' - ' or equal to zero.')) - action_args['adjustment_type'] = 'EXACT_CAPACITY' - action_args['number'] = capacity - - if adjustment is not None: - if adjustment == 0: - raise exc.CommandError(_('Adjustment cannot be zero.')) - action_args['adjustment_type'] = 'CHANGE_IN_CAPACITY' - action_args['number'] = adjustment - - if percentage is not None: - if (percentage == 0 or percentage == 0.0): - raise exc.CommandError(_('Percentage cannot be zero.')) - action_args['adjustment_type'] = 'CHANGE_IN_PERCENTAGE' - action_args['number'] = percentage - - if min_step is not None and percentage is None: - raise exc.CommandError(_('Min step is only used with ' - 'percentage.')) - - if min_size is not None: - if min_size < 0: - raise exc.CommandError(_('Min size cannot be less than zero.')) - if max_size is not None and max_size >= 0 and min_size > max_size: - raise exc.CommandError(_('Min size cannot be larger than ' - 'max size.')) - if capacity is not None and min_size > capacity: - raise exc.CommandError(_('Min size cannot be larger than the ' - 'specified capacity')) - - if max_size is not None: - if capacity is not None and max_size > 0 and max_size < capacity: - raise exc.CommandError(_('Max size cannot be less than the ' - 'specified capacity.')) - # do a normalization - if max_size < 0: - max_size = -1 - - action_args['min_size'] = min_size - action_args['max_size'] = max_size - action_args['min_step'] = min_step - action_args['strict'] = parsed_args.strict - - resp = senlin_client.resize_cluster(parsed_args.cluster, **action_args) - - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if wait: - senlin_utils.await_action(senlin_client, resp['action']) - senlin_utils.await_cluster_status(senlin_client, - parsed_args.cluster) - return _show_cluster(senlin_client, parsed_args.cluster) - else: - print('Request error: %s' % resp) - - return '', '' - - -class ScaleInCluster(command.ShowOne): - """Scale in a cluster by the specified number of nodes.""" - - log = logging.getLogger(__name__ + ".ScaleInCluster") - - def get_parser(self, prog_name): - parser = super(ScaleInCluster, self).get_parser(prog_name) - parser.add_argument( - '--count', - metavar='', - help=_('Number of nodes to be deleted from the specified cluster') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to operate on') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster scale-in to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - - resp = senlin_client.scale_in_cluster(parsed_args.cluster, - parsed_args.count) - status_code = resp.get('code', None) - if status_code in [409]: - raise exc.CommandError(_( - 'Unable to scale in cluster: %s') % resp['error']['message']) - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if parsed_args.wait: - senlin_utils.await_action(senlin_client, resp['action']) - senlin_utils.await_cluster_status(senlin_client, - parsed_args.cluster) - return _show_cluster(senlin_client, parsed_args.cluster) - else: - print('Request error: %s' % resp) - - return '', '' - - -class ScaleOutCluster(command.ShowOne): - """Scale out a cluster by the specified number of nodes.""" - - log = logging.getLogger(__name__ + ".ScaleOutCluster") - - def get_parser(self, prog_name): - parser = super(ScaleOutCluster, self).get_parser(prog_name) - parser.add_argument( - '--count', - metavar='', - help=_('Number of nodes to be added to the specified cluster') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to operate on') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster scale-out to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - - resp = senlin_client.scale_out_cluster(parsed_args.cluster, - parsed_args.count) - status_code = resp.get('code', None) - if status_code in [409]: - raise exc.CommandError(_( - 'Unable to scale out cluster: %s') % resp['error']['message']) - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if parsed_args.wait: - senlin_utils.await_action(senlin_client, resp['action']) - senlin_utils.await_cluster_status(senlin_client, - parsed_args.cluster) - return _show_cluster(senlin_client, parsed_args.cluster) - else: - print('Request error: %s' % resp) - - return '', '' - - -class ClusterPolicyAttach(command.Command): - """Attach policy to cluster.""" - - log = logging.getLogger(__name__ + ".ClusterPolicyAttach") - - def get_parser(self, prog_name): - parser = super(ClusterPolicyAttach, self).get_parser(prog_name) - parser.add_argument( - '--enabled', - metavar='', - default=True, - help=_('Whether the policy should be enabled once attached. ' - 'Default to True') - ) - parser.add_argument( - '--policy', - metavar='', - required=True, - help=_('ID or name of policy to be attached') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to operate on') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster policy-attach to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - - kwargs = { - 'enabled': strutils.bool_from_string(parsed_args.enabled, - strict=True), - } - - resp = senlin_client.attach_policy_to_cluster(parsed_args.cluster, - parsed_args.policy, - **kwargs) - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if parsed_args.wait: - senlin_utils.await_action(senlin_client, resp['action']) - else: - print('Request error: %s' % resp) - - -class ClusterPolicyDetach(command.Command): - """Detach policy from cluster.""" - - log = logging.getLogger(__name__ + ".ClusterPolicyDetach") - - def get_parser(self, prog_name): - parser = super(ClusterPolicyDetach, self).get_parser(prog_name) - parser.add_argument( - '--policy', - metavar='', - required=True, - help=_('ID or name of policy to be detached') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to operate on') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster policy-detach to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - resp = senlin_client.detach_policy_from_cluster(parsed_args.cluster, - parsed_args.policy) - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if parsed_args.wait: - senlin_utils.await_action(senlin_client, resp['action']) - else: - print('Request error: %s' % resp) - - -class ClusterNodeList(command.Lister): - """List nodes from cluster.""" - - log = logging.getLogger(__name__ + ".ClusterNodeList") - - def get_parser(self, prog_name): - parser = super(ClusterNodeList, self).get_parser(prog_name) - parser.add_argument( - '--filters', - metavar='', - help=_("Filter parameters to apply on returned nodes. " - "This can be specified multiple times, or once with " - "parameters separated by a semicolon. The valid filter " - "keys are: ['status', 'name']"), - action='append' - ) - parser.add_argument( - '--sort', - metavar='[:]', - help=_("Sorting option which is a string containing a list of " - "keys separated by commas. Each key can be optionally " - "appended by a sort direction (:asc or :desc)' The valid " - "sort keys are:['index', 'name', 'status', 'init_at', " - "'created_at', 'updated_at']") - ) - parser.add_argument( - '--limit', - metavar='', - help=_('Limit the number of nodes returned') - ) - parser.add_argument( - '--marker', - metavar='', - help=_('Only return nodes that appear after the given node ID') - ) - parser.add_argument( - '--full-id', - default=False, - action="store_true", - help=_('Print full IDs in list') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to nodes from') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - queries = { - 'cluster_id': parsed_args.cluster, - 'sort': parsed_args.sort, - 'limit': parsed_args.limit, - 'marker': parsed_args.marker, - } - if parsed_args.filters: - queries.update(senlin_utils.format_parameters(parsed_args.filters)) - - nodes = senlin_client.nodes(**queries) - if not parsed_args.full_id: - formatters = { - 'id': lambda x: x[:8], - 'physical_id': lambda x: x[:8] if x else '' - } - else: - formatters = {} - - columns = ['id', 'name', 'index', 'status', 'physical_id', - 'created_at'] - return ( - columns, - (utils.get_item_properties(n, columns, formatters=formatters) - for n in nodes) - ) - - -class ClusterNodeAdd(command.ShowOne): - """Add specified nodes to cluster.""" - log = logging.getLogger(__name__ + ".ClusterNodeAdd") - - def get_parser(self, prog_name): - parser = super(ClusterNodeAdd, self).get_parser(prog_name) - parser.add_argument( - '--nodes', - metavar='', - required=True, - help=_('ID or name of nodes to be added; multiple nodes can be' - ' separated with ","') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to operate on') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster members add to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - node_ids = parsed_args.nodes.split(',') - resp = senlin_client.add_nodes_to_cluster(parsed_args.cluster, - node_ids) - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if parsed_args.wait: - senlin_utils.await_action(senlin_client, resp['action']) - return _show_cluster(senlin_client, parsed_args.cluster) - else: - print('Request error: %s' % resp) - - return '', '' - - -class ClusterNodeDel(command.ShowOne): - """Delete specified nodes from cluster.""" - log = logging.getLogger(__name__ + ".ClusterNodeDel") - - def get_parser(self, prog_name): - parser = super(ClusterNodeDel, self).get_parser(prog_name) - parser.add_argument( - '--nodes', - metavar='', - required=True, - help=_('Name or ID of nodes to be deleted; multiple nodes can be ' - 'separated with ","') - ) - parser.add_argument( - '-d', - '--destroy-after-deletion', - required=False, - default=False, - help=_('Whether nodes should be destroyed after deleted. ' - 'Default is False.') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to operate on') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster members delete to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - node_ids = parsed_args.nodes.split(',') - destroy = parsed_args.destroy_after_deletion - destroy = strutils.bool_from_string(destroy, strict=True) - kwargs = {"destroy_after_deletion": destroy} - resp = senlin_client.remove_nodes_from_cluster( - parsed_args.cluster, node_ids, **kwargs) - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if parsed_args.wait: - senlin_utils.await_action(senlin_client, resp['action']) - return _show_cluster(senlin_client, parsed_args.cluster) - else: - print('Request error: %s' % resp) - - return '', '' - - -class ClusterNodeReplace(command.ShowOne): - """Replace the nodes in a cluster with specified nodes.""" - log = logging.getLogger(__name__ + ".ClusterNodeReplace") - - def get_parser(self, prog_name): - parser = super(ClusterNodeReplace, self).get_parser(prog_name) - parser.add_argument( - '--nodes', - metavar='', - required=True, - help=_("OLD_NODE is the name or ID of a node to be replaced, " - "NEW_NODE is the name or ID of a node as replacement. " - "This can be specified multiple times, or once with " - "node-pairs separated by a comma ','."), - action='append' - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('Name or ID of cluster to operate on') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster members replace to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - nodepairs = {} - for nodepair in parsed_args.nodes: - key = nodepair.split('=')[0] - value = nodepair.split('=')[1] - nodepairs[key] = value - resp = senlin_client.replace_nodes_in_cluster(parsed_args.cluster, - nodepairs) - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if parsed_args.wait: - senlin_utils.await_action(senlin_client, resp['action']) - return _show_cluster(senlin_client, parsed_args.cluster) - else: - print('Request error: %s' % resp) - - return '', '' - - -class CheckCluster(command.Lister): - """Check the cluster(s).""" - log = logging.getLogger(__name__ + ".CheckCluster") - - def get_parser(self, prog_name): - parser = super(CheckCluster, self).get_parser(prog_name) - parser.add_argument( - 'cluster', - metavar='', - nargs='+', - help=_('ID or name of cluster(s) to operate on.') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster check to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - - cluster_actions = {} - - for cid in parsed_args.cluster: - try: - resp = senlin_client.check_cluster(cid) - except sdk_exc.ResourceNotFound: - raise exc.CommandError(_('Cluster not found: %s') % cid) - if 'action' in resp: - print('Cluster check request on cluster %(cid)s is ' - 'accepted by action %(action)s.' - % {'cid': cid, 'action': resp['action']}) - cluster_actions[cid] = resp['action'] - else: - print('Request error: %s' % resp) - - # generate the output after all actions have been accepted/rejected - if parsed_args.wait and len(cluster_actions) > 0: - for cid, action in cluster_actions.items(): - senlin_utils.await_action(senlin_client, action) - senlin_utils.await_cluster_status(senlin_client, cid) - return _list_cluster_summaries(senlin_client, - cluster_actions.keys()) - - return '', '' - - -def _list_cluster_summaries(senlin_client, cluster_ids): - clusters = [] - for cluster_id in cluster_ids: - try: - cluster = senlin_client.get_cluster(cluster_id) - except sdk_exc.ResourceNotFound: - raise exc.CommandError(_('Cluster not found: %s') % cluster_id) - - clusters.append(cluster) - - columns = ['ID', 'Name', 'Status', 'Status Reason'] - formatters = {} - props = (utils.get_item_properties(c, columns, formatters=formatters) - for c in clusters) - return columns, props - - -class RecoverCluster(command.Lister): - """Recover the cluster(s).""" - log = logging.getLogger(__name__ + ".RecoverCluster") - - def get_parser(self, prog_name): - parser = super(RecoverCluster, self).get_parser(prog_name) - parser.add_argument( - 'cluster', - metavar='', - nargs='+', - help=_('ID or name of cluster(s) to operate on.') - ) - parser.add_argument( - '--check', - metavar='', - default=False, - help=_("Whether the cluster should check it's nodes status before " - "doing cluster recover. Default is false") - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster recover to complete') - ) - - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - - params = { - 'check': strutils.bool_from_string(parsed_args.check, strict=True) - } - - cluster_actions = {} - for cid in parsed_args.cluster: - try: - resp = senlin_client.recover_cluster(cid, **params) - except sdk_exc.ResourceNotFound: - raise exc.CommandError(_('Cluster not found: %s') % cid) - if 'action' in resp: - print('Cluster recover request on cluster %(cid)s is ' - 'accepted by action %(action)s.' - % {'cid': cid, 'action': resp['action']}) - cluster_actions[cid] = resp['action'] - else: - print('Request error: %s' % resp) - - # generate the output after all actions have been accepted/rejected - if parsed_args.wait and len(cluster_actions) > 0: - for cid, action in cluster_actions.items(): - senlin_utils.await_action(senlin_client, action) - senlin_utils.await_cluster_status(senlin_client, cid) - return _list_cluster_summaries(senlin_client, - cluster_actions.keys()) - - return '', '' - - -class ClusterCollect(command.Lister): - """Collect attributes across a cluster.""" - log = logging.getLogger(__name__ + ".ClusterCollect") - - def get_parser(self, prog_name): - parser = super(ClusterCollect, self).get_parser(prog_name) - parser.add_argument( - '--full-id', - default=False, - action="store_true", - help=_('Print full IDs in list') - ) - parser.add_argument( - '--path', - metavar='', - required=True, - help=_('JSON path expression for attribute to be collected') - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('ID or name of cluster(s) to operate on.') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - attrs = senlin_client.collect_cluster_attrs(parsed_args.cluster, - parsed_args.path) - columns = ['node_id', 'attr_value'] - formatters = {} - if not parsed_args.full_id: - formatters = { - 'node_id': lambda x: x[:8] - } - return (columns, - (utils.get_item_properties(a, columns, formatters=formatters) - for a in attrs)) - - -class ClusterOp(command.ShowOne): - """Perform an operation on all nodes across a cluster.""" - log = logging.getLogger(__name__ + ".ClusterOp") - - def get_parser(self, prog_name): - parser = super(ClusterOp, self).get_parser(prog_name) - parser.add_argument( - '--operation', - metavar='', - required=True, - help=_('Operation to be performed on the cluster') - ) - parser.add_argument( - '--params', - metavar='', - help=_("Parameters to for the specified operation. " - "This can be specified multiple times, or once with " - "parameters separated by a semicolon."), - action='append' - ) - parser.add_argument( - 'cluster', - metavar='', - help=_('ID or name of cluster to operate on.') - ) - parser.add_argument( - '--wait', - action='store_true', - help=_('Wait for cluster operation to complete') - ) - return parser - - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - senlin_client = self.app.client_manager.clustering - cid = parsed_args.cluster - if parsed_args.params: - params = senlin_utils.format_parameters(parsed_args.params) - else: - params = {} - - try: - resp = senlin_client.perform_operation_on_cluster( - cid, parsed_args.operation, **params) - except sdk_exc.ResourceNotFound: - raise exc.CommandError(_('Cluster not found: %s') % cid) - if 'action' in resp: - print('Request accepted by action: %s' % resp['action']) - if parsed_args.wait: - senlin_utils.await_action(senlin_client, resp['action']) - senlin_utils.await_cluster_status(senlin_client, cid) - return _show_cluster(senlin_client, cid) - else: - print('Request error: %s' % resp) - - return '', '' - - -class ClusterRun(command.Command): - """Run scripts on cluster.""" - log = logging.getLogger(__name__ + ".ClusterRun") - - def get_parser(self, prog_name): - parser = super(ClusterRun, self).get_parser(prog_name) - parser.add_argument( - '--port', - metavar='', - type=int, - default=22, - help=_('The TCP port to use for SSH connection') - ) - parser.add_argument( - '--address-type', - metavar='', - default='floating', - help=_("The type of IP address to use. Possible values include " - "'fixed' and 'floating' (the default)") - ) - parser.add_argument( - '--network', - metavar='', - default='', - help=_("The network to use for SSH connection") - ) - parser.add_argument( - '--ipv6', - action="store_true", - default=False, - help=_("Whether the IPv6 address should be used for SSH. Default " - "to use IPv4 address.") - ) - parser.add_argument( - '--user', - metavar='', - default='root', - help=_("The login name to use for SSH connection. Default to " - "'root'.") - ) - parser.add_argument( - '--identity-file', - metavar='', - help=_("The private key file to use, same as the '-i' SSH option") - ) - parser.add_argument( - '--ssh-options', - metavar='', - default="", - help=_("Extra options to pass to SSH. See: man ssh.") - ) - parser.add_argument( - '--script', - metavar='