From 5f534155932abf8a5754278e4b43d03fbf23b603 Mon Sep 17 00:00:00 2001 From: Ghanshyam Mann Date: Fri, 10 May 2024 14:29:23 -0700 Subject: [PATCH] Retire Senlin: remove repo content Senlin project is retiring - https://review.opendev.org/c/openstack/governance/+/919347 this commit remove the content of this project repo Depends-On: https://review.opendev.org/c/openstack/project-config/+/919348/ Change-Id: Id24a51f183aeeb80f0d80b16759694e602b26824 --- .gitignore | 67 - .stestr.conf | 3 - .zuul.yaml | 41 - CONTRIBUTING.rst | 16 - LICENSE | 175 -- README.rst | 24 +- TODO | 23 - bindep.txt | 5 - doc/.gitignore | 2 - doc/Makefile | 177 -- doc/requirements.txt | 6 - doc/source/cli/index.rst | 88 - doc/source/conf.py | 70 - doc/source/contributor/index.rst | 55 - doc/source/index.rst | 21 - doc/source/install/index.rst | 36 - releasenotes/notes/.placeholder | 0 .../notes/bug-1814171-b1c58797c9ca9f44.yaml | 6 - .../cli-deprecation-241b9569b85f8fbd.yaml | 4 - .../cluster-collect-a9d1bc8c2e799c7c.yaml | 5 - .../cluster-policy-list-42ff03ef25d64dd1.yaml | 4 - .../notes/cluster-run-210247ab70b289a5.yaml | 5 - ...ster-scaling-command-e0d96f2cd0c7ca5f.yaml | 5 - .../deletion-output-a841931367a2689d.yaml | 5 - .../notes/drop-py-2-7-cced38f13fd3b44c.yaml | 6 - .../notes/fix-region-732c2be90e58c347.yaml | 3 - .../notes/force-delete-c8d6cf4d6f049cb2.yaml | 3 - .../micro-version-1.10-dabb632bfa40b79b.yaml | 3 - .../notes/micro-version-a292ce3b00d886af.yaml | 4 - .../node-check-recover-469bf81db9f9f1ec.yaml | 3 - .../notes/others-e13ff69738d062c6.yaml | 7 - .../policy-validate-193a5ebb7db3440a.yaml | 4 - .../profile-validate-587f1a964e93c0bf.yaml | 4 - .../notes/python-3.5-c9fd8e34c4046357.yaml | 3 - .../receiver-create-8305d4efbdf35f35.yaml | 5 - .../retire-senlin-cli-8ba21807b584993d.yaml | 4 - .../senlinclient-1.1.0-daf1f24c73ee8b17.yaml | 10 - .../senlinclient-1.2.0-4680ea85ba2dc6c8.yaml | 10 - .../test-function-test-d90d7af1994a5f88.yaml | 4 - releasenotes/source/2023.1.rst | 6 - releasenotes/source/2023.2.rst | 6 - releasenotes/source/_static/.placeholder | 0 releasenotes/source/_templates/.placeholder | 0 releasenotes/source/conf.py | 275 --- releasenotes/source/index.rst | 23 - .../locale/en_GB/LC_MESSAGES/releasenotes.po | 288 ---- .../locale/fr/LC_MESSAGES/releasenotes.po | 42 - .../locale/zh_CN/LC_MESSAGES/releasenotes.po | 40 - releasenotes/source/newton.rst | 6 - releasenotes/source/ocata.rst | 6 - releasenotes/source/pike.rst | 6 - releasenotes/source/queens.rst | 6 - releasenotes/source/rocky.rst | 6 - releasenotes/source/stein.rst | 6 - releasenotes/source/train.rst | 6 - releasenotes/source/unreleased.rst | 5 - releasenotes/source/ussuri.rst | 6 - releasenotes/source/victoria.rst | 6 - releasenotes/source/wallaby.rst | 6 - releasenotes/source/xena.rst | 6 - releasenotes/source/yoga.rst | 6 - releasenotes/source/zed.rst | 6 - requirements.txt | 19 - senlinclient/__init__.py | 16 - senlinclient/client.py | 23 - senlinclient/common/__init__.py | 0 senlinclient/common/exc.py | 312 ---- senlinclient/common/format_utils.py | 51 - senlinclient/common/i18n.py | 24 - senlinclient/common/utils.py | 236 --- .../locale/zh_CN/LC_MESSAGES/senlinclient.po | 535 ------ senlinclient/plugin.py | 118 -- senlinclient/tests/__init__.py | 0 senlinclient/tests/functional/__init__.py | 0 senlinclient/tests/functional/base.py | 176 -- .../functional/policies/deletion_policy.yaml | 19 - .../functional/profiles/cirros_basic.yaml | 12 - senlinclient/tests/functional/test_actions.py | 25 - .../tests/functional/test_cluster_policy.py | 109 -- .../tests/functional/test_clusters.py | 279 --- senlinclient/tests/functional/test_events.py | 25 - senlinclient/tests/functional/test_help.py | 22 - senlinclient/tests/functional/test_nodes.py | 104 -- .../tests/functional/test_policies.py | 40 - .../tests/functional/test_policy_types.py | 37 - .../tests/functional/test_profile_types.py | 42 - .../tests/functional/test_profiles.py | 40 - .../tests/functional/test_readonly_senlin.py | 24 - .../tests/functional/test_receivers.py | 57 - senlinclient/tests/functional/test_version.py | 20 - .../tests/test_specs/deletion_policy.yaml | 8 - .../tests/test_specs/nova_server.yaml | 6 - senlinclient/tests/unit/__init__.py | 0 senlinclient/tests/unit/fakes.py | 25 - senlinclient/tests/unit/test_format_utils.py | 91 - senlinclient/tests/unit/test_plugin.py | 72 - senlinclient/tests/unit/test_utils.py | 147 -- senlinclient/tests/unit/v1/__init__.py | 0 senlinclient/tests/unit/v1/fakes.py | 176 -- senlinclient/tests/unit/v1/test_action.py | 222 --- senlinclient/tests/unit/v1/test_build_info.py | 35 - senlinclient/tests/unit/v1/test_client.py | 488 ------ senlinclient/tests/unit/v1/test_cluster.py | 1520 ----------------- .../tests/unit/v1/test_cluster_policy.py | 100 -- senlinclient/tests/unit/v1/test_event.py | 165 -- senlinclient/tests/unit/v1/test_node.py | 658 ------- senlinclient/tests/unit/v1/test_policy.py | 441 ----- .../tests/unit/v1/test_policy_type.py | 96 -- senlinclient/tests/unit/v1/test_profile.py | 449 ----- .../tests/unit/v1/test_profile_type.py | 137 -- senlinclient/tests/unit/v1/test_receiver.py | 373 ---- senlinclient/tests/unit/v1/test_service.py | 43 - senlinclient/v1/__init__.py | 0 senlinclient/v1/action.py | 187 -- senlinclient/v1/build_info.py | 48 - senlinclient/v1/client.py | 512 ------ senlinclient/v1/cluster.py | 1390 --------------- senlinclient/v1/cluster_policy.py | 159 -- senlinclient/v1/event.py | 138 -- senlinclient/v1/node.py | 569 ------ senlinclient/v1/policy.py | 312 ---- senlinclient/v1/policy_type.py | 82 - senlinclient/v1/profile.py | 369 ---- senlinclient/v1/profile_type.py | 112 -- senlinclient/v1/receiver.py | 321 ---- senlinclient/v1/service.py | 43 - setup.cfg | 90 - setup.py | 20 - test-requirements.txt | 17 - tools/senlinrc | 41 - tox.ini | 76 - 131 files changed, 8 insertions(+), 13774 deletions(-) delete mode 100644 .gitignore delete mode 100644 .stestr.conf delete mode 100644 .zuul.yaml delete mode 100644 CONTRIBUTING.rst delete mode 100644 LICENSE delete mode 100644 TODO delete mode 100644 bindep.txt delete mode 100644 doc/.gitignore delete mode 100644 doc/Makefile delete mode 100644 doc/requirements.txt delete mode 100644 doc/source/cli/index.rst delete mode 100644 doc/source/conf.py delete mode 100644 doc/source/contributor/index.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/install/index.rst delete mode 100644 releasenotes/notes/.placeholder delete mode 100644 releasenotes/notes/bug-1814171-b1c58797c9ca9f44.yaml delete mode 100644 releasenotes/notes/cli-deprecation-241b9569b85f8fbd.yaml delete mode 100644 releasenotes/notes/cluster-collect-a9d1bc8c2e799c7c.yaml delete mode 100644 releasenotes/notes/cluster-policy-list-42ff03ef25d64dd1.yaml delete mode 100644 releasenotes/notes/cluster-run-210247ab70b289a5.yaml delete mode 100644 releasenotes/notes/cluster-scaling-command-e0d96f2cd0c7ca5f.yaml delete mode 100644 releasenotes/notes/deletion-output-a841931367a2689d.yaml delete mode 100644 releasenotes/notes/drop-py-2-7-cced38f13fd3b44c.yaml delete mode 100644 releasenotes/notes/fix-region-732c2be90e58c347.yaml delete mode 100644 releasenotes/notes/force-delete-c8d6cf4d6f049cb2.yaml delete mode 100644 releasenotes/notes/micro-version-1.10-dabb632bfa40b79b.yaml delete mode 100644 releasenotes/notes/micro-version-a292ce3b00d886af.yaml delete mode 100644 releasenotes/notes/node-check-recover-469bf81db9f9f1ec.yaml delete mode 100644 releasenotes/notes/others-e13ff69738d062c6.yaml delete mode 100644 releasenotes/notes/policy-validate-193a5ebb7db3440a.yaml delete mode 100644 releasenotes/notes/profile-validate-587f1a964e93c0bf.yaml delete mode 100644 releasenotes/notes/python-3.5-c9fd8e34c4046357.yaml delete mode 100644 releasenotes/notes/receiver-create-8305d4efbdf35f35.yaml delete mode 100644 releasenotes/notes/retire-senlin-cli-8ba21807b584993d.yaml delete mode 100644 releasenotes/notes/senlinclient-1.1.0-daf1f24c73ee8b17.yaml delete mode 100644 releasenotes/notes/senlinclient-1.2.0-4680ea85ba2dc6c8.yaml delete mode 100644 releasenotes/notes/test-function-test-d90d7af1994a5f88.yaml delete mode 100644 releasenotes/source/2023.1.rst delete mode 100644 releasenotes/source/2023.2.rst delete mode 100644 releasenotes/source/_static/.placeholder delete mode 100644 releasenotes/source/_templates/.placeholder delete mode 100644 releasenotes/source/conf.py delete mode 100644 releasenotes/source/index.rst delete mode 100644 releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po delete mode 100644 releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po delete mode 100644 releasenotes/source/locale/zh_CN/LC_MESSAGES/releasenotes.po delete mode 100644 releasenotes/source/newton.rst delete mode 100644 releasenotes/source/ocata.rst delete mode 100644 releasenotes/source/pike.rst delete mode 100644 releasenotes/source/queens.rst delete mode 100644 releasenotes/source/rocky.rst delete mode 100644 releasenotes/source/stein.rst delete mode 100644 releasenotes/source/train.rst delete mode 100644 releasenotes/source/unreleased.rst delete mode 100644 releasenotes/source/ussuri.rst delete mode 100644 releasenotes/source/victoria.rst delete mode 100644 releasenotes/source/wallaby.rst delete mode 100644 releasenotes/source/xena.rst delete mode 100644 releasenotes/source/yoga.rst delete mode 100644 releasenotes/source/zed.rst delete mode 100644 requirements.txt delete mode 100644 senlinclient/__init__.py delete mode 100644 senlinclient/client.py delete mode 100644 senlinclient/common/__init__.py delete mode 100644 senlinclient/common/exc.py delete mode 100644 senlinclient/common/format_utils.py delete mode 100644 senlinclient/common/i18n.py delete mode 100644 senlinclient/common/utils.py delete mode 100644 senlinclient/locale/zh_CN/LC_MESSAGES/senlinclient.po delete mode 100644 senlinclient/plugin.py delete mode 100644 senlinclient/tests/__init__.py delete mode 100644 senlinclient/tests/functional/__init__.py delete mode 100644 senlinclient/tests/functional/base.py delete mode 100644 senlinclient/tests/functional/policies/deletion_policy.yaml delete mode 100644 senlinclient/tests/functional/profiles/cirros_basic.yaml delete mode 100644 senlinclient/tests/functional/test_actions.py delete mode 100644 senlinclient/tests/functional/test_cluster_policy.py delete mode 100644 senlinclient/tests/functional/test_clusters.py delete mode 100644 senlinclient/tests/functional/test_events.py delete mode 100644 senlinclient/tests/functional/test_help.py delete mode 100644 senlinclient/tests/functional/test_nodes.py delete mode 100644 senlinclient/tests/functional/test_policies.py delete mode 100644 senlinclient/tests/functional/test_policy_types.py delete mode 100644 senlinclient/tests/functional/test_profile_types.py delete mode 100644 senlinclient/tests/functional/test_profiles.py delete mode 100644 senlinclient/tests/functional/test_readonly_senlin.py delete mode 100644 senlinclient/tests/functional/test_receivers.py delete mode 100644 senlinclient/tests/functional/test_version.py delete mode 100644 senlinclient/tests/test_specs/deletion_policy.yaml delete mode 100644 senlinclient/tests/test_specs/nova_server.yaml delete mode 100644 senlinclient/tests/unit/__init__.py delete mode 100644 senlinclient/tests/unit/fakes.py delete mode 100644 senlinclient/tests/unit/test_format_utils.py delete mode 100644 senlinclient/tests/unit/test_plugin.py delete mode 100644 senlinclient/tests/unit/test_utils.py delete mode 100644 senlinclient/tests/unit/v1/__init__.py delete mode 100644 senlinclient/tests/unit/v1/fakes.py delete mode 100644 senlinclient/tests/unit/v1/test_action.py delete mode 100644 senlinclient/tests/unit/v1/test_build_info.py delete mode 100644 senlinclient/tests/unit/v1/test_client.py delete mode 100644 senlinclient/tests/unit/v1/test_cluster.py delete mode 100644 senlinclient/tests/unit/v1/test_cluster_policy.py delete mode 100644 senlinclient/tests/unit/v1/test_event.py delete mode 100644 senlinclient/tests/unit/v1/test_node.py delete mode 100644 senlinclient/tests/unit/v1/test_policy.py delete mode 100644 senlinclient/tests/unit/v1/test_policy_type.py delete mode 100644 senlinclient/tests/unit/v1/test_profile.py delete mode 100644 senlinclient/tests/unit/v1/test_profile_type.py delete mode 100644 senlinclient/tests/unit/v1/test_receiver.py delete mode 100644 senlinclient/tests/unit/v1/test_service.py delete mode 100644 senlinclient/v1/__init__.py delete mode 100644 senlinclient/v1/action.py delete mode 100644 senlinclient/v1/build_info.py delete mode 100644 senlinclient/v1/client.py delete mode 100644 senlinclient/v1/cluster.py delete mode 100644 senlinclient/v1/cluster_policy.py delete mode 100644 senlinclient/v1/event.py delete mode 100644 senlinclient/v1/node.py delete mode 100644 senlinclient/v1/policy.py delete mode 100644 senlinclient/v1/policy_type.py delete mode 100644 senlinclient/v1/profile.py delete mode 100644 senlinclient/v1/profile_type.py delete mode 100644 senlinclient/v1/receiver.py delete mode 100644 senlinclient/v1/service.py delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tools/senlinrc delete mode 100644 tox.ini 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='