diff --git a/.gitignore b/.gitignore deleted file mode 100644 index f1d9b8b..0000000 --- a/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -etc/ -*.pyc -.stestr/* -.tox/* -kolla_cli.egg-info/* -.mypy_cache/* -.stestr - -# Files generated by JetBrains -.idea/ - -# Files generates by Eclipse -.project -.pydevproject - -# Files generated by Ansible -ansible/*.retry - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog - -.coverage -cover/ diff --git a/.stestr.conf b/.stestr.conf deleted file mode 100644 index 83abc4f..0000000 --- a/.stestr.conf +++ /dev/null @@ -1,3 +0,0 @@ -[DEFAULT] -test_path=${OS_TEST_PATH:-./kolla_cli/tests/unit} -top_dir=./ diff --git a/.zuul.yaml b/.zuul.yaml deleted file mode 100644 index 01a2559..0000000 --- a/.zuul.yaml +++ /dev/null @@ -1,38 +0,0 @@ ---- -- job: - name: kollacli-tox-functional-py36 - parent: openstack-tox - description: | - Run tox-based py36 functional tests for the OpenStack Kolla-cli project. - Uses tox with the ``functional`` environment. - irrelevant-files: - - ^.*\.rst$ - - ^doc/source/.*$ - - ^releasenotes/.*$ - vars: - tox_envlist: functional-py36 - timeout: 3600 - -- job: - name: kollacli-tox-mypy - parent: openstack-tox - description: | - Run static mypy type checker for the OpenStack Kolla-cli project. - vars: - tox_envlist: mypy - timeout: 3600 - -- project: - templates: - - openstack-cover-jobs - - openstack-lower-constraints-jobs - - openstack-python3-victoria-jobs - - publish-openstack-docs-pti - check: - jobs: - - kollacli-tox-mypy - - kollacli-tox-functional-py36 - gate: - jobs: - - kollacli-tox-mypy - - kollacli-tox-functional-py36 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a..0000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - diff --git a/README.rst b/README.rst index 0374f63..266e43d 100644 --- a/README.rst +++ b/README.rst @@ -1,135 +1,13 @@ -**This project is deprecated since the Ussuri release and will not be -maintained in the future.** +This project is no longer maintained. -========= -Kolla-CLI -========= +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". -The Kolla-CLI project provides the ability to more easily manage -Kolla-Ansible deployments. It provides both a CLI and a python -API that you can use to configure and deploy OpenStack using Kolla-Ansible. +Please use Kolla Ansible at https://opendev.org/openstack/kolla-ansible +directly or Kayobe at https://opendev.org/openstack/kayobe . -Kolla-Ansible requires that hosts, groups, and services are specified -in an inventory file. With Kolla-CLI, you can add/remove hosts, change group -associations, etc from the CLI or API. Kolla-Ansible also maintains -passwords and various configuration variables in a variety of global, group -and host files. With Kolla-CLI, you can now view and change these from the -CLI/API. - -Finally, Kolla-CLI provides commands to setup the SSH keys on hosts, run -deployments and perform upgrades. - -Installing -========== - -The installation process below assumes that the kolla-ansible repository -exists at the same level as the kolla-cli repository. This is made clear -in the cli_setup.py script which makes a relative '../' reference to -the kolla-ansible repository. If your kolla-ansible directory is somewhere -else then that location can be passed as an argument to the cli_setup.py -script. The location on the system where the kolla-cli expects the -kolla-ansible files to be and installs them to can be tweaked by setting -the KOLLA_HOME and KOLLA_ETC environment variables before running the -cli_setup.py script, and while running the kolla-cli command itself. The -default value for KOLLA_HOME is /usr/share/kolla-ansible and the default -value for KOLLA_ETC is /etc/kolla. - -The following steps can be used to build / run the kolla-cli - -* install ansible and docker -* virtualenv .venv -* . .venv/bin/activate -* pip install -r requirements.txt -* python setup.py install -* python ./cli_setup.py -* kolla-cli - -At that point you will be dropped into the kollacli shell where -you can run commands like help or ? to see what commands are -available and any of the sub commands can be executed directly. - -Alternately you can not use the shell and just execute commands -directly via kollacli host add, etc. - -If you make changes to the i18n strings (denoted by methods like -_("message")) make sure to re-generate the i18n files with the -``python setup.py extract_messages`` command and check in the -files generated in openstack-kollacli. - - -API -=== - -To use the API, import the ClientAPI into your module: - -from kolla_cli.api.client import ClientApi - -Then define a global: - -CLIENT = ClientApi() - -And then you can use that global to execute API commands, for example, -to add a host to the inventory: - -CLIENT.host_add(['host_name']) - -Generating Documentation -======================== - -We use `Sphinx `_ to maintain the -documentation. You can install Sphinx using pip. - -:: - - $ pip install -U Sphinx - -In addition to Sphinx you will also need the following requirements -(covered by `doc/requirements.txt`):: - - $ pip install openstackdocstheme reno 'reno[sphinx]' - -The source code of the documentation are under *doc*, you can generate the -html files using the following command. If the generation succeeds,a -*build/html* dir will be created under *doc*. - -:: - - $ cd doc - $ make html - -Now you can serve the documentation at http://localhost:8080 as a simple -website. - -:: - - $ cd build/html - $ python -m SimpleHTTPServer 8080 - -Getting Involved -================ - -Need a feature? Find a bug? Let us know! Contributions are much -appreciated and should follow the standard `Gerrit -workflow `__. - -- We communicate using the #openstack-kolla irc channel. -- File bugs, blueprints, track releases, etc on - `Launchpad `__. -- Attend weekly - `meetings `__. -- Contribute `code `__. - -Contributors -============ - -Check out who is `contributing -code `__ and -`contributing -reviews `__. - -Troubleshooting -=============== - -If you get an error about missing python.h install the python-dev -package via apt-get or yum or whatever mechanism is appropriate -for your platform. +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-kolla on +Freenode. diff --git a/cli_setup.py b/cli_setup.py deleted file mode 100755 index a47745a..0000000 --- a/cli_setup.py +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2018 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import os -import sys - -from kolla_cli.common import utils - -kolla_ansible_source_base = '../kolla-ansible' -kolla_ansible_home_target = utils.get_kolla_ansible_home() -kolla_ansible_etc_target = utils.get_kolla_etc() -ansible = 'ansible' -kolla = 'kolla' -kolla_cli = 'kolla-cli' -tools = 'tools' - - -def setup_ansible_etc(): - # if the kolla-cli directory for the inventory doesn't exist - # already then make it. this will also create the directory the - # globals and password file goes into - cli_etc_dir = os.path.join(kolla_ansible_etc_target, - kolla_cli, ansible) - if not os.path.exists(cli_etc_dir): - make_cli_etc_dir_cmd = ('mkdir -p %s' % cli_etc_dir) - _command_exec(make_cli_etc_dir_cmd) - - # Create the inventory file (if it doesn't already exist). - # (The script will exit here if the user doesn't have sufficient privs.) - inventory_file_path = os.path.join(cli_etc_dir, 'inventory.json') - if not os.path.exists(inventory_file_path): - touch_inventory_file_cmd = ('touch %s' % inventory_file_path) - _command_exec(touch_inventory_file_cmd) - - # copy over all kolla ansible etc files - kolla_ansible_etc_source = os.path.join(kolla_ansible_source_base, - 'etc', kolla) - for etc_file in os.listdir(kolla_ansible_etc_source): - if not os.path.exists(os.path.join(kolla_ansible_etc_target, - etc_file)): - copy_kolla_etc_files_cmd = ( - 'cp -a {source_dir}/{filename} {target_dir}'.format( - source_dir=kolla_ansible_etc_source, - filename=etc_file, - target_dir=kolla_ansible_etc_target)) - _command_exec(copy_kolla_etc_files_cmd) - - # add ssh keys for cli - key_path = os.path.join(os.getenv('HOME'), '.ssh', 'id_rsa') - if not os.path.exists(key_path): - # generate new ssh keys - keygen_cmd = 'ssh-keygen -t rsa -N \'\' -f %s' % key_path - _command_exec(keygen_cmd) - # copy the public key to where kolla-cli expects it - pub_key_path = os.path.join(os.getenv('HOME'), '.ssh', 'id_rsa.pub') - cli_etc_path = os.path.join(kolla_ansible_etc_target, kolla_cli) - copy_cmd = 'cp -p %s %s/' % (pub_key_path, cli_etc_path) - _command_exec(copy_cmd) - - -def setup_ansible_home(): - # make cli home ansible directory - cli_ansible_dir = os.path.join(kolla_ansible_home_target, - kolla_cli, ansible) - if not os.path.exists(cli_ansible_dir): - make_cli_ansible_dir_cmd = ('mkdir -p %s' % cli_ansible_dir) - _command_exec(make_cli_ansible_dir_cmd) - - # make cli home tools directory - cli_tools_dir = os.path.join(kolla_ansible_home_target, - kolla_cli, tools) - if not os.path.exists(cli_tools_dir): - make_cli_tools_dir_cmd = ('mkdir -p %s' % cli_tools_dir) - _command_exec(make_cli_tools_dir_cmd) - - # move cli tools files to tools directory - copy_cli_tools_files_cmd = ('cp -a %s %s' % ('./tools/*', cli_tools_dir)) - _command_exec(copy_cli_tools_files_cmd) - - # create cli ansible lock file - lock_file_path = os.path.join(kolla_ansible_home_target, - kolla_cli, 'ansible.lock') - if not os.path.exists(lock_file_path): - touch_ansible_lock_file_cmd = ('touch %s' % lock_file_path) - _command_exec(touch_ansible_lock_file_cmd) - - # copy over all kolla ansible home files - kolla_ansible_home_source = os.path.join(kolla_ansible_source_base, - ansible) - copy_kolla_home_files_cmd = ('cp -a %s %s' % (kolla_ansible_home_source, - kolla_ansible_home_target)) - _command_exec(copy_kolla_home_files_cmd) - - # create the host_vars directory if it doesn't exist already - host_vars_path = os.path.join(kolla_ansible_home_target, - ansible, 'host_vars') - if not os.path.exists(host_vars_path): - make_kolla_host_vars_dir_cmd = ('mkdir %s' % host_vars_path) - _command_exec(make_kolla_host_vars_dir_cmd) - - # make link from etc globals to home globals - target_etc_path = os.path.join(kolla_ansible_etc_target, 'globals.yml') - target_home_link = os.path.join(kolla_ansible_home_target, - ansible, 'group_vars', '__GLOBAL__') - if not os.path.exists(target_home_link): - link_globals_file_cmd = ('ln -s %s %s' % (target_etc_path, - target_home_link)) - _command_exec(link_globals_file_cmd) - - -def _command_exec(command): - print('running - %s' % command) - error, _ = utils.run_cmd(command) - if error: - print('error - %s' % error) - sys.exit(1) - - -def main(): - """make sure kolla-ansible and cli files are in the right places""" - - if len(sys.argv) >= 2: - global kolla_ansible_source_base - kolla_ansible_source_base = sys.argv[1] - - setup_ansible_etc() - setup_ansible_home() - - -if __name__ == '__main__': - main() diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 6f60721..0000000 --- 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/kollacli.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/kollacli.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/kollacli" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/kollacli" - @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 c6bb74f..0000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,8 +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>=1.18.1 # Apache-2.0 -reno>=2.5.0 # Apache-2.0 -sphinx>=1.8.0,!=2.1.0 # BSD -sphinxcontrib-pecanwsme>=0.8 diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 56fcece..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,264 +0,0 @@ -# -*- coding: utf-8 -*- -# -# kolla-cli documentation build configuration file, created by -# sphinx-quickstart on Thu Mar 17 18:17:04 2016. -# -# 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. - -import os -import sys - -# 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 = [ - 'openstackdocstheme', - 'sphinx.ext.autodoc', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'kolla-cli' -copyright = u'2016, Oracle' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '1.0' -# The full version, including alpha/beta/rc tags. -release = '1.0' - -# 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' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - - -# -- Options for LaTeX output --------------------------------------------- - -# Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664 -latex_use_xindy = False - -latex_domain_indices = False - -latex_elements = { - 'makeindex': '', - 'printindex': '', - 'preamble': r'\setcounter{tocdepth}{3}', - 'maxlistdepth': 10, -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -# NOTE(jacky06): Specify toctree_only=True for a better document structure of -# the generated PDF file. -latex_documents = [ - ('index', 'doc-kolla-cli.tex', u'kolla-cli Documentation', - u'Oracle', 'manual', True), -] - -# 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', 'kolla-cli', u'kolla-cli Documentation', - [u'Oracle'], 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', 'kolla-cli', u'kolla-cli Documentation', - u'Oracle', 'kolla-cli', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 91cb2a9..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. kollacli documentation master file, created by - sphinx-quickstart on Thu Mar 17 18:17:04 2016. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to kolla-cli's documentation! -===================================== - -**This project is deprecated since the Ussuri release and will not be -maintained in the future.** - -Contents: - -.. toctree:: - :maxdepth: 2 - - modules - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/kolla_cli.api.rst b/doc/source/kolla_cli.api.rst deleted file mode 100644 index 1cbecd7..0000000 --- a/doc/source/kolla_cli.api.rst +++ /dev/null @@ -1,99 +0,0 @@ -api Package -=========== - -:mod:`certificate` Module -------------------------- - -.. automodule:: kolla_cli.api.certificate - :members: - :undoc-members: - :show-inheritance: - -:mod:`client` Module --------------------- - -.. automodule:: kolla_cli.api.client - :members: - :undoc-members: - :show-inheritance: - -:mod:`config` Module --------------------- - -.. automodule:: kolla_cli.api.config - :members: - :undoc-members: - :show-inheritance: - -:mod:`control_plane` Module ---------------------------- - -.. automodule:: kolla_cli.api.control_plane - :members: - :undoc-members: - :show-inheritance: - -:mod:`exceptions` Module ------------------------- - -.. automodule:: kolla_cli.api.exceptions - :members: - :undoc-members: - :show-inheritance: - -:mod:`group` Module -------------------- - -.. automodule:: kolla_cli.api.group - :members: - :undoc-members: - :show-inheritance: - -:mod:`host` Module ------------------- - -.. automodule:: kolla_cli.api.host - :members: - :undoc-members: - :show-inheritance: - -:mod:`job` Module ------------------ - -.. automodule:: kolla_cli.api.job - :members: - :undoc-members: - :show-inheritance: - -:mod:`password` Module ----------------------- - -.. automodule:: kolla_cli.api.password - :members: - :undoc-members: - :show-inheritance: - -:mod:`properties` Module ------------------------- - -.. automodule:: kolla_cli.api.properties - :members: - :undoc-members: - :show-inheritance: - -:mod:`service` Module ---------------------- - -.. automodule:: kolla_cli.api.service - :members: - :undoc-members: - :show-inheritance: - -:mod:`support` Module ---------------------- - -.. automodule:: kolla_cli.api.support - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/source/kolla_cli.commands.rst b/doc/source/kolla_cli.commands.rst deleted file mode 100644 index 6fe4c00..0000000 --- a/doc/source/kolla_cli.commands.rst +++ /dev/null @@ -1,83 +0,0 @@ -commands Package -================ - -:mod:`config` Module --------------------- - -.. automodule:: kolla_cli.commands.config - :members: - :undoc-members: - :show-inheritance: - -:mod:`exceptions` Module ------------------------- - -.. automodule:: kolla_cli.commands.exceptions - :members: - :undoc-members: - :show-inheritance: - -:mod:`group` Module -------------------- - -.. automodule:: kolla_cli.commands.group - :members: - :undoc-members: - :show-inheritance: - -:mod:`host` Module ------------------- - -.. automodule:: kolla_cli.commands.host - :members: - :undoc-members: - :show-inheritance: - -:mod:`kolla_action` Module --------------------------- - -.. automodule:: kolla_cli.commands.kolla_action - :members: - :undoc-members: - :show-inheritance: - -:mod:`mode` Module ------------------- - -.. automodule:: kolla_cli.commands.mode - :members: - :undoc-members: - :show-inheritance: - -:mod:`password` Module ----------------------- - -.. automodule:: kolla_cli.commands.password - :members: - :undoc-members: - :show-inheritance: - -:mod:`property` Module ----------------------- - -.. automodule:: kolla_cli.commands.property - :members: - :undoc-members: - :show-inheritance: - -:mod:`service` Module ---------------------- - -.. automodule:: kolla_cli.commands.service - :members: - :undoc-members: - :show-inheritance: - -:mod:`support` Module ---------------------- - -.. automodule:: kolla_cli.commands.support - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/source/kolla_cli.common.ansible.rst b/doc/source/kolla_cli.common.ansible.rst deleted file mode 100644 index 7eee499..0000000 --- a/doc/source/kolla_cli.common.ansible.rst +++ /dev/null @@ -1,35 +0,0 @@ -ansible Package -=============== - -:mod:`actions` Module ---------------------- - -.. automodule:: kolla_cli.common.ansible.actions - :members: - :undoc-members: - :show-inheritance: - -:mod:`job` Module ------------------ - -.. automodule:: kolla_cli.common.ansible.job - :members: - :undoc-members: - :show-inheritance: - -:mod:`playbook` Module ----------------------- - -.. automodule:: kolla_cli.common.ansible.playbook - :members: - :undoc-members: - :show-inheritance: - -:mod:`utils` Module -------------------- - -.. automodule:: kolla_cli.common.ansible.utils - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/source/kolla_cli.common.rst b/doc/source/kolla_cli.common.rst deleted file mode 100644 index 2e9e7b6..0000000 --- a/doc/source/kolla_cli.common.rst +++ /dev/null @@ -1,98 +0,0 @@ -common Package -============== - -:mod:`ansible_inventory` Module -------------------------------- - -.. automodule:: kolla_cli.common.ansible_inventory - :members: - :undoc-members: - :show-inheritance: - -:mod:`host` Module ------------------- - -.. automodule:: kolla_cli.common.host - :members: - :undoc-members: - :show-inheritance: - -:mod:`host_group` Module ------------------------- - -.. automodule:: kolla_cli.common.host_group - :members: - :undoc-members: - :show-inheritance: - -:mod:`inventory` Module ------------------------ - -.. automodule:: kolla_cli.common.inventory - :members: - :undoc-members: - :show-inheritance: - -:mod:`passwords` Module ------------------------ - -.. automodule:: kolla_cli.common.passwords - :members: - :undoc-members: - :show-inheritance: - -:mod:`properties` Module ------------------------- - -.. automodule:: kolla_cli.common.properties - :members: - :undoc-members: - :show-inheritance: - -:mod:`service` Module ---------------------- - -.. automodule:: kolla_cli.common.service - :members: - :undoc-members: - :show-inheritance: - -:mod:`sshutils` Module ----------------------- - -.. automodule:: kolla_cli.common.sshutils - :members: - :undoc-members: - :show-inheritance: - -:mod:`subservice` Module ------------------------- - -.. automodule:: kolla_cli.common.subservice - :members: - :undoc-members: - :show-inheritance: - -:mod:`support` Module ---------------------- - -.. automodule:: kolla_cli.common.support - :members: - :undoc-members: - :show-inheritance: - -:mod:`utils` Module -------------------- - -.. automodule:: kolla_cli.common.utils - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - - kolla_cli.common.ansible - diff --git a/doc/source/kolla_cli.rst b/doc/source/kolla_cli.rst deleted file mode 100644 index f490209..0000000 --- a/doc/source/kolla_cli.rst +++ /dev/null @@ -1,29 +0,0 @@ -kolla_cli Package -================= - -:mod:`i18n` Module ------------------- - -.. automodule:: kolla_cli.i18n - :members: - :undoc-members: - :show-inheritance: - -:mod:`shell` Module -------------------- - -.. automodule:: kolla_cli.shell - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - - kolla_cli.api - kolla_cli.commands - kolla_cli.common - kolla_cli.tests - diff --git a/doc/source/kolla_cli.tests.functional.rst b/doc/source/kolla_cli.tests.functional.rst deleted file mode 100644 index 1ba9530..0000000 --- a/doc/source/kolla_cli.tests.functional.rst +++ /dev/null @@ -1,107 +0,0 @@ -functional Package -================== - -:mod:`common` Module --------------------- - -.. automodule:: kolla_cli.tests.functional.common - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_client_upgrade` Module ---------------------------------- - -.. automodule:: kolla_cli.tests.functional.test_client_upgrade - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_config` Module -------------------------- - -.. automodule:: kolla_cli.tests.functional.test_config - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_deploy` Module -------------------------- - -.. automodule:: kolla_cli.tests.functional.test_deploy - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_destroy` Module --------------------------- - -.. automodule:: kolla_cli.tests.functional.test_destroy - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_group` Module ------------------------- - -.. automodule:: kolla_cli.tests.functional.test_group - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_host` Module ------------------------ - -.. automodule:: kolla_cli.tests.functional.test_host - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_password` Module ---------------------------- - -.. automodule:: kolla_cli.tests.functional.test_password - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_property` Module ---------------------------- - -.. automodule:: kolla_cli.tests.functional.test_property - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_reconfigure` Module ------------------------------- - -.. automodule:: kolla_cli.tests.functional.test_reconfigure - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_service` Module --------------------------- - -.. automodule:: kolla_cli.tests.functional.test_service - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_stop` Module ------------------------ - -.. automodule:: kolla_cli.tests.functional.test_stop - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_support` Module --------------------------- - -.. automodule:: kolla_cli.tests.functional.test_support - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/source/kolla_cli.tests.rst b/doc/source/kolla_cli.tests.rst deleted file mode 100644 index 3381275..0000000 --- a/doc/source/kolla_cli.tests.rst +++ /dev/null @@ -1,11 +0,0 @@ -tests Package -============= - -Subpackages ------------ - -.. toctree:: - - kolla_cli.tests.functional - kolla_cli.tests.unit - diff --git a/doc/source/kolla_cli.tests.unit.rst b/doc/source/kolla_cli.tests.unit.rst deleted file mode 100644 index a8891f0..0000000 --- a/doc/source/kolla_cli.tests.unit.rst +++ /dev/null @@ -1,43 +0,0 @@ -unit Package -============ - -:mod:`common` Module --------------------- - -.. automodule:: kolla_cli.tests.unit.common - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_deploy_cmd` Module ------------------------------ - -.. automodule:: kolla_cli.tests.unit.test_deploy_cmd - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_group_cmd` Module ----------------------------- - -.. automodule:: kolla_cli.tests.unit.test_group_cmd - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_host_cmd` Module ---------------------------- - -.. automodule:: kolla_cli.tests.unit.test_host_cmd - :members: - :undoc-members: - :show-inheritance: - -:mod:`test_service_cmd` Module ------------------------------- - -.. automodule:: kolla_cli.tests.unit.test_service_cmd - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/source/modules.rst b/doc/source/modules.rst deleted file mode 100644 index 2580153..0000000 --- a/doc/source/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -kolla_cli -========= - -.. toctree:: - :maxdepth: 4 - - kolla_cli diff --git a/kolla-cli/locale/openstack-kollacli.pot b/kolla-cli/locale/openstack-kollacli.pot deleted file mode 100644 index a283d7c..0000000 --- a/kolla-cli/locale/openstack-kollacli.pot +++ /dev/null @@ -1,79 +0,0 @@ -# Translations template for kollacli. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the kollacli project. -# FIRST AUTHOR , 2015. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: kollacli 0.1.0.dev22\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-08-06 15:09-0700\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.0\n" - -#: kollacli/common.py:30 -msgid "deploy" -msgstr "" - -#: kollacli/common.py:40 -msgid "install" -msgstr "" - -#: kollacli/common.py:50 -msgid "list" -msgstr "" - -#: kollacli/common.py:62 -msgid "start" -msgstr "" - -#: kollacli/common.py:80 -msgid "stop" -msgstr "" - -#: kollacli/common.py:89 -msgid "sync" -msgstr "" - -#: kollacli/common.py:98 -msgid "upgrade" -msgstr "" - -#: kollacli/common.py:107 -msgid "dump" -msgstr "" - -#: kollacli/host.py:156 -msgid "host addservice" -msgstr "" - -#: kollacli/host.py:166 -msgid "host removeservice" -msgstr "" - -#: kollacli/property.py:29 -msgid "property set" -msgstr "" - -#: kollacli/service.py:27 -msgid "service activate" -msgstr "" - -#: kollacli/service.py:37 -msgid "service deactivate" -msgstr "" - -#: kollacli/service.py:47 -msgid "service autodeploy" -msgstr "" - -#: kollacli/service.py:57 -msgid "service list" -msgstr "" - diff --git a/kolla_cli/__init__.py b/kolla_cli/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kolla_cli/api/__init__.py b/kolla_cli/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kolla_cli/api/certificate.py b/kolla_cli/api/certificate.py deleted file mode 100644 index c2eeac3..0000000 --- a/kolla_cli/api/certificate.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright(c) 2018, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kolla_cli.api.job import Job -from kolla_cli.common.ansible.actions import KollaAction -from kolla_cli.common.utils import check_arg -import kolla_cli.i18n as u - - -class CertificateApi(object): - - @staticmethod - def certificate_init(verbose_level=1): - """Certificate Init. - - Creates a self-signed certificate for secure TLS communication. - - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :return: Job object - :rtype: Job - """ - check_arg(verbose_level, u._('Verbose level'), int) - action = KollaAction(verbose_level=verbose_level, - playbook_name='certificates.yml') - ansible_job = action.certificate_init() - return Job(ansible_job) diff --git a/kolla_cli/api/client.py b/kolla_cli/api/client.py deleted file mode 100644 index 5cd6251..0000000 --- a/kolla_cli/api/client.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright(c) 2017, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import sys - -from kolla_cli.api.certificate import CertificateApi -from kolla_cli.api.config import ConfigApi -from kolla_cli.api.control_plane import ControlPlaneApi -from kolla_cli.api.group import GroupApi -from kolla_cli.api.host import HostApi -from kolla_cli.api.password import PasswordApi -from kolla_cli.api.properties import PropertyApi -from kolla_cli.api.service import ServiceApi -from kolla_cli.api.support import SupportApi - -CONSOLE_MESSAGE_FORMAT = '%(message)s' - -# TODO(bmace) - API version should probably be stored somewhere else -VERSION = '0.1' - - -class ClientApi( - CertificateApi, - ConfigApi, - ControlPlaneApi, - GroupApi, - HostApi, - PasswordApi, - PropertyApi, - ServiceApi, - SupportApi, - ): - """Client API Notes - - Objects returned by the API contain a local copy of the information - in the datastore. While changes made to the local copy will be - reflected in the local object, changes made to the datastore - from other objects will not be reflected in this local copy. The - object will need to be re-fetched from the datastore to reflect - the updates. - """ - - @staticmethod - def get_version(): - # type: () -> str - return VERSION - - @staticmethod - def enable_console_logging(level, enable=True): - # type: (int, bool) -> None - """enable/disable console logging for the api - - enable: True/False - level: logging.INFO, logging.DEBUG, logging.WARNING, - logging.CRITICAL... - """ - root_logger = logging.getLogger('') - console = logging.StreamHandler(sys.stderr) - if enable: - console.setLevel(level) - formatter = logging.Formatter(CONSOLE_MESSAGE_FORMAT) - console.setFormatter(formatter) - root_logger.addHandler(console) - else: - root_logger.removeHandler(console) diff --git a/kolla_cli/api/config.py b/kolla_cli/api/config.py deleted file mode 100644 index f605529..0000000 --- a/kolla_cli/api/config.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright(c) 2018, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -from kolla_cli.api.exceptions import FailedOperation -from kolla_cli.api.exceptions import InvalidArgument -from kolla_cli.common.inventory import Inventory -from kolla_cli.common import utils -from kolla_cli.common.utils import check_arg -import kolla_cli.i18n as u - - -class ConfigApi(object): - - @staticmethod - def config_reset(): - """Config Reset. - - Resets the kolla-ansible configuration to its release defaults. - """ - actions_path = utils.get_kolla_actions_path() - cmd = ('%s config_reset' % actions_path) - err_msg, output = utils.run_cmd(cmd, print_output=False) - if err_msg: - raise FailedOperation( - u._('Configuration reset failed. {error} {message}') - .format(error=err_msg, message=output)) - - def config_import_inventory(self, file_path): - # type: (str) -> None - """Config Import Inventory - - Import groups and child associations from the provided - inventory file. This currently does not import hosts, group - vars, or host vars that may also exist in the inventory file. - - :param file_path: path to inventory file to import - :type file_path: string - """ - check_arg(file_path, u._('File path'), str) - if not os.path.isfile(file_path): - raise InvalidArgument( - u._('File {path} is not valid.').format( - path=file_path)) - inventory = Inventory(file_path) - Inventory.save(inventory) diff --git a/kolla_cli/api/control_plane.py b/kolla_cli/api/control_plane.py deleted file mode 100644 index e5e13c4..0000000 --- a/kolla_cli/api/control_plane.py +++ /dev/null @@ -1,345 +0,0 @@ -# Copyright(c) 2017, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kolla_cli.api.job import Job -from kolla_cli.common.ansible.actions import KollaAction -from kolla_cli.common.ansible.utils import check_kolla_args -from kolla_cli.common.inventory import Inventory -from kolla_cli.common.utils import check_arg -from kolla_cli.common.utils import safe_decode -import kolla_cli.i18n as u - -MYPY = False -if MYPY: - from typing import List # noqa - - -class ControlPlaneApi(object): - - @staticmethod - def deploy(hostnames=[], - serial_flag=False, verbose_level=1, servicenames=[]): - # type: (List[str], bool, int, List[str]) -> Job - """Deploy. - - Deploy and start all kolla containers. - - :param hostnames: hosts to deploy to. If empty, then deploy to all. - :type hostnames: list of strings - :param serial_flag: if true, deploy will be done one host at a time - :type serial_flag: boolean - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :param servicenames: services to deploy. If empty, then deploy all. - :type servicenames: list of strings - :return: Job object - :rtype: Job - """ - check_arg(hostnames, u._('Host names'), list, - empty_ok=True, none_ok=True) - check_arg(serial_flag, u._('Serial flag'), bool) - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(servicenames, u._('Service names'), list, - empty_ok=True, none_ok=True) - - check_kolla_args(hostnames=hostnames, - servicenames=servicenames) - - hostnames = safe_decode(hostnames) - servicenames = safe_decode(servicenames) - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.deploy(hostnames, serial_flag, servicenames) - return Job(ansible_job) - - @staticmethod - def prechecks(verbose_level=1, hostnames=[], servicenames=[]): - # type: (int, List[str], List[str]) -> Job - """Check pre-deployment configuration of hosts. - - Check if host is ready for a new deployment. This will fail if - any of the hosts are not configured correctly or if they have - already been deployed to. - :param hostnames: host names - :type hostnames: list - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :param servicenames: services to prechecks. - :type servicenames: list of strings - :return: Job object - :rtype: Job - """ - check_arg(hostnames, u._('Host names'), list, - empty_ok=True, none_ok=True) - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(servicenames, u._('Service names'), list, - empty_ok=True, none_ok=True) - - check_kolla_args(hostnames=hostnames, - servicenames=servicenames) - - hostnames = safe_decode(hostnames) - servicenames = safe_decode(servicenames) - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.precheck(hostnames, servicenames) - return Job(ansible_job) - - @staticmethod - def pull(verbose_level=1, hostnames=[], servicenames=[]): - """Pull. - - Pull all images for containers (only pulls, no running container). - - :param verbose_level: the higher the number, the more verbose - :param hostnames: hosts to pull to. If empty, then pull to all. - :type hostnames: list of strings - :type verbose_level: integer - :param servicenames: services to pull. If empty, then pull all. - :return: Job object - :rtype: Job - """ - check_arg(hostnames, u._('Host names'), list, - empty_ok=True, none_ok=True) - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(servicenames, u._('Service names'), list, - empty_ok=True, none_ok=True) - - check_kolla_args(hostnames=hostnames, - servicenames=servicenames) - - hostnames = safe_decode(hostnames) - servicenames = safe_decode(servicenames) - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.pull(hostnames, servicenames) - return Job(ansible_job) - - @staticmethod - def stop(verbose_level=1, hostnames=[], servicenames=[]): - # type: (int, List[str], List[str]) -> Job - """Stop Hosts. - - Stops all kolla related docker containers on the specified hosts. - - :param hostnames: host names - :type hostnames: list - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :param servicenames: services to stop. If empty, then stop all. - :type servicenames: list of strings - :return: Job object - :rtype: Job - """ - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(hostnames, u._('Host names'), list, - empty_ok=True, none_ok=True) - check_arg(servicenames, u._('Service names'), list, - empty_ok=True, none_ok=True) - - check_kolla_args(hostnames=hostnames, - servicenames=servicenames) - - hostnames = safe_decode(hostnames) - servicenames = safe_decode(servicenames) - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.stop(hostnames, servicenames) - return Job(ansible_job) - - @staticmethod - def upgrade(verbose_level=1, hostnames=[], servicenames=[]): - # type: (int, List[str], List[str]) -> Job - """Upgrade. - - Upgrades existing OpenStack Environment. - - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :param hostnames: hostnames to upgrade. - :type hostnames: list of strings. - :param servicenames: services to upgrade. If empty, then upgrade all. - :type servicenames: list of strings - :return: Job object - :rtype: Job - - Upgrade containers to new version specified by the property - "openstack_release." - """ - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(hostnames, u._('Host names'), list, - empty_ok=True, none_ok=True) - check_arg(servicenames, u._('Service names'), list, - empty_ok=True, none_ok=True) - - check_kolla_args(servicenames=servicenames) - - hostnames = safe_decode(hostnames) - servicenames = safe_decode(servicenames) - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.upgrade(hostnames, servicenames) - return Job(ansible_job) - - @staticmethod - def genconfig(verbose_level=1, hostnames=[], servicenames=[]): - # type: (int, List[str], List[str]) -> Job - """Genconfig. - - Generate configuration files for enabled OpenStack services. - - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :param servicenames: services to generate. If empty, then generate all. - :type servicenames: list of strings - :return: Job object - :rtype: Job - - Upgrade containers to new version specified by the property - "openstack_release." - """ - check_arg(hostnames, u._('Host names'), list, - empty_ok=True, none_ok=True) - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(servicenames, u._('Service names'), list, - empty_ok=True, none_ok=True) - - check_kolla_args(hostnames=hostnames, - servicenames=servicenames) - - hostnames = safe_decode(hostnames) - servicenames = safe_decode(servicenames) - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.genconfig(hostnames, servicenames) - return Job(ansible_job) - - @staticmethod - def check(verbose_level=1, hostnames=[], servicenames=[]): - # type: (int, List[str], List[str]) -> Job - """Do post-deployment smoke tests. - - :param hostnames: host names - :type hostnames: list - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :param servicenames: services to check. If empty, then check all. - :type servicenames: list of strings - :return: Job object - :rtype: Job - """ - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(hostnames, u._('Host names'), list, - empty_ok=True, none_ok=True) - check_arg(servicenames, u._('Service names'), list, - empty_ok=True, none_ok=True) - - check_kolla_args(servicenames=servicenames) - - hostnames = safe_decode(hostnames) - servicenames = safe_decode(servicenames) - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.check(hostnames, servicenames) - return Job(ansible_job) - - @staticmethod - def postdeploy(verbose_level=1): - """Post-Deploy. - - Do post deploy on deploy node. - - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :return: Job object - :rtype: Job - """ - check_arg(verbose_level, u._('Verbose level'), int) - - action = KollaAction(verbose_level=verbose_level, - playbook_name='post-deploy.yml') - ansible_job = action.postdeploy() - return Job(ansible_job) - - @staticmethod - def reconfigure(verbose_level=1, hostnames=[], servicenames=[]): - # type: (int, List[str], List[str]) -> Job - """Reconfigure. - - Reconfigure OpenStack service. - - :param hostnames: host names - :type hostnames: list - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :param servicenames: services to prechecks. - :type servicenames: list of strings - :return: Job object - :rtype: Job - """ - check_arg(hostnames, u._('Host names'), list, - empty_ok=True, none_ok=True) - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(servicenames, u._('Service names'), list, - empty_ok=True, none_ok=True) - - check_kolla_args(hostnames=hostnames, - servicenames=servicenames) - - hostnames = safe_decode(hostnames) - servicenames = safe_decode(servicenames) - - check_kolla_args(hostnames=hostnames, - servicenames=servicenames) - - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.reconfigure(hostnames, servicenames) - return Job(ansible_job) - - @staticmethod - def set_deploy_mode(remote_mode): - # type: (bool) -> None - """Set deploy mode to either local or remote. - - Local indicates that the openstack deployment will be - to the local host. Remote means that the deployment is - executed via ssh. - - NOTE: local mode is not supported and should never be used - in production environments. - - :param remote_mode: if remote mode is True deployment is done via ssh - :type remote_mode: bool - """ - check_arg(remote_mode, u._('Remote mode'), bool) - inventory = Inventory.load() - inventory.set_deploy_mode(remote_mode) - Inventory.save(inventory) - - @staticmethod - def get_deploy_mode(): - """Get deploy mode from either local or remote. - - Local indicates that the openstack deployment will be - to the local host. Remote means that the deployment is - executed via ssh. - - NOTE: local mode is not supported and should never be used - in production environments. - """ - inventory = Inventory.load() - remote_mode = inventory.remote_mode - deploy_mode = 'remote' if remote_mode else 'local' - return deploy_mode diff --git a/kolla_cli/api/exceptions.py b/kolla_cli/api/exceptions.py deleted file mode 100644 index d6f1999..0000000 --- a/kolla_cli/api/exceptions.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Exception definitions.""" -import kolla_cli.i18n as u - - -class ClientException(Exception): - """KollaClient Base Class Exception""" - def __init__(self, message, *args): - if not message: - message = u._('An unknown exception occurred.') - super(ClientException, self).__init__(message, *args) - - -class NotInInventory(ClientException): - """Not in inventory exception""" - def __init__(self, obj_type, obj_names, *args): - if isinstance(obj_names, list): - # list of names - invalid_objs = '' - comma = '' - for obj_name in obj_names: - invalid_objs = ''.join([invalid_objs, comma, obj_name]) - comma = ',' - else: - # single object name - invalid_objs = obj_names - message = (u._('{type} ({objs}) does not exist.') - .format(type=obj_type, objs=invalid_objs)) - super(NotInInventory, self).__init__(message, *args) - - -class HostError(ClientException): - pass - - -class HostsSshCheckError(ClientException): - """Host failed its ssh check""" - def __init__(self, hostnames, *args): - failed_hosts = '' - comma = '' - for hostname in hostnames: - failed_hosts = ''.join([failed_hosts, comma, hostname]) - comma = ',' - message = (u._('Host(s) ssh check failed: {hosts}') - .format(hosts=failed_hosts)) - super(HostsSshCheckError, self).__init__(message, *args) - - -class InvalidArgument(ClientException): - """Invalid argument""" - pass - - -class InvalidConfiguration(ClientException): - """Invalid configuration""" - pass - - -class FailedOperation(ClientException): - pass - - -class MissingArgument(ClientException): - """Missing argument""" - def __init__(self, argname, *args): - message = (u._('Argument is missing: {name}') - .format(name=argname)) - super(MissingArgument, self).__init__(message, *args) diff --git a/kolla_cli/api/group.py b/kolla_cli/api/group.py deleted file mode 100644 index 3500dcb..0000000 --- a/kolla_cli/api/group.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from copy import copy - -from kolla_cli.common.inventory import Inventory -from kolla_cli.common.utils import check_arg -from kolla_cli.common.utils import safe_decode -import kolla_cli.i18n as u - - -MYPY = False -if MYPY: - from typing import List # noqa - - -class GroupApi(object): - - def group_add(self, groupnames): - # type: (List[str]) -> None - """Add groups to the inventory - - :param groupnames: names of the groups to add to the inventory - :type groupnames: list of strings - - """ - check_arg(groupnames, u._('Group names'), list) - groupnames = safe_decode(groupnames) - - inventory = Inventory.load() - for groupname in groupnames: - inventory.add_group(groupname) - Inventory.save(inventory) - - def group_remove(self, groupnames): - # type: (List[str]) -> None - """Remove groups from the inventory - - :param groupnames: names of the groups to remove from the inventory - :type groupnames: list of strings - """ - check_arg(groupnames, u._('Group names'), list) - groupnames = safe_decode(groupnames) - - inventory = Inventory.load() - for groupname in groupnames: - inventory.remove_group(groupname) - Inventory.save(inventory) - - def group_get_all(self): - # type: () -> List[Group] - """Get all groups in the inventory - - :return: groups - :rtype: list of Group objects - """ - return self._get_groups([], get_all=True) - - def group_get(self, groupnames): - # type: (List[str]) -> List[Group] - """Get selected groups in the inventory - - :param groupnames: names of groups to be read - :type groupnames: list of strings - :return: groups - :rtype: list of Group objects - """ - check_arg(groupnames, u._('Group names'), list) - groupnames = safe_decode(groupnames) - return self._get_groups(groupnames) - - def _get_groups(self, groupnames, get_all=False): - # type: (List[str], bool) -> List[Group] - groups = [] - inventory = Inventory.load() - if get_all: - groupnames = inventory.get_groupnames() - else: - inventory.validate_groupnames(groupnames) - - group_services = inventory.get_group_services() - for groupname in groupnames: - inv_group = inventory.get_group(groupname) - group = Group(groupname, - group_services[groupname], - inv_group.get_hostnames()) - groups.append(group) - return groups - - -class Group(object): - def __init__(self, groupname, servicenames, hostnames): - # type: (str, List[str], List[str]) -> None - self.name = groupname - self._servicenames = servicenames - self._hostnames = hostnames - - def get_name(self): - # type: () -> str - """Get name - - :return: group name - :rtype: string - """ - return self.name - - def get_services(self): - # type: () -> List[str] - """Get names of services associated with this group. - - :return: service names - :rtype: list of strings - """ - return copy(self._servicenames) - - def add_service(self, servicename): - # type: (str) -> None - """Add service to group - - :param servicename: name of the service to add to the group - :type servicename: string - """ - check_arg(servicename, u._('Service name'), str) - servicename = safe_decode(servicename) - inventory = Inventory.load() - inventory.validate_servicenames([servicename], client_filter=True) - - group_services = inventory.get_group_services() - self._servicenames = group_services[self.name] - if servicename not in self._servicenames: - # service not associated with group, add it - inventory.add_group_to_service(self.name, servicename) - self._servicenames.append(servicename) - Inventory.save(inventory) - - def remove_service(self, servicename): - # type: (str) -> None - """Remove service from group - - :param servicename: name of the service to remove from the group - :type servicename: string - - """ - check_arg(servicename, u._('Service name'), str) - servicename = safe_decode(servicename) - inventory = Inventory.load() - inventory.validate_servicenames([servicename], client_filter=True) - - group_services = inventory.get_group_services() - self._servicenames = group_services[self.name] - if servicename in self._servicenames: - # service is associated with group, remove it - inventory.remove_group_from_service(self.name, servicename) - self._servicenames.remove(servicename) - Inventory.save(inventory) - - def get_hosts(self): - # type: () -> List[str] - """Get names of hosts associated with this group. - - :return: host names - :rtype: list of strings - """ - return copy(self._hostnames) - - def add_host(self, hostname): - # type: (str) -> None - """Add host to group - - :param hostname: name of the host to add to the group - :type hostname: string - - """ - check_arg(hostname, u._('Host name'), str) - hostname = safe_decode(hostname) - inventory = Inventory.load() - inventory.validate_hostnames([hostname]) - - group = inventory.get_group(self.name) - self._hostnames = group.get_hostnames() - if hostname not in self._hostnames: - # host not associated with group, add it - inventory.add_host(hostname, self.name) - self._hostnames.append(hostname) - Inventory.save(inventory) - - def remove_host(self, hostname): - # type: (str) -> None - """Remove host from group - - :param hostname: name of the host to remove from the group - :type hostname: string - - """ - check_arg(hostname, u._('Host name'), str) - hostname = safe_decode(hostname) - inventory = Inventory.load() - inventory.validate_hostnames([hostname]) - - group = inventory.get_group(self.name) - self._hostnames = group.get_hostnames() - if hostname in self._hostnames: - # host is associated with group, remove it - inventory.remove_host(hostname, self.name) - self._hostnames.remove(hostname) - Inventory.save(inventory) diff --git a/kolla_cli/api/host.py b/kolla_cli/api/host.py deleted file mode 100644 index 9b0b499..0000000 --- a/kolla_cli/api/host.py +++ /dev/null @@ -1,222 +0,0 @@ -# Copyright(c) 2017, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from copy import copy - -from kolla_cli.api.exceptions import InvalidArgument -from kolla_cli.api.job import Job -from kolla_cli.common.ansible.actions import KollaAction -from kolla_cli.common.inventory import Inventory -from kolla_cli.common.utils import check_arg -from kolla_cli.common.utils import safe_decode -import kolla_cli.i18n as u - - -MYPY = False -if MYPY: - from typing import Dict # noqa - from typing import List # noqa - - -class HostApi(object): - - @staticmethod - def host_add(hostnames): - # type: (List[str]) -> None - """Add hosts to the inventory - - :param hostnames: list of strings - """ - check_arg(hostnames, u._('Host names'), list) - hostnames = safe_decode(hostnames) - - inventory = Inventory.load() - any_changed = False - for hostname in hostnames: - changed = inventory.add_host(hostname) - if changed: - any_changed = True - if any_changed: - Inventory.save(inventory) - - @staticmethod - def host_remove(hostnames): - # type: (List[str]) -> None - """Remove hosts from the inventory - - :param hostnames: list of strings - """ - check_arg(hostnames, u._('Host names'), list) - hostnames = safe_decode(hostnames) - - inventory = Inventory.load() - any_changed = False - for hostname in hostnames: - changed = inventory.remove_host(hostname) - if changed: - any_changed = True - if any_changed: - Inventory.save(inventory) - - @staticmethod - def host_get_all(): - # type: () -> List[Host] - """Get all hosts in the inventory - - :return: Hosts - :rtype: list of Host objects - """ - inventory = Inventory.load() - hosts = [] - host_groups = inventory.get_host_groups() - for hostname, groupnames in host_groups.items(): - hosts.append(Host(hostname, groupnames)) - return hosts - - @staticmethod - def host_get(hostnames): - # type: (List[str]) -> List[Host] - """Get selected hosts in the inventory - - :param hostnames: list of strings - :return: hosts - :rtype: list of Host objects - """ - check_arg(hostnames, u._('Host names'), list) - hostnames = safe_decode(hostnames) - inventory = Inventory.load() - inventory.validate_hostnames(hostnames) - - hosts = [] - host_groups = inventory.get_host_groups() - for hostname in hostnames: - hosts.append(Host(hostname, host_groups[hostname])) - return hosts - - @staticmethod - def host_ssh_check(hostnames): - # type: (List[str]) -> Dict[str,Dict[str,object]] - """Check hosts for ssh connectivity - - Check status is a dictionary of form: - - {hostname: { - 'success':, - 'msg':message_string}, - ... - } - - :param hostnames: list of strings - :return: check status - :rtype: dictionary - """ - check_arg(hostnames, u._('Host names'), list) - inventory = Inventory.load() - hostnames = safe_decode(hostnames) - inventory.validate_hostnames(hostnames) - summary = inventory.ssh_check_hosts(hostnames) - return summary - - @staticmethod - def host_setup(hosts_info): - # type: (Dict[str,Dict[str,object]]) -> None - """Setup multiple hosts for ssh access - - hosts_info is a dictionary of form: - - {hostname': { - 'password': password - 'uname': user_name}, - ... - } - - The uname entry is optional. - - :param hosts_info: dictionary - """ - check_arg(hosts_info, u._('Hosts info'), dict) - inventory = Inventory.load() - inventory.validate_hostnames(hosts_info.keys()) - inventory.setup_hosts(hosts_info) - - @staticmethod - def host_destroy(hostnames, destroy_type, verbose_level=1, - include_data=False, remove_images=False): - # type: (List[str], str, int, bool, bool) -> Job - """Destroy Hosts. - - Stops and removes all kolla related docker containers on the - specified hosts. - - :param hostnames: host names - :type hostnames: list - :param destroy_type: either 'kill' or 'stop' - :type destroy_type: string - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :param include_data: if true, destroy data containers too. - :type include_data: boolean - :param remove_images: if true, destroy will remove the docker images - :type remove_images: boolean - :return: Job object - :rtype: Job - """ - check_arg(hostnames, u._('Host names'), list) - check_arg(destroy_type, u._('Destroy type'), str) - check_arg(verbose_level, u._('Verbose level'), int) - check_arg(include_data, u._('Include data'), bool) - check_arg(remove_images, u._('Remove images'), bool) - if destroy_type not in ['stop', 'kill']: - raise InvalidArgument( - u._('Invalid destroy type ({type}). Must be either ' - '"stop" or "kill".').format(type=destroy_type)) - - hostnames = safe_decode(hostnames) - inventory = Inventory.load() - inventory.validate_hostnames(hostnames) - - action = KollaAction(verbose_level=verbose_level, - playbook_name='destroy.yml') - ansible_job = action.destroy_hosts(hostnames, destroy_type, - include_data, remove_images) - return Job(ansible_job) - - -class Host(object): - """Host""" - - def __init__(self, hostname, groupnames=[]): - # type: (str, List[str]) -> None - self.name = hostname - self._groupnames = groupnames - - def get_name(self): - # type: () -> str - """Get name - - :return: host name - :rtype: string - """ - return self.name - - def get_groups(self): - # type: () -> List[str] - """Get names of the groups associated with this host - - :return: group names - :rtype: list of strings - - Note: If the groups associated with this host change after this - host is fetched, the host must be re-fetched to reflect those - changes. - """ - return copy(self._groupnames) diff --git a/kolla_cli/api/job.py b/kolla_cli/api/job.py deleted file mode 100644 index 8d20a9d..0000000 --- a/kolla_cli/api/job.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -class Job(object): - """Job""" - def __init__(self, ansible_job): - self._ansible_job = ansible_job - - def wait(self): - # type: () -> int - """Wait for job to complete - - :return: 0 if job succeeded, 1 if job failed - :rtype: int - """ - return self._ansible_job.wait() - - def get_status(self): - # type: () -> int - """Get status of job - - :return: None: job is still running - 0: job succeeded - 1: job failed - 2: job killed by user - :rtype: int or None - """ - return self._ansible_job.get_status() - - def get_error_message(self): - # type: () -> str - """Get error message - - :return: if job failed, this will return the error message. - :rtype: string - """ - return self._ansible_job.get_error_message() - - def get_console_output(self): - # type: () -> str - """Get the console output from the job - - :return: console output useful for debugging failed jobs. - :rtype: string - """ - return self._ansible_job.get_command_output() - - def kill(self): - """kill the job""" - self._ansible_job.kill() diff --git a/kolla_cli/api/password.py b/kolla_cli/api/password.py deleted file mode 100644 index be3a9ac..0000000 --- a/kolla_cli/api/password.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kolla_cli.common.passwords import clear_password -from kolla_cli.common.passwords import get_password_names -from kolla_cli.common.passwords import init_passwords -from kolla_cli.common.passwords import set_password -from kolla_cli.common.passwords import set_password_sshkey -from kolla_cli.common.utils import check_arg -from kolla_cli.common.utils import disallow_chars -import kolla_cli.i18n as u - - -MYPY = False -if MYPY: - from typing import List # noqa - - -class PasswordApi(object): - - def password_set(self, name, value): - # type: (str, str) -> None - """Set password - - :param name: name of the password - :type name: string - :param value: value of the password - :type value: string - """ - password_name_string = u._('Password name') - password_value_string = u._('Password value') - check_arg(name, password_name_string, str) - disallow_chars(name, password_name_string, '\'') - check_arg(value, password_value_string, str, display_param=False, - empty_ok=True, none_ok=True) - disallow_chars(value, password_value_string, '\'') - set_password(name, value) - - def password_set_sshkey(self, name, private_key, public_key): - # type: (str, str, str) -> None - """Set password to an ssh key - - :param name: name of the password - :type name: string - :param private_key: ssh private key - :type value: string - :param public_key: ssh public key - :type value: string - """ - password_name_string = u._('Password name') - private_key_string = u._('Private key') - public_key_string = u._('Public key') - check_arg(name, password_name_string, str) - disallow_chars(name, password_name_string, '\'') - check_arg(private_key, private_key_string, str, display_param=False) - disallow_chars(private_key, private_key_string, '\'') - check_arg(public_key, public_key_string, str, display_param=False) - disallow_chars(public_key, public_key_string, '\'') - set_password_sshkey(name, private_key, public_key) - - def password_clear(self, name): - # type: (str) -> None - """Clear password - - :param name: name of the password - :type name: string - """ - password_name_string = u._('Password name') - check_arg(name, password_name_string, str) - disallow_chars(name, password_name_string, '\'') - clear_password(name) - - def password_get_names(self): - # type: () -> List[str] - """Get password names - - :return: password names - :rtype: list of strings - """ - return get_password_names() - - def password_init(self): - # type: () -> None - """Init empty passwords - - Init empty passwords and ssh keys in /etc/kolla/passwords.yml - to auto-generated values - """ - return init_passwords() diff --git a/kolla_cli/api/properties.py b/kolla_cli/api/properties.py deleted file mode 100644 index 6bad1bb..0000000 --- a/kolla_cli/api/properties.py +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import yaml - -from kolla_cli.api.exceptions import InvalidArgument -from kolla_cli.common.properties import AnsibleProperties -from kolla_cli.common.utils import check_arg -from kolla_cli.common.utils import safe_decode -import kolla_cli.i18n as u - - -MYPY = False -if MYPY: - from typing import Dict # noqa - from typing import List # noqa - -LOG = logging.getLogger(__name__) - -GLOBAL_TYPE = 'global' -GROUP_TYPE = 'group' -HOST_TYPE = 'host' -PROP_TYPES = [GLOBAL_TYPE, GROUP_TYPE, HOST_TYPE] - - -class PropertyApi(object): - - def property_set(self, property_dict, - property_type=GLOBAL_TYPE, change_set=None): - # type: (Dict[str,str], str, List[str]) -> None - """Set a property - - :param property_dict: property dictionary containing key / values - :type property_dict: dictionary - :param property_type: one of 'global', 'group' or 'host' - :type property_type: string - :param change_set: for group or host sets this is the list of groups - or hosts to set the property for - :type change_set: list of strings - - """ - ansible_properties = AnsibleProperties() - for key, value in property_dict.items(): - check_arg(key, u._('Property Key'), str) - current_property = ansible_properties.get_property(key) - if current_property is not None: - current_property_type = current_property.value_type - if current_property_type is not str: - original_value = value - value = yaml.safe_load(value) - - # this check is to make sure that we can assign an empty - # string to a property. without this safe_load will turn - # an empty string into a None which is different than an - # empty string. - if isinstance(original_value, str) and value is None: - value = '' - if current_property.value is None: - current_property_type = None - check_arg(value, u._('Property Value'), - current_property_type, empty_ok=True) - property_dict[key] = value - else: - check_arg(value, u._('Property Value'), str, empty_ok=True) - if type(value) is str and '"' in value: - raise InvalidArgument(u._('Cannot use double quotes in ' - 'a property value.')) - - self._check_type(property_type) - if property_type is not GLOBAL_TYPE: - check_arg(change_set, u._('Change Set'), list, none_ok=True) - change_set = safe_decode(change_set) - - if property_type == GLOBAL_TYPE: - ansible_properties.set_property(property_dict) - elif property_type == GROUP_TYPE: - ansible_properties.set_group_property(property_dict, change_set) - else: - ansible_properties.set_host_property(property_dict, change_set) - - def property_clear(self, property_list, property_type=GLOBAL_TYPE, - change_set=None): - # type: (List[str], str, List[str]) -> None - """Clear a property - - :param property_list: property list - :type property_list: list - :param property_type: one of 'global', 'group' or 'host' - :type property_type: string - :param change_set: for group or host clears this is the list of - groups or hosts to clear the property for - :type change_set: list of strings - - """ - check_arg(property_list, u._('Property List'), list) - property_list = safe_decode(property_list) - - self._check_type(property_type) - if property_type is not GLOBAL_TYPE: - check_arg(change_set, u._('Change Set'), list, none_ok=True) - change_set = safe_decode(change_set) - - ansible_properties = AnsibleProperties() - - if property_type == GLOBAL_TYPE: - ansible_properties.clear_property(property_list) - elif property_type == GROUP_TYPE: - ansible_properties.clear_group_property(property_list, change_set) - else: - ansible_properties.clear_host_property(property_list, change_set) - - def property_get(self, property_type=GLOBAL_TYPE, get_set=None): - # type: (str, List[str]) -> List[Property] - """Returns a list of Property objects - - :param property_type: one of 'global', 'group', or 'host' - :type property_type: string - :param get_set: optional list of hosts or groups to be used when - getting group or host related property lists - :type get_set: list of strings - :return: properties - :rtype: list of Property objects - """ - self._check_type(property_type) - get_set = safe_decode(get_set) - - ansible_properties = AnsibleProperties() - - result_list = [] - if property_type == GLOBAL_TYPE: - property_list = ansible_properties.get_all_unique() - elif property_type == GROUP_TYPE: - property_list = ansible_properties.get_group_list(get_set) - else: - property_list = ansible_properties.get_host_list(get_set) - - override_flags = ansible_properties.get_all_override_flags() - - for prop in property_list: - result = Property(prop, override_flags.get(prop.name, None)) - result_list.append(result) - - return result_list - - def _check_type(self, property_type): - if property_type is None or property_type not in PROP_TYPES: - raise InvalidArgument(u._('Property Type ({value} is not one of ' - 'global, group or host') - .format(value=property_type)) - - -class Property(object): - """Property - - Members: - - name (str): key - - value (Any): value - - file_name (str): name of file property is from - - overrides (bool): does the property override some other value - - orig_value (str): the value which is overridden or None - - target (str): group or host name for group or host properties - - prop_type (str): one of 'global', 'group' or 'host' - - ovr_global (bool): true if property is overridden at global level - - ovr_group (bool): true if property is overridden at group level - - ovr_host (bool): true if property is overridden at host level - - value_type (type): the python type of the value - """ - - def __init__(self, ansible_property, override_flags): - self.name = ansible_property.name - self.value = ansible_property.value - self.file_name = ansible_property.file_name - self.overrides = ansible_property.overrides - self.orig_value = ansible_property.orig_value - self.target = ansible_property.target - self.prop_type = ansible_property.prop_type - self.value_type = ansible_property.value_type - - if override_flags is not None: - self.ovr_global = override_flags.ovr_global - self.ovr_group = override_flags.ovr_group - self.ovr_host = override_flags.ovr_host - else: - self.ovr_global = False - self.ovr_group = False - self.ovr_host = False diff --git a/kolla_cli/api/service.py b/kolla_cli/api/service.py deleted file mode 100644 index b9740f1..0000000 --- a/kolla_cli/api/service.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from copy import copy - -from kolla_cli.common.inventory import Inventory -from kolla_cli.common.utils import check_arg -from kolla_cli.common.utils import safe_decode -import kolla_cli.i18n as u - -MYPY = False -if MYPY: - from typing import List # noqa - - -class ServiceApi(object): - - def service_get_all(self): - # type: () -> List[Service] - """Get all services in the inventory - - :return: services - :rtype: List of Service objects - """ - return self._get_services([], get_all=True) - - def service_get(self, servicenames): - # type: (List[str]) -> List[Service] - """Get selected services in the inventory - - :param servicenames: names of services to be read - :type servicenames: list of strings - :return: services - :rtype: list of Service objects - """ - check_arg(servicenames, u._('Service names'), list) - servicenames = safe_decode(servicenames) - return self._get_services(servicenames) - - def _get_services(self, servicenames, get_all=False): - # type: (List[str], bool) -> List[Service] - services = [] - inventory = Inventory.load() - - if get_all: - inv_services = inventory.get_services(client_filter=True) - for inv_service in inv_services: - service = Service(inv_service.name, - inv_service.get_parentnames(), - inv_service.get_childnames(), - inv_service.get_groupnames()) - services.append(service) - else: - inventory.validate_servicenames(servicenames, client_filter=True) - - for servicename in servicenames: - inv_service = inventory.get_service(servicename, - client_filter=True) - if inv_service: - service = Service(inv_service.name, - inv_service.get_parentnames(), - inv_service.get_childnames(), - inv_service.get_groupnames()) - services.append(service) - return services - - -class Service(object): - """Service - - A service is one of the services available in openstack-kolla-ansible. - - For example, this would be how the murano services would be - represented: - - - murano - - parentnames: [] - - childnames: [murano-api, murano-engine] - - murano-api - - parentnames: [murano] - - childnames: [] - - murano-engine - - parentnames: [murano] - - childnames: [] - """ - - def __init__(self, servicename, parentnames=[], - childnames=[], groupnames=[]): - # type: (str, List[str], List[str], List[str]) -> None - self.name = servicename - self._parentnames = parentnames - self._childnames = childnames - self._groupnames = groupnames - - def get_name(self): - # type: () -> str - """Get name - - :return: service name - :rtype: string - """ - return self.name - - def get_parents(self): - # type: () -> List[str] - """Get name of parent services - - :return: parent service names - :rtype: string - """ - return copy(self._parentnames) - - def get_children(self): - # type: () -> List[str] - """Get names of the child services - - :return: child names - :rtype: list of strings - """ - return copy(self._childnames) - - def get_groups(self): - # type: () -> List[str] - """Get names of the groups - - :return: group names - :rtype: list of strings - - Note: If the groups associated with this service change after this - service is fetched, the service must be re-fetched to reflect those - changes. - """ - return copy(self._groupnames) diff --git a/kolla_cli/api/support.py b/kolla_cli/api/support.py deleted file mode 100644 index 92f6e25..0000000 --- a/kolla_cli/api/support.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -from kolla_cli.api.exceptions import InvalidArgument -from kolla_cli.common.support import dump -from kolla_cli.common.support import get_logs -from kolla_cli.common.utils import check_arg -from kolla_cli.common.utils import safe_decode -import kolla_cli.i18n as u - -MYPY = False -if MYPY: - from typing import List # noqa - - -class SupportApi(object): - - def support_dump(self, dirpath): - # type: (str) -> str - """Dumps configuration data for debugging. - - Dumps most files in /etc/kolla and /usr/share/kolla into a - tar file so be given to support / development to help with - debugging problems. - - :param dirpath: path to directory where dump will be placed - :type dirpath: string - :return: path to dump file - :rtype: string - """ - check_arg(dirpath, u._('Directory path'), str) - dirpath = safe_decode(dirpath) - if not os.path.exists(dirpath): - raise InvalidArgument(u._('Directory path: {path} does not exist') - .format(path=dirpath)) - dumpfile_path = dump(dirpath) - return dumpfile_path - - def support_get_logs(self, servicenames, hostname, dirpath): - # type: (List[str], str, str) -> None - """get container logs - - Fetch the container log files of services from the specified hosts. - The log files will be placed in the named directory. All the containers - for the host will be placed in a directory named hostname. The file - names for each log will be servicename_id.log. - - :param servicenames: names of services (ie nova, glance, etc) - :type servicenames: list of strings - :param hostname: name of host to look for logs on - :type hostname: string - :param dirpath: path of directory where log files will be written - :type dirpath: string - """ - check_arg(dirpath, u._('Directory path'), str) - dirpath = safe_decode(dirpath) - if not os.path.exists(dirpath): - raise InvalidArgument(u._('Directory path: {path} does not exist') - .format(path=dirpath)) - - check_arg(servicenames, u._('Service names'), list) - servicenames = safe_decode(servicenames) - check_arg(hostname, u._('Host names'), str) - hostname = safe_decode(hostname) - - get_logs(servicenames, hostname, dirpath) diff --git a/kolla_cli/commands/__init__.py b/kolla_cli/commands/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kolla_cli/commands/config.py b/kolla_cli/commands/config.py deleted file mode 100644 index 32c28c6..0000000 --- a/kolla_cli/commands/config.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright(c) 2018, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import traceback - -from cliff.command import Command - -from kolla_cli.api.client import ClientApi -from kolla_cli.commands.exceptions import CommandError -import kolla_cli.i18n as u - -CLIENT = ClientApi() -LOG = logging.getLogger(__name__) - - -class ConfigReset(Command): - """Resets the kolla-ansible configuration to its release defaults.""" - - def take_action(self, parsed_args): - try: - CLIENT.config_reset() - except Exception: - raise Exception(traceback.format_exc()) - - -class ConfigImport(Command): - """Config Import - - """ - def get_parser(self, prog_name): - parser = super(ConfigImport, self).get_parser(prog_name) - parser.add_argument('import_type', metavar='', - help=u._('Import type=')) - parser.add_argument('file_path', metavar='', - help=u._('File path')) - return parser - - def take_action(self, parsed_args): - try: - legal_types = ['inventory'] - import_type = parsed_args.import_type - if not import_type or import_type not in legal_types: - raise CommandError(u._( - 'Import type must be {type}.').format(type=legal_types)) - - file_path = None - if parsed_args.file_path: - file_path = parsed_args.file_path.strip() - CLIENT.config_import_inventory(file_path) - except Exception: - raise Exception(traceback.format_exc()) diff --git a/kolla_cli/commands/exceptions.py b/kolla_cli/commands/exceptions.py deleted file mode 100644 index 942cec4..0000000 --- a/kolla_cli/commands/exceptions.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Exception definitions.""" -import kolla_cli.i18n as u - - -class CommandError(Exception): - """CLI command error""" - def __init__(self, message, *args): - prefix = u._('ERROR: ') - if not message.startswith(prefix): - message = prefix + message - super(CommandError, self).__init__(message, *args) diff --git a/kolla_cli/commands/group.py b/kolla_cli/commands/group.py deleted file mode 100644 index 6171aa3..0000000 --- a/kolla_cli/commands/group.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import traceback - -from cliff.command import Command -from cliff.lister import Lister - -from kolla_cli.api.client import ClientApi -from kolla_cli.api.exceptions import ClientException -from kolla_cli.commands.exceptions import CommandError -from kolla_cli.common.utils import convert_lists_to_string -import kolla_cli.i18n as u - -CLIENT = ClientApi() - - -class GroupAdd(Command): - """Add group to openstack-kolla.""" - def get_parser(self, prog_name): - parser = super(GroupAdd, self).get_parser(prog_name) - parser.add_argument('groupname', metavar='', - help=u._('Group name')) - return parser - - def take_action(self, parsed_args): - try: - groupname = parsed_args.groupname.strip() - - CLIENT.group_add([groupname]) - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class GroupRemove(Command): - """Remove group from openstack-kolla.""" - - def get_parser(self, prog_name): - parser = super(GroupRemove, self).get_parser(prog_name) - parser.add_argument('groupname', metavar='', - help=u._('Group name')) - return parser - - def take_action(self, parsed_args): - try: - groupname = parsed_args.groupname.strip() - - CLIENT.group_remove([groupname]) - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class GroupAddhost(Command): - """Add host to group.""" - def get_parser(self, prog_name): - parser = super(GroupAddhost, self).get_parser(prog_name) - parser.add_argument('groupname', metavar='', - help=u._('Group name')) - parser.add_argument('hostname', metavar='', - help=u._('Host name')) - return parser - - def take_action(self, parsed_args): - try: - groupname = parsed_args.groupname.strip() - hostname = parsed_args.hostname.strip() - - group = CLIENT.group_get([groupname])[0] - group.add_host(hostname) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class GroupRemovehost(Command): - """Remove host group from group.""" - - def get_parser(self, prog_name): - parser = super(GroupRemovehost, self).get_parser(prog_name) - parser.add_argument('groupname', metavar='', - help=u._('Group name')) - parser.add_argument('hostname', metavar='', - help=u._('Host name')) - return parser - - def take_action(self, parsed_args): - try: - groupname = parsed_args.groupname.strip() - hostname = parsed_args.hostname.strip() - - group = CLIENT.group_get([groupname])[0] - group.remove_host(hostname) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class GroupList(Lister): - """Only list all groups """ - - def take_action(self, parsed_args): - try: - data = [('',)] - groups = CLIENT.group_get_all() - if groups: - data = [] - for group in groups: - data.append((group.get_name(),)) - data = convert_lists_to_string(data, parsed_args) - return ((u._('Group'), ), sorted(data)) - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class GroupListhosts(Lister): - """List all groups and their hosts.""" - - def take_action(self, parsed_args): - try: - data = [('', '')] - groups = CLIENT.group_get_all() - if groups: - data = [] - for group in groups: - data.append((group.get_name(), - sorted(group.get_hosts()))) - data = convert_lists_to_string(data, parsed_args) - return ((u._('Group'), u._('Hosts')), sorted(data)) - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class GroupListservices(Lister): - """List all groups and their services.""" - - def take_action(self, parsed_args): - try: - data = [('', '')] - groups = CLIENT.group_get_all() - if groups: - data = [] - for group in groups: - data.append((group.get_name(), - sorted(group.get_services()))) - data = convert_lists_to_string(data, parsed_args) - return ((u._('Group'), u._('Services')), sorted(data)) - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) diff --git a/kolla_cli/commands/host.py b/kolla_cli/commands/host.py deleted file mode 100644 index 411c9eb..0000000 --- a/kolla_cli/commands/host.py +++ /dev/null @@ -1,302 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import getpass -import logging -import os -import traceback -import yaml - -from cliff.command import Command -from cliff.lister import Lister -from six.moves import input - -from kolla_cli.api.client import ClientApi -from kolla_cli.api.exceptions import ClientException -from kolla_cli.commands.exceptions import CommandError -from kolla_cli.common.utils import convert_lists_to_string -from kolla_cli.common.utils import get_setup_user -from kolla_cli.common.utils import handers_action_result -import kolla_cli.i18n as u - -LOG = logging.getLogger(__name__) -CLIENT = ClientApi() - - -class HostAdd(Command): - """Add host to openstack-kolla.""" - - def get_parser(self, prog_name): - parser = super(HostAdd, self).get_parser(prog_name) - parser.add_argument('hostname', metavar='', - help=u._('Host name or ip address')) - return parser - - def take_action(self, parsed_args): - try: - hostname = parsed_args.hostname.strip() - CLIENT.host_add([hostname]) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class HostDestroy(Command): - """Destroy all kolla containers on host(s). - - Stops and removes all kolla related docker containers on either the - specified host or all hosts if the hostname all is used. - """ - - def get_parser(self, prog_name): - parser = super(HostDestroy, self).get_parser(prog_name) - parser.add_argument('hostname', metavar='', - help=u._('Host name or ip address or "all"')) - parser.add_argument('--stop', action='store_true', - help=u._('Stop rather than kill')) - parser.add_argument('--includedata', action='store_true', - help=u._('Destroy data containers')) - parser.add_argument('--removeimages', action='store_true', - help=u._('Remove docker images')) - return parser - - def take_action(self, parsed_args): - try: - hostname = parsed_args.hostname.strip() - - hostnames = [hostname] - if hostname == 'all': - hostnames = _get_all_hostnames() - # if there are no hosts, don't bother doing anything - if not hostnames: - return - - destroy_type = 'kill' - if parsed_args.stop: - destroy_type = 'stop' - include_data = False - if parsed_args.includedata: - include_data = True - remove_images = False - if parsed_args.removeimages: - remove_images = True - - if include_data and not self._is_ok_to_delete_data(): - LOG.info('Aborting destroy') - return - - verbose_level = self.app.options.verbose_level - - job = CLIENT.host_destroy(hostnames, destroy_type, - verbose_level, include_data, - remove_images) - status = job.wait() - handers_action_result(job, status, verbose_level) - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - def _is_ok_to_delete_data(self): - question = ('This will delete all containers and data' - ', are you sure? (y/n)') - answer = input(question) - while answer != 'y' and answer != 'n': - answer = input(question) - return True if answer == 'y' else False - - -class HostRemove(Command): - """Remove host from openstack-kolla.""" - - def get_parser(self, prog_name): - parser = super(HostRemove, self).get_parser(prog_name) - parser.add_argument('hostname', metavar='', - help=u._('Host name or "all"')) - return parser - - def take_action(self, parsed_args): - try: - hostname = parsed_args.hostname.strip() - hostnames = [hostname] - if hostname == 'all': - hostnames = _get_all_hostnames() - if len(hostnames) > 0: - CLIENT.host_remove(hostnames) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class HostList(Lister): - """List hosts and their groups. - - If a hostname is provided, only list information about that host. - """ - - def get_parser(self, prog_name): - parser = super(HostList, self).get_parser(prog_name) - parser.add_argument('hostname', nargs='?', metavar='[hostname]', - help=u._('Host name')) - return parser - - def take_action(self, parsed_args): - try: - hostname = None - if parsed_args.hostname: - hostname = parsed_args.hostname.strip() - - hosts = [] - if hostname: - hosts = CLIENT.host_get([hostname]) - else: - hosts = CLIENT.host_get_all() - - data = [] - if hosts: - for host in hosts: - data.append((host.name, host.get_groups())) - else: - data.append(('', '')) - - data = convert_lists_to_string(data, parsed_args) - return ((u._('Host'), u._('Groups')), sorted(data)) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class HostCheck(Command): - """Check an ssh check of host(s).""" - - def get_parser(self, prog_name): - parser = super(HostCheck, self).get_parser(prog_name) - parser.add_argument('hostname', metavar='', - help=u._('Host name or "all"')) - return parser - - def take_action(self, parsed_args): - try: - hostname = parsed_args.hostname.strip() - if hostname == 'all': - hostnames = _get_all_hostnames() - else: - hostnames = [hostname] - - # just do an ssh check - summary = CLIENT.host_ssh_check(hostnames) - all_ok = True - for hostname, info in summary.items(): - status = u._('success') - msg = '' - if not info['success']: - status = u._('failed-') - msg = info['msg'] - all_ok = False - LOG.info(u._('Host {host}: {sts} {msg}') - .format(host=hostname, sts=status, msg=msg)) - - if not all_ok: - raise CommandError(u._('Host check failed.')) - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class HostSetup(Command): - """Setup kolla-cli on host.""" - - def get_parser(self, prog_name): - parser = super(HostSetup, self).get_parser(prog_name) - parser.add_argument('hostname', nargs='?', - metavar='', help=u._('Host name')) - parser.add_argument('--insecure', nargs='?', help=argparse.SUPPRESS) - parser.add_argument('--file', '-f', nargs='?', - metavar='', - help=u._('Absolute path to hosts info file ')) - return parser - - def take_action(self, parsed_args): - try: - if not parsed_args.hostname and not parsed_args.file: - raise CommandError( - u._('Host name or hosts info file path is required.')) - if parsed_args.hostname and parsed_args.file: - raise CommandError( - u._('Host name and hosts info file path ' - 'cannot both be present.')) - - if parsed_args.file: - # multi-host setup via xml file - # The xml file's content is like a dict of format: - # hostname1: - # uname: user1 - # password: - # hostname2: - # uname: user2 - # password: - hosts_data = self._get_yml_data(parsed_args.file.strip()) - CLIENT.host_setup(hosts_data) - else: - # single host setup - hostname = parsed_args.hostname.strip() - summary = CLIENT.host_ssh_check([hostname]) - if summary[hostname]['success']: - LOG.info( - u._LI('Skipping setup of host ({host}) as ' - 'ssh check is ok.').format(host=hostname)) - return 0 - - if parsed_args.insecure: - password = parsed_args.insecure.strip() - else: - password = getpass.getpass( - u._('{name} password for {host}: ') - .format(name=get_setup_user(), host=hostname)) - CLIENT.host_setup({hostname: {'password': password}}) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - def _get_yml_data(self, yml_path): - if not os.path.isfile(yml_path): - raise CommandError( - u._('No file exists at {path}. An absolute file path is ' - 'required.').format(path=yml_path)) - - with open(yml_path, 'r') as hosts_file: - file_data = hosts_file.read() - - hosts_info = yaml.safe_load(file_data) - if not hosts_info: - raise CommandError(u._('{path} is empty.').format(path=yml_path)) - return hosts_info - - -def _get_all_hostnames(): - hostnames = [] - hosts = CLIENT.host_get_all() - for host in hosts: - hostnames.append(host.name) - return hostnames diff --git a/kolla_cli/commands/kolla_action.py b/kolla_cli/commands/kolla_action.py deleted file mode 100644 index 09c11db..0000000 --- a/kolla_cli/commands/kolla_action.py +++ /dev/null @@ -1,342 +0,0 @@ -# Copyright(c) 2017, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import time -import traceback - -from cliff.command import Command - -from kolla_cli.api.client import ClientApi -from kolla_cli.commands.exceptions import CommandError -from kolla_cli.common.utils import handers_action_result -import kolla_cli.i18n as u - -CLIENT = ClientApi() -LOG = logging.getLogger(__name__) - - -class Deploy(Command): - """Deploy and start all kolla containers.""" - def get_parser(self, prog_name): - parser = super(Deploy, self).get_parser(prog_name) - parser.add_argument('--hosts', nargs='?', - metavar='', - help=u._('Deployment host list')) - parser.add_argument('--serial', action='store_true', - help=u._('Deploy serially')) - parser.add_argument('--timeout', nargs=1, - metavar='', - help=u._('timeout (in minutes)')) - parser.add_argument('--services', nargs='?', - metavar='', - help=u._('Deploy service list')) - return parser - - def take_action(self, parsed_args): - hosts = None - serial_flag = False - verbose_level = self.app.options.verbose_level - timeout_target = 0 - services = None - try: - if parsed_args.hosts: - host_list = parsed_args.hosts.strip() - hosts = host_list.split(',') - if parsed_args.serial: - serial_flag = True - if parsed_args.timeout: - try: - timeout = float(parsed_args.timeout[0]) - except Exception: - raise CommandError(u._('Timeout value is not a number.')) - timeout_target = time.time() + (60 * timeout) - if parsed_args.services: - service_list = parsed_args.services.strip() - services = service_list.split(',') - - # if we are doing a targeted host deploy make sure we are doing it - # to only compute nodes - if hosts: - invalid_host_list = [] - compute_group = CLIENT.group_get(['compute'])[0] - compute_hosts = compute_group.get_hosts() - for host in hosts: - if host not in compute_hosts: - invalid_host_list.append(host) - if len(invalid_host_list) > 0: - raise CommandError( - u._('Invalid hosts for host targeted deploy. ' - 'Hosts must be in the compute group only.' - 'Invalid hosts: {hosts}') - .format(hosts=invalid_host_list)) - - job = CLIENT.deploy(hosts, serial_flag, verbose_level, services) - - # wait for job to complete - status = None - while status is None: - if timeout_target and time.time() > timeout_target: - job.kill() - raise CommandError(u._('Job timed out and was killed.')) - time.sleep(1) - status = job.get_status() - - # job is done - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class Prechecks(Command): - """Do pre-deployment checks for hosts.""" - def get_parser(self, prog_name): - parser = super(Prechecks, self).get_parser(prog_name) - parser.add_argument('--hosts', nargs='?', - metavar='', - help=u._('Precheck host list')) - parser.add_argument('--services', nargs='?', - metavar='', - help=u._('Precheck service list')) - return parser - - def take_action(self, parsed_args): - hosts = [] - services = [] - try: - verbose_level = self.app.options.verbose_level - - if parsed_args.hosts: - host_list = parsed_args.hosts.strip() - hosts = host_list.split(',') - if parsed_args.services: - service_list = parsed_args.services.strip() - services = service_list.split(',') - job = CLIENT.prechecks(verbose_level, hosts, services) - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class Pull(Command): - """Pull all images for containers (only pulls, no running container).""" - def get_parser(self, prog_name): - parser = super(Pull, self).get_parser(prog_name) - parser.add_argument('--hosts', nargs='?', - metavar='', - help=u._('Pull host list')) - parser.add_argument('--services', nargs='?', - metavar='', - help=u._('Pull service list')) - return parser - - def take_action(self, parsed_args): - hosts = [] - services = [] - try: - verbose_level = self.app.options.verbose_level - if parsed_args.hosts: - host_list = parsed_args.hosts.strip() - hosts = host_list.split(',') - if parsed_args.services: - service_list = parsed_args.services.strip() - services = service_list.split(',') - job = CLIENT.pull(verbose_level, hosts, services) - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class Reconfigure(Command): - """Reconfigure OpenStack service.""" - def get_parser(self, prog_name): - parser = super(Reconfigure, self).get_parser(prog_name) - parser.add_argument('--hosts', nargs='?', - metavar='', - help=u._('Reconfigure host list')) - parser.add_argument('--services', nargs='?', - metavar='', - help=u._('Reconfigure service list')) - return parser - - def take_action(self, parsed_args): - hosts = [] - services = [] - try: - verbose_level = self.app.options.verbose_level - if parsed_args.hosts: - host_list = parsed_args.hosts.strip() - hosts = host_list.split(',') - if parsed_args.services: - service_list = parsed_args.services.strip() - services = service_list.split(',') - job = CLIENT.reconfigure(verbose_level, hosts, services) - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class Stop(Command): - """Stop all kolla containers on host(s). - - Stops all kolla related docker containers on either the - specified host or all hosts if the hostname all is used. - """ - def get_parser(self, prog_name): - parser = super(Stop, self).get_parser(prog_name) - parser.add_argument('--hosts', nargs='?', - metavar='', - help=u._('Stop host list')) - parser.add_argument('--services', nargs='?', - metavar='', - help=u._('Stop service list')) - return parser - - def take_action(self, parsed_args): - try: - hosts = [] - services = [] - verbose_level = self.app.options.verbose_level - if parsed_args.hosts: - host_list = parsed_args.hosts.strip() - hosts = host_list.split(',') - if parsed_args.services: - service_list = parsed_args.services.strip() - services = service_list.split(',') - job = CLIENT.stop(verbose_level, hosts, services) - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class Upgrade(Command): - """Upgrades existing OpenStack Environment.""" - def get_parser(self, prog_name): - parser = super(Upgrade, self).get_parser(prog_name) - parser.add_argument('--hosts', nargs='?', - metavar='', - help=u._('Upgrade host list')) - parser.add_argument('--services', nargs='?', - metavar='', - help=u._('Upgrade service list')) - return parser - - def take_action(self, parsed_args): - hosts = [] - services = [] - try: - if parsed_args.hosts: - host_list = parsed_args.hosts.strip() - hosts = host_list.split(',') - if parsed_args.services: - service_list = parsed_args.services.strip() - services = service_list.split(',') - verbose_level = self.app.options.verbose_level - job = CLIENT.upgrade(verbose_level, hosts, services) - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class Check(Command): - """Do post-deployment smoke tests.""" - def get_parser(self, prog_name): - parser = super(Check, self).get_parser(prog_name) - parser.add_argument('--hosts', nargs='?', - metavar='', - help=u._('Check host list')) - parser.add_argument('--services', nargs='?', - metavar='', - help=u._('Check service list')) - return parser - - def take_action(self, parsed_args): - hosts = [] - services = None - try: - if parsed_args.hosts: - host_list = parsed_args.hosts.strip() - hosts = host_list.split(',') - if parsed_args.services: - service_list = parsed_args.services.strip() - services = service_list.split(',') - verbose_level = self.app.options.verbose_level - job = CLIENT.check(verbose_level, hosts, services) - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class Genconfig(Command): - """Generate configuration files for enabled OpenStack services.""" - def get_parser(self, prog_name): - parser = super(Genconfig, self).get_parser(prog_name) - parser.add_argument('--hosts', nargs='?', - metavar='', - help=u._('genarate configs host list')) - parser.add_argument('--services', nargs='?', - metavar='', - help=u._('genarate configs service list')) - return parser - - def take_action(self, parsed_args): - hosts = [] - services = [] - try: - verbose_level = self.app.options.verbose_level - if parsed_args.hosts: - host_list = parsed_args.hosts.strip() - hosts = host_list.split(',') - if parsed_args.services: - service_list = parsed_args.services.strip() - services = service_list.split(',') - job = CLIENT.genconfig(verbose_level, hosts, services) - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class PostDeploy(Command): - """Do post deploy on deploy node.""" - - def take_action(self, parsed_args): - verbose_level = self.app.options.verbose_level - try: - job = CLIENT.postdeploy(verbose_level) - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) - - -class CertificateInit(Command): - """Generates self-signed certificate""" - - def take_action(self, parsed_args): - verbose_level = self.app.options.verbose_level - try: - job = CLIENT.certificate_init(verbose_level) - - # wait for job to complete - status = job.wait() - handers_action_result(job, status, verbose_level) - except Exception: - raise Exception(traceback.format_exc()) diff --git a/kolla_cli/commands/mode.py b/kolla_cli/commands/mode.py deleted file mode 100644 index 9529eaa..0000000 --- a/kolla_cli/commands/mode.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import traceback - -from cliff.command import Command - -from kolla_cli.api.client import ClientApi -from kolla_cli.commands.exceptions import CommandError -import kolla_cli.i18n as u - -LOG = logging.getLogger(__name__) -CLIENT = ClientApi() - - -class Setdeploy(Command): - """Set deploy mode to either local or remote. - - Local indicates that the openstack deployment will be - to the local host. Remote means that the deployment is - on remote hosts. - """ - def get_parser(self, prog_name): - parser = super(Setdeploy, self).get_parser(prog_name) - parser.add_argument('mode', metavar='', - help=u._('mode=')) - return parser - - def take_action(self, parsed_args): - try: - mode = parsed_args.mode.strip() - remote_flag = True - if mode == 'local': - remote_flag = False - LOG.info(u._('Please note that local mode is not supported ' - 'and should never be used in production ' - 'environments.')) - elif mode != 'remote': - raise CommandError( - u._('Invalid deploy mode. Mode must be ' - 'either "local" or "remote".')) - CLIENT.set_deploy_mode(remote_flag) - except CommandError as e: - raise e - except Exception: - raise Exception(traceback.format_exc()) - - -class Getdeploy(Command): - """get deploy mode from either local or remote. - - Local indicates that the openstack deployment will be - to the local host. Remote means that the deployment is - on remote hosts. - """ - - def take_action(self, parsed_args): - try: - mode = CLIENT.get_deploy_mode() - return mode - except CommandError as e: - raise e - except Exception: - raise Exception(traceback.format_exc()) diff --git a/kolla_cli/commands/password.py b/kolla_cli/commands/password.py deleted file mode 100644 index 496a358..0000000 --- a/kolla_cli/commands/password.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import getpass -import os -import traceback - -from cliff.command import Command -from cliff.lister import Lister - -from kolla_cli.api.client import ClientApi -from kolla_cli.commands.exceptions import CommandError -import kolla_cli.i18n as u - -CLIENT = ClientApi() - - -class PasswordSet(Command): - "Password Set" - - def get_parser(self, prog_name): - parser = super(PasswordSet, self).get_parser(prog_name) - parser.add_argument('passwordname', metavar='', - help=u._('Password name')) - parser.add_argument('--insecure', nargs='?', default=False, - help=argparse.SUPPRESS) - return parser - - def take_action(self, parsed_args): - try: - password_name = parsed_args.passwordname.strip() - if parsed_args.insecure is not False: - # --insecure flag is present - password = '' # nosec - if parsed_args.insecure: - password = parsed_args.insecure.strip() - else: - password = getpass.getpass(u._('Password: ')).strip() - passtwo = getpass.getpass(u._('Retype Password: ')).strip() - - if password != passtwo: - raise CommandError(u._('Passwords do not match')) - - CLIENT.password_set(password_name, password) - - except Exception: - raise Exception(traceback.format_exc()) - - -class PasswordSetKey(Command): - "Password Set SSH Key" - - def get_parser(self, prog_name): - parser = super(PasswordSetKey, self).get_parser(prog_name) - parser.add_argument('passwordname', metavar='', - help=u._('Password name')) - parser.add_argument('privatekeypath', metavar='', - help=u._('Path to private key file')) - parser.add_argument('publickeypath', metavar='', - help=u._('Path to public key file')) - return parser - - def take_action(self, parsed_args): - try: - password_name = parsed_args.passwordname.strip() - private_keypath = parsed_args.privatekeypath.strip() - private_keypath = os.path.abspath(private_keypath) - public_keypath = parsed_args.publickeypath.strip() - public_keypath = os.path.abspath(public_keypath) - - if not os.path.isfile(private_keypath): - raise(CommandError(u._('Private key file not found: {path}') - .format(path=private_keypath))) - if not os.path.isfile(public_keypath): - raise(CommandError(u._('Public key file not found: {path}') - .format(path=public_keypath))) - - with open(private_keypath, 'r') as f: - private_key = f.read() - with open(public_keypath, 'r') as f: - public_key = f.read() - CLIENT.password_set_sshkey(password_name, private_key.strip(), - public_key.strip()) - - except Exception: - raise Exception(traceback.format_exc()) - - -class PasswordClear(Command): - "Password Clear" - - def get_parser(self, prog_name): - parser = super(PasswordClear, self).get_parser(prog_name) - parser.add_argument('passwordname', metavar='', - help=u._('Password name')) - return parser - - def take_action(self, parsed_args): - try: - password_name = parsed_args.passwordname.strip() - CLIENT.password_clear(password_name) - except Exception: - raise Exception(traceback.format_exc()) - - -class PasswordList(Lister): - """List all password names.""" - - def take_action(self, parsed_args): - try: - password_names = CLIENT.password_get_names() - password_names = sorted(password_names) - - data = [] - for password_name in password_names: - data.append((password_name, '-')) - - return ((u._('Password Name'), u._('Password')), data) - except Exception: - raise Exception(traceback.format_exc()) - - -class PasswordInit(Command): - """Init all empty passwords and ssh keys.""" - - def take_action(self, parsed_args): - try: - CLIENT.password_init() - except Exception: - raise Exception(traceback.format_exc()) diff --git a/kolla_cli/commands/property.py b/kolla_cli/commands/property.py deleted file mode 100644 index 77e5112..0000000 --- a/kolla_cli/commands/property.py +++ /dev/null @@ -1,266 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import traceback - -from cliff.command import Command -from cliff.lister import Lister - -from kolla_cli.api.client import ClientApi -from kolla_cli.commands.exceptions import CommandError -from kolla_cli.common import utils -import kolla_cli.i18n as u - -CLIENT = ClientApi() - - -def _get_names(args_list): - csv_list = args_list[0].strip() - names = csv_list.split(',') - if 'all' in names: - names = None - return names - - -class PropertySet(Command): - "Property Set" - - def get_parser(self, prog_name): - parser = super(PropertySet, self).get_parser(prog_name) - parser.add_argument('propertyname', metavar='', - help=u._('Property name')) - parser.add_argument('propertyvalue', metavar=' property_length): - if self.is_all_flag: - include_prop = True - else: - include_prop = True - - if not include_prop: - continue - - ovr_global = '-' - ovr_group = '-' - ovr_host = '-' - - if prop.ovr_global: - ovr_global = '*' - if prop.ovr_group: - ovr_group = 'G' - if prop.ovr_host: - ovr_host = 'H' - - prop_ovr = ovr_global + ovr_group + ovr_host - - if self.is_long_flag: - if self.is_global: - data.append((prop_ovr, prop.name, prop.value, - prop.orig_value)) - else: - data.append((prop_ovr, prop.name, prop.value, - prop.orig_value, prop.target)) - else: - if self.is_global: - data.append((prop_ovr, prop.name, prop.value)) - else: - data.append((prop_ovr, prop.name, prop.value, - prop.target)) - else: - if self.is_long_flag: - if self.is_global: - data.append(('', '', '', '')) - else: - data.append(('', '', '', '', '')) - else: - if self.is_global: - data.append(('', '', '')) - else: - data.append(('', '', '', '')) - - return data diff --git a/kolla_cli/commands/service.py b/kolla_cli/commands/service.py deleted file mode 100644 index 9c72db5..0000000 --- a/kolla_cli/commands/service.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import traceback - -from cliff.command import Command -from cliff.lister import Lister - -from kolla_cli.api.client import ClientApi -from kolla_cli.api.exceptions import ClientException -from kolla_cli.commands.exceptions import CommandError -from kolla_cli.common.utils import convert_lists_to_string -import kolla_cli.i18n as u - -CLIENT = ClientApi() - - -class ServiceAddGroup(Command): - """Add group to service. - - Associated the service to a group. If this is a sub-service, - the inherit flag will be cleared. - """ - - def get_parser(self, prog_name): - parser = super(ServiceAddGroup, self).get_parser(prog_name) - parser.add_argument('servicename', metavar='', - help=u._('Service name')) - parser.add_argument('groupname', metavar='', - help=u._('Group name')) - return parser - - def take_action(self, parsed_args): - try: - groupname = parsed_args.groupname.strip() - servicename = parsed_args.servicename.strip() - - group = CLIENT.group_get([groupname])[0] - group.add_service(servicename) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class ServiceRemoveGroup(Command): - """Remove group from service.""" - - def get_parser(self, prog_name): - parser = super(ServiceRemoveGroup, self).get_parser(prog_name) - parser.add_argument('servicename', metavar='', - help=u._('Service name')) - parser.add_argument('groupname', metavar='', - help=u._('Group name')) - return parser - - def take_action(self, parsed_args): - try: - groupname = parsed_args.groupname.strip() - servicename = parsed_args.servicename.strip() - - group = CLIENT.group_get([groupname])[0] - group.remove_service(servicename) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class ServiceListGroups(Lister): - """List services and their groups.""" - - def take_action(self, parsed_args): - try: - data = [('', '')] - services = CLIENT.service_get_all() - if services: - data = [] - for service in services: - groupnames = sorted(service.get_groups()) - data.append((service.name, groupnames)) - - data = convert_lists_to_string(data, parsed_args) - return (u._('Service'), u._('Groups')), sorted(data) - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) - - -class ServiceList(Lister): - """List services and their sub-services.""" - - def take_action(self, parsed_args): - try: - data = [('', '')] - services = CLIENT.service_get_all() - if services: - data = [] - for service in services: - data.append((service.name, - sorted(service.get_children()))) - - data = convert_lists_to_string(data, parsed_args) - return ((u._('Service'), u._('Children')), sorted(data)) - - except ClientException as e: - raise CommandError(str(e)) - except Exception: - raise Exception(traceback.format_exc()) diff --git a/kolla_cli/commands/support.py b/kolla_cli/commands/support.py deleted file mode 100644 index 1483dab..0000000 --- a/kolla_cli/commands/support.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import tempfile -import traceback - -from cliff.command import Command - -from kolla_cli.api.client import ClientApi -import kolla_cli.i18n as u - -LOG = logging.getLogger(__name__) -CLIENT = ClientApi() - - -class Dump(Command): - """Dumps configuration data for debugging. - - Dumps most files in /etc/kolla and /usr/share/kolla into a - tar file so be given to support / development to help with - debugging problems. - """ - def take_action(self, parsed_args): - try: - dump_path = CLIENT.support_dump(tempfile.gettempdir()) - LOG.info(u._('Dump successful to {path}').format(path=dump_path)) - except Exception: - msg = (u._('Dump failed: {reason}') - .format(reason=traceback.format_exc())) - raise Exception(msg) diff --git a/kolla_cli/common/__init__.py b/kolla_cli/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kolla_cli/common/ansible/__init__.py b/kolla_cli/common/ansible/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kolla_cli/common/ansible/actions.py b/kolla_cli/common/ansible/actions.py deleted file mode 100644 index 58f9037..0000000 --- a/kolla_cli/common/ansible/actions.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os - -from kolla_cli.api.exceptions import InvalidArgument -from kolla_cli.api.exceptions import InvalidConfiguration -from kolla_cli.api.exceptions import NotInInventory -from kolla_cli.common.ansible.playbook import AnsiblePlaybook -from kolla_cli.common.inventory import Inventory -from kolla_cli.common.passwords import get_empty_password_values -from kolla_cli.common.properties import AnsibleProperties -from kolla_cli.common.utils import get_admin_user -from kolla_cli.common.utils import get_kolla_ansible_home -from kolla_cli.common.utils import get_kolla_etc -from kolla_cli.common.utils import is_string_true -import kolla_cli.i18n as u - -LOG = logging.getLogger(__name__) - - -class KollaAction(object): - """Kolla Action.""" - - def __init__(self, verbose_level=0, playbook_name=''): - self.playbook_name = playbook_name - self.playbook_path = os.path.join(get_kolla_ansible_home(), - 'ansible/', - self.playbook_name) - self.playbook = AnsiblePlaybook() - self.playbook.verbose_level = verbose_level - self.playbook.playbook_path = self.playbook_path - - def certificate_init(self): - '''Creates a self-signed certificate''' - - self.playbook.local_only = True - self.playbook.become_user = get_admin_user() - job = self.playbook.run() - return job - - def deploy(self, hostnames=[], serial_flag=False, servicenames=[]): - '''Deploy and start all kolla containers.''' - - self.playbook.hosts = hostnames - self.playbook.serial = serial_flag - self.playbook.services = servicenames - self.playbook.extra_vars = 'kolla_action=deploy' - - self._run_deploy_rules(self.playbook) - - job = self.playbook.run() - return job - - def reconfigure(self, hostnames=[], servicenames=[]): - '''Reconfigure OpenStack service.''' - - self.playbook.hosts = hostnames - self.playbook.services = servicenames - self.playbook.extra_vars = 'kolla_action=reconfigure' - - self._run_deploy_rules(self.playbook) - - job = self.playbook.run() - return job - - def postdeploy(self): - '''Do post deploy on deploy node.''' - - self.playbook.local_only = True - self.playbook.become_user = get_admin_user() - job = self.playbook.run() - return job - - def destroy_hosts(self, hostnames, destroy_type, - include_data=False, remove_images=False): - '''destroy containers on a set of hosts. - - The containers on the specified hosts will be stopped - or killed. - ''' - - LOG.info(u._LI('Please be patient as this may take a while.')) - # 'hosts' is defined as 'all' in the playbook yml code, but inventory - # filtering will subset that down to the hosts in playbook.hosts. - self.playbook.hosts = hostnames - if remove_images: - self.playbook.extra_vars = 'destroy_include_images=yes' - if self.playbook.verbose_level <= 1: - self.playbook.print_output = False - job = self.playbook.run() - return job - - def stop(self, hostnames=[], servicenames=[]): - '''stop containers on a set of hosts. - - The containers on the specified hosts will be stopped - or killed if the stop takes over 20 seconds. - ''' - - LOG.info(u._LI('Please be patient as this may take a while.')) - # 'hosts' is defined as 'all' in the playbook yml code, but inventory - # filtering will subset that down to the hosts in playbook.hosts. - self.playbook.hosts = hostnames - self.playbook.services = servicenames - self.playbook.extra_vars = 'kolla_action=stop' - if self.playbook.verbose_level <= 1: - self.playbook.print_output = False - job = self.playbook.run() - return job - - def precheck(self, hostnames=[], servicenames=[]): - '''run check playbooks on a set of hosts''' - - # check that password file has no empty password values - empty_keys = get_empty_password_values() - if empty_keys: - raise InvalidConfiguration( - u._('password check failed. There are empty password values ' - 'in {etc}passwords.yml. ' - 'Please run kolla-cli password init or ' - 'kolla-cli password set(key) to correct them. ' - '\nEmpty passwords: ' - '{keys}').format(etc=get_kolla_etc(), keys=empty_keys)) - - # define 'hosts' to be all, but inventory filtering will subset - # that down to the hosts in playbook.hosts. - self.playbook.hosts = hostnames - self.playbook.services = servicenames - self.playbook.extra_vars = 'kolla_action=precheck' - self.playbook.print_output = True - job = self.playbook.run() - return job - - def pull(self, hostnames=[], servicenames=[]): - '''run pull action against all hosts''' - - self.playbook.hosts = hostnames - self.playbook.services = servicenames - self.playbook.extra_vars = 'kolla_action=pull' - self.playbook.print_output = True - job = self.playbook.run() - return job - - def upgrade(self, hostnames=[], servicenames=[]): - '''Upgrades existing OpenStack Environment.''' - - self.playbook.hosts = hostnames - self.playbook.services = servicenames - self.playbook.extra_vars = 'kolla_action=upgrade' - self.playbook.print_output = True - job = self.playbook.run() - return job - - def genconfig(self, hostnames=[], servicenames=[]): - '''Generate configuration files for enabled OpenStack services''' - - self.playbook.hosts = hostnames - self.playbook.services = servicenames - self.playbook.extra_vars = 'kolla_action=config' - self.playbook.print_output = True - job = self.playbook.run() - return job - - def check(self, hostnames=[], servicenames=[]): - '''Do post-deployment smoke tests.''' - - self.playbook.hosts = hostnames - self.playbook.services = servicenames - self.playbook.extra_vars = 'kolla_action=check' - self.playbook.print_output = True - job = self.playbook.run() - return job - - def _run_deploy_rules(self, playbook): - properties = AnsibleProperties() - inventory = Inventory.load() - - # cannot have both groups and hosts - if playbook.hosts and playbook.groups: - raise InvalidArgument( - u._('Hosts and Groups arguments cannot ' - 'both be present at the same time.')) - - # verify that all services exists - if playbook.services: - for service in playbook.services: - valid_service = inventory.get_service(service) - if not valid_service: - raise NotInInventory(u._('Service'), service) - - # check that every group with enabled services - # has hosts associated to it - group_services = inventory.get_group_services() - failed_groups = [] - failed_services = [] - if group_services: - for (groupname, servicenames) in group_services.items(): - group = inventory.get_group(groupname) - hosts = group.get_hostnames() - - group_needs_host = False - if not hosts: - for servicename in servicenames: - if self._is_service_enabled(servicename, - inventory, - properties): - group_needs_host = True - failed_services.append(servicename) - if group_needs_host: - failed_groups.append(groupname) - - if len(failed_groups) > 0: - raise InvalidConfiguration( - u._('Deploy failed. ' - 'Groups: {groups} with enabled ' - 'services : {services} ' - 'have no associated hosts') - .format(groups=failed_groups, services=failed_services)) - - def _is_service_enabled(self, servicename, inventory, properties): - service = inventory.get_service(servicename) - if service is not None: - enabled_property = 'enable_' + servicename.replace('-', '_') - is_enabled = properties.get_property_value(enabled_property) - if type(is_enabled) is str: - is_enabled = is_string_true(is_enabled) - return is_enabled diff --git a/kolla_cli/common/ansible/job.py b/kolla_cli/common/ansible/job.py deleted file mode 100644 index e60d707..0000000 --- a/kolla_cli/common/ansible/job.py +++ /dev/null @@ -1,269 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fcntl -import json -import logging -import os -import pwd -import re -import subprocess # nosec -import time - -from kolla_cli.common.inventory import remove_temp_inventory -from kolla_cli.common.utils import get_kolla_actions_path -from kolla_cli.common.utils import Lock -from kolla_cli.common.utils import PidManager -from kolla_cli.common.utils import run_cmd -from kolla_cli.common.utils import safe_decode -import kolla_cli.i18n as u - -LOG = logging.getLogger(__name__) - -LINE_LENGTH = 80 - -ANSIBLE_1_OR_MORE = 'One or more items failed' - - -class AnsibleJob(object): - """class for running ansible commands""" - - def __init__(self, cmd, deploy_id, print_output, inventory_path): - self._command = cmd - self._deploy_id = deploy_id - self._print_output = print_output - self._temp_inv_path = inventory_path - - self._process = None - self._process_std_err = None - self._errors = [] - self._error_total = 0 - self._ignore_total = 0 - self._cmd_output = '' - self._kill_uname = None - self._ansible_lock = Lock(owner='ansible_job') - self._ignore_error_strings = None - self._host_ignored_error_count = {} - - def run(self): - try: - locked = self._ansible_lock.wait_acquire() - if not locked: - raise Exception( - u._('unable to get lock: {lock}, to run ' - 'ansible job: {cmd} ') - .format(lock=self._ansible_lock.lockpath, - cmd=self._command)) - - LOG.debug('playbook command: %s' % self._command) - # ansible 2.2 and later introduced an issue where if - # the playbook is executed from within a directory without - # read / write permission (which can happen when you, - # for example, execute via sudo) it will fail. the - # workaround will be to run the ansible command from /tmp - # and then change back to the original directory at the end - current_dir = os.getcwd() # nosec - os.chdir('/tmp') # nosec - self._process = subprocess.Popen(self._command, # nosec - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - # setup stdout to be read without blocking - LOG.debug('process pid: %s' % self._process.pid) - flags = fcntl.fcntl(self._process.stdout, fcntl.F_GETFL) - fcntl.fcntl(self._process.stdout, fcntl.F_SETFL, - (flags | os.O_NONBLOCK)) - - # this is also part of the fix for ansible 2.2 and later - os.chdir(current_dir) - except Exception as e: - self._cleanup() - raise e - - def wait(self): - """wait for job to complete - - return status of job (see get_status for status values) - """ - while True: - status = self.get_status() - if status is not None: - break - time.sleep(0.2) - return status - - def get_status(self): - """get process status - - status: - - None: running - - 0: done, success - - 1: done, error - - 2: done, killed by user - """ - status = self._process.poll() - out = self._read_stream(self._process.stdout) - self._cmd_output = ''.join([self._cmd_output, out]) - - # unnecessary spaces should be hidden - if out: - self._log_output(out) - if status is not None: - # job has completed - if self._kill_uname: - status = 2 - msg = (u._('Job killed by user ({name})') - .format(name=self._kill_uname)) - self._errors = [msg] - else: - status = self._process.returncode - if status != 0: - # if the process ran and returned a non zero return - # code we want to see if we got some ansible errors - # and if so if we ignored all the errors. if all - # errors are ignored we consider the job a success - if (self._error_total > 0 and - self._error_total == self._ignore_total): - status = 0 - else: - status = 1 - if not self._process_std_err: - # read stderr from process - std_err = self._read_stream(self._process.stderr) - self._process_std_err = std_err.strip() - self._cleanup() - return status - - def get_error_message(self): - """"get error message""" - msg = '' - for error in self._errors: - if error: - msg = ''.join([msg, error, '\n']) - - if ANSIBLE_1_OR_MORE in msg: - msg = self._get_msg_from_cmdout(msg) - if not msg: - msg = self._process_std_err - return msg - - def get_command_output(self): - """get command output - - get final output text from command execution - """ - return self._cmd_output - - def kill(self): - """kill job in progress - - The process pid is owned by root, so - that is not killable. Need to kill all its children. - """ - # the kill must be run as the kolla user so the - # kolla_actions program must be used. - try: - actions_path = get_kolla_actions_path() - cmd_prefix = ('%s job -t -p ' - % actions_path) - - # kill the children from largest to smallest pids. - child_pids = PidManager.get_child_pids(self._process.pid) - for child_pid in sorted(child_pids, reverse=True): - cmd = ''.join([cmd_prefix, child_pid]) - err_msg, output = run_cmd(cmd, print_output=False) - if err_msg: - LOG.debug('kill failed: %s %s' % (err_msg, output)) - else: - LOG.debug('kill succeeded: %s' % child_pid) - - # record the name of user who killed the job - cur_uid = os.getuid() - self._kill_uname = pwd.getpwuid(cur_uid)[0] - finally: - self._cleanup() - - def _get_msg_from_cmdout(self, msg): - """get message from command output - - This is where the error message is in cmd out- - \nfailed: [ol7-c5] (item=[u'/etc/kolla/config/aodh.conf', - u'/usr/share/kolla/templates/aodh/aodh.conf_augment']) => - {"failed": true, "invocation": {"module_args": {"dest": - "/usr/share/kolla/templates/aodh/aodh.conf_augment", - "src": "/etc/kolla/config/aodh.conf"}, "module_name": "template"}, - "item": ["/etc/kolla/config/aodh.conf", - "/usr/share/kolla/templates/aodh/aodh.conf_augment"], - "msg": "IOError: [Errno 2] No such file or directory: - u'/etc/kolla/config/aodh.conf'"}\n - """ - fail_key = '\nfailed: ' - hostnames = re.findall(fail_key + r'\[(.+?)]', self._cmd_output) - msgs = re.findall(fail_key + '.+ => (.+?)\n', self._cmd_output) - - for i in range(0, min(len(hostnames), len(msgs))): - err = '' - hostname = hostnames[i] - ans_dict_str = msgs[i] - try: - ans_dict = json.loads(ans_dict_str) - err = ans_dict.get('msg', '') - except Exception as e: - LOG.warn('Exception reading cmd_out ansible dictionary: %s' - % str(e)) - msg = ''.join([msg, 'Host: ', hostname, ', ', err, '\n']) - return msg - - def _read_stream(self, stream): - out = '' - if stream and not stream.closed: - try: - out = safe_decode(stream.read()) - except IOError: # nosec - # error can happen if stream is empty - pass - if out is None: - out = '' - return out - - def _log_lines(self, lines): - if self._print_output: - for line in lines: - LOG.info(line) - - def _log_output(self, output): - if self._print_output: - LOG.info(output) - - def _cleanup(self): - """cleanup job - - - release the ansible lock - - close stdout and stderr - - delete temp inventory - """ - # try to clear the ansible lock - self._ansible_lock.release() - - # close the process's stdout and stderr streams - if (self._process and self._process.stdout and not - self._process.stdout.closed): - self._process.stdout.close() - if (self._process and self._process.stderr and not - self._process.stderr.closed): - self._process.stderr.close() - - # delete temp inventory file - remove_temp_inventory(self._temp_inv_path) diff --git a/kolla_cli/common/ansible/playbook.py b/kolla_cli/common/ansible/playbook.py deleted file mode 100644 index 184c86a..0000000 --- a/kolla_cli/common/ansible/playbook.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os -import traceback - -from kolla_cli.common.ansible.job import AnsibleJob -from kolla_cli.common.inventory import Inventory -from kolla_cli.common.utils import get_ansible_command -from kolla_cli.common.utils import get_kolla_etc - -MYPY = False -if MYPY: - from typing import List # noqa - - -LOG = logging.getLogger(__name__) - - -class AnsiblePlaybook(object): - playbook_path = '' - extra_vars = '' - include_passwords = True - flush_cache = True - print_output = True - verbose_level = 0 - hosts = None # type: List[str] - groups = None # type: List[str] - services = None # type: List[str] - ignore_error_strings = None # type: List[str] - serial = False - deploy_id = None # type: str - inventory = None # type: Inventory - local_only = False - become_user = None # type: str - - def run(self): - try: - if self.local_only: - # Create a temporary local inventory with only localhost - self.inventory = Inventory() - self.inventory.set_deploy_mode(False) - self.inventory.add_host('localhost') - else: - self.inventory = Inventory.load() - inventory_path = self._make_temp_inventory() - cmd = self._get_playbook_cmd(inventory_path) - self._log_ansible_cmd(cmd, inventory_path) - - # create and run the job - job = AnsibleJob(cmd, self.deploy_id, - self.print_output, inventory_path) - job._ignore_error_strings = self.ignore_error_strings - job.run() - return job - - except Exception: - raise Exception(traceback.format_exc()) - - def _get_playbook_cmd(self, inventory_path): - flag = '' - # verbose levels: 1=not verbose, 2=more verbose - if self.verbose_level > 1: - flag = '-' - for x in range(1, self.verbose_level): - flag += 'v' - - ansible_cmd = get_ansible_command(playbook=True) - cmd = '%s %s' % (ansible_cmd, flag) - - cmd += ' -i %s' % inventory_path - - if self.include_passwords: - cmd += ' %s' % self._get_password_path() - - cmd += ' %s' % self.playbook_path - - if self.extra_vars or self.serial: - extra_vars = '' - if self.extra_vars: - extra_vars = self.extra_vars - if self.serial: - extra_vars += ' ' - if self.serial: - extra_vars += 'serial_var=1' - - cmd += ' --extra-vars \"%s\"' % extra_vars - - if self.services: - service_string = '' - first = True - for service in self.services: - if not first: - service_string += ',' - else: - first = False - service_string = service_string + service - cmd += ' --tags %s' % service_string - - if self.hosts: - host_string = '' - first = True - for host in self.hosts: - if not first: - host_string += ',' - else: - first = False - host_string = host_string + host - cmd += ' --limit %s' % host_string - - if self.flush_cache: - cmd += ' --flush-cache' - - if self.become_user: - cmd += ' --become-user %s' % self.become_user - - return cmd - - def _make_temp_inventory(self): - """Create temporary inventory file - - A temporary inventory is created so that a - unique id can be assigned to the deployment. - """ - inventory_filter = {} - inventory_path = \ - self.inventory.create_json_gen_file(inventory_filter) - - # inv path = /tmp/kolla_UUID/temp_inventory.py - deploy_id = os.path.dirname(inventory_path) - self.deploy_id = deploy_id.split('kolla_')[1] - - return inventory_path - - def _get_password_path(self): - kolla_etc = get_kolla_etc() - return ('-e @' + os.path.join(kolla_etc, 'passwords.yml ')) - - def _log_ansible_cmd(self, cmd, inventory_path): - if self.verbose_level > 2: - # log the ansible command - LOG.debug('cmd:\n%s' % cmd) - - if self.verbose_level > 3: - # log the inventory - with open(inventory_path, 'r') as inv_file: - inv = inv_file.read() - LOG.debug('\ninventory: \n%s' % inv) diff --git a/kolla_cli/common/ansible/utils.py b/kolla_cli/common/ansible/utils.py deleted file mode 100644 index b0495a0..0000000 --- a/kolla_cli/common/ansible/utils.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright(c) 2019, caoyuan. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from kolla_cli.common.inventory import Inventory - - -def check_kolla_args(hostnames=[], servicenames=[]): - - if not any([hostnames, servicenames]): - return - - inventory = Inventory.load() - if hostnames: - inventory.validate_hostnames(hostnames) - - if servicenames: - inventory.validate_servicenames(servicenames) diff --git a/kolla_cli/common/ansible_inventory.py b/kolla_cli/common/ansible_inventory.py deleted file mode 100644 index d11b17b..0000000 --- a/kolla_cli/common/ansible_inventory.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -import os - -from kolla_cli.common.service import Service -from kolla_cli.common.utils import get_kolla_ansible_home - - -class AnsibleInventory(object): - """AnsibleInventory helper class - - This class parses an ansible inventory file and provides an - easier to use way to represent that file. - """ - def __init__(self, inventory_path=None): - self.groups = [] - self.services = {} - self.group_vars = {} - self.host_vars = {} - - self._load(inventory_path) - - def add_service(self, servicename): - if servicename not in self.services: - service = Service(servicename) - self.services[servicename] = service - return self.services[servicename] - - def add_group(self, groupname): - if groupname not in self.groups: - self.groups.append(groupname) - - def _load(self, inventory_path): - """load an ansible inventory file - - Note: This assumes that there will be a blank line between each - section: - - # Mistral - [mistral-api:children] - mistral - - [mistral-executor:children] - mistral - """ - if not inventory_path: - inventory_path = os.path.join( - get_kolla_ansible_home(), 'ansible', 'inventory', - 'all-in-one') - with open(inventory_path, 'r') as ain1: - ain1_inv = ain1.read() - - lines = [x for x in ain1_inv.split('\n') if not x.startswith('#')] - for i in range(0, len(lines)): - line = lines[i] - if not line.startswith('['): - continue - line.strip() - if ':vars' in line: - # this is defining a set of group vars in the next set - # of lines. - groupname = line.split(':')[0] - i = self._process_group_vars(groupname, lines, i) - continue - if ':children' not in line: - groupname = line[1:len(line) - 1] - self.add_group(groupname) - continue - - servicename = line.split(':children')[0] - servicename = servicename[1:] - service = self.add_service(servicename) - - # next lines will be parents or groups for service found above - has_parents_or_groups = False - while True: - i += 1 - line = lines[i] - parent_or_group = line.strip() - if parent_or_group.startswith('#'): - # comment line, skip - continue - if not parent_or_group: - # blank line, done processing parents - # if a service has no parent or group associations - # we infer that it is not supported and is filtered - # from being shown to the client - service.set_supported(has_parents_or_groups) - break - if parent_or_group in self.groups: - service.add_groupname(parent_or_group) - has_parents_or_groups = True - else: - service.add_parentname(parent_or_group) - has_parents_or_groups = True - - for _, service in self.services.items(): - for parentname in service.get_parentnames(): - parent = self.services[parentname] - if parent: - parent.add_childname(service.name) - - def _process_group_vars(self, groupname, lines, i): - # currently group vars are ignored - while True: - i += 1 - line = lines[i].strip() - if not line: - break diff --git a/kolla_cli/common/host.py b/kolla_cli/common/host.py deleted file mode 100644 index 9a87532..0000000 --- a/kolla_cli/common/host.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - - -class Host(object): - class_version = 1 - - def __init__(self, hostname): - self.name = hostname - self.alias = '' - self.is_mgmt = False - self.hypervisor = '' - self.vars = {} - self.version = self.__class__.class_version - - def get_vars(self): - return self.vars.copy() - - def set_var(self, name, value): - self.vars[name] = value - - def upgrade(self): - pass diff --git a/kolla_cli/common/host_group.py b/kolla_cli/common/host_group.py deleted file mode 100644 index 0a666ac..0000000 --- a/kolla_cli/common/host_group.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from copy import copy -from kolla_cli.common.utils import get_admin_user - -ANSIBLE_BECOME = 'ansible_become' -ANSIBLE_SSH_USER = 'ansible_ssh_user' -ANSIBLE_CONNECTION = 'ansible_connection' - - -class HostGroup(object): - class_version = 1 - - def __init__(self, name): - self.name = name - self.hostnames = [] - self.vars = {} - self.version = self.__class__.class_version - - def upgrade(self): - pass - - def add_host(self, host): - if host.name is not None and host.name not in self.hostnames: - self.hostnames.append(host.name) - - def remove_host(self, host): - if host.name in self.hostnames: - self.hostnames.remove(host.name) - - def get_hostnames(self): - return copy(self.hostnames) - - def get_vars(self): - return self.vars.copy() - - def set_var(self, name, value): - self.vars[name] = value - - def clear_var(self, name): - if name in self.vars: - del self.vars[name] - - def set_remote(self, remote_flag): - self.set_var(ANSIBLE_BECOME, 'yes') - if remote_flag: - # set the ssh info for all the servers in the group - self.set_var(ANSIBLE_SSH_USER, get_admin_user()) - self.clear_var(ANSIBLE_CONNECTION) - else: - # remove ssh info, add local connection type - self.set_var(ANSIBLE_CONNECTION, 'local') - self.clear_var(ANSIBLE_SSH_USER) diff --git a/kolla_cli/common/inventory.py b/kolla_cli/common/inventory.py deleted file mode 100644 index 01846f2..0000000 --- a/kolla_cli/common/inventory.py +++ /dev/null @@ -1,687 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from copy import copy -import json -import jsonpickle -import logging -import os -import tempfile -import traceback -import uuid - -import kolla_cli.i18n as u - -from kolla_cli.api.exceptions import FailedOperation -from kolla_cli.api.exceptions import HostError -from kolla_cli.api.exceptions import InvalidArgument -from kolla_cli.api.exceptions import InvalidConfiguration -from kolla_cli.api.exceptions import MissingArgument -from kolla_cli.api.exceptions import NotInInventory -from kolla_cli.common.ansible_inventory import AnsibleInventory -from kolla_cli.common.host import Host -from kolla_cli.common.host_group import HostGroup -from kolla_cli.common.service import Service -from kolla_cli.common.sshutils import ssh_setup_host -from kolla_cli.common.utils import get_admin_uids -from kolla_cli.common.utils import get_ansible_command -from kolla_cli.common.utils import get_group_vars_dir -from kolla_cli.common.utils import get_host_vars_dir -from kolla_cli.common.utils import get_kolla_cli_etc -from kolla_cli.common.utils import run_cmd -from kolla_cli.common.utils import sync_read_file -from kolla_cli.common.utils import sync_write_file - -ANSIBLE_SSH_USER = 'ansible_ssh_user' -ANSIBLE_CONNECTION = 'ansible_connection' -ANSIBLE_BECOME = 'ansible_become' - -INVENTORY_PATH = 'ansible/inventory.json' - -COMPUTE_GRP_NAME = 'compute' - -# these groups cannot be deleted, they are required by kolla -PROTECTED_GROUPS = [COMPUTE_GRP_NAME] - -LOG = logging.getLogger(__name__) - - -def remove_temp_inventory(path): - # type: (str) -> None - """remove temp inventory file and its parent directory""" - if path: - if os.path.exists(path): - os.remove(path) - dirpath = os.path.dirname(path) - if os.path.exists(dirpath): - os.rmdir(dirpath) - - -class Inventory(object): - class_version = 4 - """class version history - - 4: (v4.0.1): - removed concept of sub-services (not backward compatible) - 3: (v3.0.1): - added aodh, ceph - fix to ensure all sub-services have service as parent - - 2: (v2.1.1) added ceilometer - - 1: (v2.0.1) initial release - """ - def __init__(self, inventory_path=None): - self._groups = {} # kv = name:object - self._hosts = {} # kv = name:object - self._services = {} # kv = name:object - self.vars = {} - self.version = self.__class__.class_version - self.remote_mode = True - - # initialize the inventory to its defaults as they are - # described in the kolla-ansible all-in-one inventory file. - self.import_inventory(inventory_path) - - def upgrade(self): - # check for new services or subservices in the all-in-one file - # leaving in this hook but no upgrade from <4 to 4 is supported - # so yanking out all upgrade logic - self._upgrade_services() - - # update the version and save upgraded inventory file - self.version = self.__class__.class_version - Inventory.save(self) - - def _upgrade_services(self): - ansible_inventory = AnsibleInventory() - - # add new services - for servicename, service in ansible_inventory.services.items(): - if servicename not in self._services: - self._services[servicename] = service - else: - # If Service newly enabled/disabled, take the latest - if self._services[servicename].is_supported() != \ - service.is_supported(): - self._services[servicename].set_supported( - service.is_supported()) - - # If Service group changed, take the latest - if sorted(self._services[servicename].get_groupnames()) != \ - sorted(service.get_groupnames()): - self._services[servicename].set_groupnames( - service.get_groupnames()) - - # remove obsolete services - for servicename in copy(self._services).keys(): - if servicename not in ansible_inventory.services: - self.delete_service(servicename) - - @staticmethod - def load(): - """load the inventory from a pickle file""" - inventory_path = os.path.join(get_kolla_cli_etc(), INVENTORY_PATH) - data = '' - try: - if os.path.exists(inventory_path): - data = sync_read_file(inventory_path) - - if data.strip(): - inventory = jsonpickle.decode(data) - - # upgrade version handling - if inventory.version != inventory.class_version: - inventory.upgrade() - else: - inventory = Inventory() - Inventory.save(inventory) - except Exception: - raise FailedOperation( - u._('Loading inventory failed. : {error}') - .format(error=traceback.format_exc())) - return inventory - - @staticmethod - def save(inventory): - """Save the inventory in a pickle file""" - inventory_path = os.path.join(get_kolla_cli_etc(), INVENTORY_PATH) - try: - # multiple trips thru json to render a readable inventory file - data = jsonpickle.encode(inventory) - data_str = json.loads(data) - pretty_data = json.dumps(data_str, indent=4) - sync_write_file(inventory_path, pretty_data) - - except Exception as e: - raise FailedOperation( - u._('Saving inventory failed. : {error}') - .format(error=str(e))) - - def get_hosts(self): - return self._hosts.values() - - def get_hostnames(self): - return list(self._hosts.keys()) - - def get_host(self, hostname): - host = None - if hostname in self._hosts: - host = self._hosts[hostname] - return host - - def add_host(self, hostname, groupname=None): - """add host - - if groupname is none, create a new host - if group name is not none, add host to group - """ - if groupname and groupname not in self._groups: - raise NotInInventory(u._('Group'), groupname) - - if groupname and hostname not in self._hosts: - # if a groupname is specified, the host must already exist - raise NotInInventory(u._('Host'), hostname) - - if not groupname and not self.remote_mode and len(self._hosts) >= 1: - raise InvalidConfiguration( - u._('Cannot have more than one host when in local deploy ' - 'mode.')) - - changed = False - # create new host if it doesn't exist - host = Host(hostname) - if hostname not in self.get_hostnames(): - # a new host is being added to the inventory - changed = True - self._hosts[hostname] = host - - # a host is to be added to an existing group - elif groupname: - group = self._groups[groupname] - if hostname not in group.get_hostnames(): - changed = True - group.add_host(host) - return changed - - def remove_all_hosts(self): - """remove all hosts.""" - hostnamess = self.get_hostnames() - for hostname in hostnamess: - self.remove_host(hostname) - - def remove_host(self, hostname, groupname=None): - """remove host - - if groupname is none, delete host - if group name is not none, remove host from group - """ - changed = False - if groupname and groupname not in self._groups: - raise NotInInventory(u._('Group'), groupname) - - if hostname not in self._hosts: - return changed - - changed = True - host = self._hosts[hostname] - groups = self.get_groups(host) - for group in groups: - if not groupname or groupname == group.name: - group.remove_host(host) - - if not groupname: - host_vars = os.path.join(get_host_vars_dir(), hostname) - if os.path.exists(host_vars): - os.remove(host_vars) - del self._hosts[hostname] - return changed - - def setup_hosts(self, hosts_info): - """setup multiple hosts - - hosts_info is a dict of format: - {'hostname1': { - 'password': password - 'uname': user_name}} - - The uname entry is optional. - """ - failed_hosts = {} - for hostname, host_info in hosts_info.items(): - host = self.get_host(hostname) - if not host: - failed_hosts[hostname] = u._("Host doesn't exist.") - continue - if not host_info or 'password' not in host_info: - failed_hosts[hostname] = u._('No password in yml file.') - continue - passwd = host_info['password'] - - # NOTE(caoyuan): The type of password must be string, - # convert to string if the password is int. - if not isinstance(passwd, str): - passwd = str(passwd) - uname = None - if 'uname' in host_info: - uname = host_info['uname'] - try: - self.setup_host(hostname, passwd, uname) - except Exception as e: - failed_hosts[hostname] = '%s' % e - if failed_hosts: - summary = '\n' - for hostname, err in failed_hosts.items(): - summary = summary + '- %s: %s\n' % (hostname, err) - raise HostError( - u._('Not all hosts were set up. : {reasons}') - .format(reasons=summary)) - else: - LOG.info(u._LI('All hosts were successfully set up.')) - - def setup_host(self, hostname, password, uname=None): - try: - LOG.info( - u._LI('Starting setup of host ({host}).') - .format(host=hostname)) - check_ok, _ = self.ssh_check_host(hostname) - if check_ok: - LOG.info(u._LI('Host ({host}) is already setup.') - .format(host=hostname)) - else: - # host needs setup - ssh_setup_host(hostname, password, uname) - check_ok, msg = self.ssh_check_host(hostname) - if not check_ok: - raise Exception(u._('Post-setup ssh check failed. {err}') - .format(err=msg)) - LOG.info(u._LI('Host ({host}) setup succeeded.') - .format(host=hostname)) - except Exception as e: - raise HostError( - u._('Host ({host}) setup failed : {error}') - .format(host=hostname, error=str(e))) - return True - - def ssh_check_hosts(self, hostnames): - """ssh check for hosts - - return {hostname: {'success': True|False, - 'msg': message}} - """ - summary = {} - for hostname in hostnames: - is_ok, msg = self.ssh_check_host(hostname) - summary[hostname] = {} - summary[hostname]['success'] = is_ok - summary[hostname]['msg'] = msg - return summary - - def ssh_check_host(self, hostname): - err_msg, output = self.run_ansible_command('-m ping', hostname) - is_ok = True - if err_msg: - is_ok = False - msg = ( - u._('Host ({host}) ssh check failed. : {error} {message}') - .format(host=hostname, error=err_msg, message=output)) - else: - msg = (u._LI('Host ({host}) ssh check succeeded.') - .format(host=hostname)) - return is_ok, msg - - def run_ansible_command(self, ansible_command, hostname): - output = None - command_string = '%s -vvv' % \ - get_ansible_command() - gen_file_path = self.create_json_gen_file() - cmd = '%s %s -i %s %s' % (command_string, hostname, gen_file_path, - ansible_command) - try: - err_msg, output = run_cmd(cmd, False) - except Exception as e: - err_msg = str(e) - finally: - self.remove_json_gen_file(gen_file_path) - return err_msg, output - - def add_group(self, groupname): - - # Group names cannot overlap with service names: - if groupname in self._services: - raise InvalidArgument( - u._('Invalid group name. A service name ' - 'cannot be used for a group name.')) - - if groupname not in self._groups: - self._groups[groupname] = HostGroup(groupname) - - group = self._groups[groupname] - - group.set_remote(self.remote_mode) - - return group - - def remove_group(self, groupname): - if groupname in PROTECTED_GROUPS: - raise InvalidArgument( - u._('Cannot remove {group} group. It is required by kolla.') - .format(group=groupname)) - - # remove group from services - for service in self._services.values(): - service.remove_groupname(groupname) - - group_vars = os.path.join(get_group_vars_dir(), groupname) - if os.path.exists(group_vars) and groupname != '__GLOBAL__': - os.remove(group_vars) - - if groupname in self._groups: - del self._groups[groupname] - - def get_group(self, groupname): - group = None - if groupname in self._groups: - group = self._groups[groupname] - return group - - def get_groupnames(self): - return list(self._groups.keys()) - - def get_groups(self, host=None): - """return all groups containing host - - if hosts is none, return all groups in inventory - """ - groups = [] - if not host: - groups = self._groups.values() - - else: - for group in self._groups.values(): - if host.name in group.get_hostnames(): - groups.append(group) - return groups - - def get_host_groups(self): - """return { hostname : [groupnames] }""" - - host_groups = {} - for host in self._hosts.values(): - host_groups[host.name] = [] - groups = self.get_groups(host) - for group in groups: - host_groups[host.name].append(group.name) - return host_groups - - def get_group_services(self): - """get groups and their services - - return { groupname: [servicenames] } - """ - - group_services = {} - - for group in self.get_groups(): - group_services[group.name] = [] - - for svc in self.get_services(): - for groupname in svc.get_groupnames(): - group_services[groupname].append(svc.name) - return group_services - - def get_group_hosts(self): - """return { groupname : [hostnames] }""" - group_hosts = {} - for group in self.get_groups(): - group_hosts[group.name] = [] - for hostname in group.get_hostnames(): - group_hosts[group.name].append(hostname) - return group_hosts - - def create_service(self, servicename): - if servicename not in self._services: - service = Service(servicename) - self._services[servicename] = service - return self._services[servicename] - - def delete_service(self, servicename): - # remove references to this service from all parent / child services - if servicename in self._services: - service = self._services[servicename] - for parentname in service.get_parentnames(): - parent = self._services[parentname] - parent.remove_childname(servicename) - for childname in service.get_childnames(): - child = self._services[childname] - child.remove_parentname(servicename) - - # then remove the service itself - del self._services[servicename] - - def get_services(self, client_filter=False): - if client_filter: - services = self._client_filtered_service_dict() - else: - services = self._services - - return services.values() - - def get_service(self, servicename, client_filter=False): - service = None - if client_filter: - services = self._client_filtered_service_dict() - else: - services = self._services - - if servicename in services: - service = services[servicename] - return service - - def add_group_to_service(self, groupname, servicename): - if groupname not in self._groups: - raise NotInInventory(u._('Group'), groupname) - if servicename in self._services: - service = self.get_service(servicename) - service.add_groupname(groupname) - else: - raise NotInInventory(u._('Service'), servicename) - - def remove_group_from_service(self, groupname, servicename): - if groupname not in self._groups: - raise NotInInventory(u._('Group'), groupname) - if servicename in self._services: - service = self.get_service(servicename) - service.remove_groupname(groupname) - else: - raise NotInInventory(u._('Service'), servicename) - - def set_deploy_mode(self, remote_flag): - if not remote_flag and len(self._hosts) > 1: - raise InvalidConfiguration( - u._('Cannot set local deploy mode when multiple hosts exist.')) - self.remote_mode = remote_flag - - for group in self.get_groups(): - group.set_remote(remote_flag) - - def get_ansible_json(self, inventory_filter=None): - """generate json inventory for ansible - - The hosts and groups added to the json output for ansible will be - filtered by the hostnames and groupnames in the deploy filters. - This allows a more targeted deploy to a specific set of hosts or - groups. - - typical ansible json format: - {'group': { - 'hosts': ['192.168.28.71', '192.168.28.72'], - 'vars': { - - 'ansible_ssh_user': 'johndoe', - 'ansible_ssh_private_key_file': '~/.ssh/mykey', - 'example_variable': 'value'}, - - 'children': [ 'marietta', '5points' ]}, - - '_meta': { - 'hostvars': { - - '192.168.28.71': { - 'host_specific_var': 'bar'}, - - '192.168.28.72': { - 'host_specific_var': 'foo'}}}} - """ - - jdict = {} - - # if no filter provided, use all groups, all hosts - deploy_hostnames = self.get_hostnames() - deploy_groupnames = self.get_groupnames() - if inventory_filter: - if 'deploy_hosts' in inventory_filter: - deploy_hostnames = inventory_filter['deploy_hosts'] - if 'deploy_groups' in inventory_filter: - deploy_groupnames = inventory_filter['deploy_groups'] - - # add hostgroups - for group in self.get_groups(): - jdict[group.name] = {} - jdict[group.name]['hosts'] = [] - - if group.name in deploy_groupnames: - jdict[group.name]['hosts'] = \ - self._filter_hosts(group.get_hostnames(), deploy_hostnames) - jdict[group.name]['children'] = [] - jdict[group.name]['vars'] = group.get_vars() - - # add all services, what groups they are in and their parents - for service in self.get_services(): - jdict[service.name] = {} - groups_and_parents = [] - groups_and_parents.extend(service.get_groupnames()) - groups_and_parents.extend(service.get_parentnames()) - jdict[service.name]['children'] = groups_and_parents - - # temporarily create group containing all hosts. this is needed for - # ansible commands that are performed on hosts not yet in groups. - group = self.add_group('__GLOBAL__') - jdict[group.name] = {} - jdict[group.name]['hosts'] = deploy_hostnames - jdict[group.name]['vars'] = group.get_vars() - self.remove_group(group.name) - - # process hosts vars - jdict['_meta'] = {} - jdict['_meta']['hostvars'] = {} - for hostname in deploy_hostnames: - host = self.get_host(hostname) - if host: - jdict['_meta']['hostvars'][hostname] = host.get_vars() - return json.dumps(jdict) - - def _filter_hosts(self, initial_hostnames, deploy_hostnames): - """filter out hosts not in deploy hosts - - Must preserve the ordering of hosts in the group. - """ - filtered_hostnames = [] - for hostname in initial_hostnames: - if hostname in deploy_hostnames: - filtered_hostnames.append(hostname) - return filtered_hostnames - - def create_json_gen_file(self, inventory_filter=None): - """create json inventory file using filter ({}) - - The inventory will be placed in a directory in /tmp, - with the directory name of form kolla_uuid.py, - where uuid is a unique deployment id. - - return path to filtered json generator file - """ - json_out = self.get_ansible_json(inventory_filter) - - deploy_id = str(uuid.uuid4()) - dirname = 'kolla_%s' % deploy_id - dirpath = os.path.join(tempfile.gettempdir(), dirname) - os.mkdir(dirpath, 0o775) - _, gid = get_admin_uids() - json_gen_path = os.path.join(dirpath, 'temp_inventory.py') - - with open(json_gen_path, 'w') as json_gen_file: - json_gen_file.write('#!/usr/bin/env python\n') - # the quotes here are significant. The json_out has double quotes - # embedded in it so single quotes are needed to wrap it. - json_gen_file.write("print('%s')" % json_out) - - # set executable by group - os.chmod(json_gen_path, 0o555) # nosec - return json_gen_path - - def remove_json_gen_file(self, path): - remove_temp_inventory(path) - - def validate_hostnames(self, hostnames): - if not hostnames: - raise MissingArgument(u._('Host name(s)')) - invalid_hosts = [] - for hostname in hostnames: - if hostname not in self._hosts: - invalid_hosts.append(hostname) - if invalid_hosts: - raise NotInInventory(u._('Host'), invalid_hosts) - - def validate_groupnames(self, groupnames): - if not groupnames: - raise MissingArgument(u._('Group name(s)')) - invalid_groups = [] - for groupname in groupnames: - if groupname not in self._groups: - invalid_groups.append(groupname) - if invalid_groups: - raise NotInInventory(u._('Group'), invalid_groups) - - def validate_servicenames(self, servicenames, client_filter=False): - if not servicenames: - raise MissingArgument(u._('Service name(s)')) - invalid_services = [] - if client_filter: - services = self._client_filtered_service_dict() - else: - services = self._services - - for service_name in servicenames: - if service_name not in services: - invalid_services.append(service_name) - if invalid_services: - raise NotInInventory(u._('Service'), invalid_services) - - def _client_filtered_service_dict(self): - """Filters out any unsupported services - - :return: filtered dictionary - """ - filtered_service_dict = {} - for service in self._services.values(): - if service.is_supported(): - filtered_service_dict[service.name] = service - return filtered_service_dict - - def import_inventory(self, inventory_path): - ansible_inventory = AnsibleInventory(inventory_path) - for groupname in ansible_inventory.groups: - self.add_group(groupname) - for servicename, service in ansible_inventory.services.items(): - self._services[servicename] = service diff --git a/kolla_cli/common/passwords.py b/kolla_cli/common/passwords.py deleted file mode 100644 index d5a81ad..0000000 --- a/kolla_cli/common/passwords.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -from kolla_cli.api.exceptions import FailedOperation -from kolla_cli.common import utils -import kolla_cli.i18n as u - -PWDS_FILENAME = 'passwords.yml' - - -def set_password(pwd_key, pwd_value): - """set a password value - - If the password name exists, it will be changed. - If it doesn't exist, a new password will be added. - """ - value_switch = '-v' - if not pwd_value: - pwd_value = '' - value_switch = '' - cmd = '%s -k \'%s\' %s \'%s\'' % (_get_cmd_prefix(), pwd_key, value_switch, - pwd_value) - err_msg, output = utils.run_cmd(cmd, print_output=False) - if err_msg: - raise FailedOperation( - u._('Password set failed. {error} {message}') - .format(error=err_msg, message=output)) - - -def set_password_sshkey(pwd_key, private_key, public_key): - cmd = '%s -k \'%s\' -r \'%s\' -u \'%s\'' % (_get_cmd_prefix(), pwd_key, - private_key, public_key) - err_msg, output = utils.run_cmd(cmd, print_output=False) - if err_msg: - raise FailedOperation( - u._('Password ssh key set failed. {error} {message}') - .format(error=err_msg, message=output)) - - -def clear_password(pwd_key): - """clear a password - - if the password exists, it will be removed from the passwords file - """ - cmd = '%s -k \'%s\' -c' % (_get_cmd_prefix(), pwd_key) - err_msg, output = utils.run_cmd(cmd, print_output=False) - if err_msg: - raise FailedOperation('%s %s' % (err_msg, output)) - - -def get_password_names(): - """return a list of password names""" - cmd = '%s -l' % (_get_cmd_prefix()) - err_msg, output = utils.run_cmd(cmd, print_output=False) - if err_msg: - raise FailedOperation('%s %s' % (err_msg, output)) - - pwd_names = [] - if output and ',' in output: - pwd_names = output.strip().split(',') - return pwd_names - - -def get_empty_password_values(): - cmd = '%s -e' % (_get_cmd_prefix()) - err_msg, output = utils.run_cmd(cmd, print_output=False) - # output of this command is a comma separated string of password keys - # that have empty values. - if err_msg: - raise FailedOperation('%s %s' % (err_msg, output)) - - empty_keys = [] - if output: - # password keys exist that have no values - empty_keys = output.strip().split(',') - return empty_keys - - -def init_passwords(): - # init empty passwords & ssh keys to auto-gen'd values - cmd = '%s -i' % (_get_cmd_prefix()) - err_msg, output = utils.run_cmd(cmd, print_output=False) - if err_msg: - raise FailedOperation('%s %s' % (err_msg, output)) - - -def _get_cmd_prefix(): - actions_path = utils.get_kolla_actions_path() - pwd_file_path = os.path.join(utils.get_kolla_etc(), - PWDS_FILENAME) - prefix = ('%s password -p %s ' - % (actions_path, pwd_file_path)) - return prefix diff --git a/kolla_cli/common/properties.py b/kolla_cli/common/properties.py deleted file mode 100644 index 50e6664..0000000 --- a/kolla_cli/common/properties.py +++ /dev/null @@ -1,365 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import logging -import os -import yaml - -from kolla_cli.api.exceptions import NotInInventory -from kolla_cli.common.inventory import Inventory -from kolla_cli.common.utils import change_property -from kolla_cli.common.utils import get_group_vars_dir -from kolla_cli.common.utils import get_host_vars_dir -from kolla_cli.common.utils import get_kolla_ansible_home -from kolla_cli.common.utils import sync_read_file -import kolla_cli.i18n as u - -LOG = logging.getLogger(__name__) - -ALLVARS_PATH = 'ansible/group_vars/all.yml' -GLOBALS_PATH = 'ansible/group_vars/__GLOBAL__' -ANSIBLE_ROLES_PATH = 'ansible/roles' -ANSIBLE_DEFAULTS_PATH = 'defaults/main.yml' - - -class AnsibleProperties(object): - - def __init__(self): - """initialize ansible property information - - property information is pulled from the following files - (from lowest to highest priority): - KOLLA_HOME/ansible/roles//default/main.yml - KOLLA_HOME/ansible/group_vars/all.yml - KOLLA_HOME/ansible/group_vars/__GLOBAL__ - KOLLA_HOME/ansible/group_vars/* - KOLLA_HOME/ansible/host_vars/* - KOLLA_ETC/passwords.yml - """ - self.globals_path = os.path.join(get_kolla_ansible_home(), - GLOBALS_PATH) - self.global_props = [] - self.unique_global_props = {} - self.unique_override_flags = {} - self.group_props = {} - self.host_props = {} - self.properties_loaded = False - self._inventory = None - - def _load_properties(self): - self._load_inventory() - if not self.properties_loaded: - self._load_properties_roles() - self._load_properties_all() - self._load_properties_global() - self._load_properties_hostvars() - self._load_properties_groupvars() - self.properties_loaded = True - - def _load_properties_roles(self): - start_dir = os.path.join(get_kolla_ansible_home(), ANSIBLE_ROLES_PATH) - services = next(os.walk(start_dir))[1] - for service_name in services: - file_name = os.path.join(start_dir, service_name, - ANSIBLE_DEFAULTS_PATH) - if os.path.isfile(file_name): - with open(file_name) as service_file: - service_contents = yaml.safe_load(service_file) - prop_file_name = service_name + ':main.yml' - for key, value in service_contents.items(): - ansible_prop = AnsibleProperty(key, value, - prop_file_name) - self.global_props.append(ansible_prop) - self.unique_global_props[key] = ansible_prop - - def _load_properties_all(self): - allvars_path = os.path.join(get_kolla_ansible_home(), ALLVARS_PATH) - with open(allvars_path) as allvars_file: - allvars_contents = yaml.safe_load(allvars_file) - for key, value in allvars_contents.items(): - overrides = False - orig_value = None - if key in self.unique_global_props: - overrides = True - orig_value = self.unique_global_props[key].value - ansible_prop = AnsibleProperty(key, value, - 'group_vars/all.yml', - overrides, orig_value) - self.global_props.append(ansible_prop) - self.unique_global_props[key] = ansible_prop - - def _load_properties_global(self): - globals_data = sync_read_file(self.globals_path) - globals_contents = yaml.safe_load(globals_data) - if not globals_contents: - return - for key, value in globals_contents.items(): - overrides = False - override_flags = OverrideFlags() - orig_value = None - if key in self.unique_global_props: - overrides = True - override_flags.ovr_global = True - orig_value = self.unique_global_props[key].value - ansible_prop = AnsibleProperty(key, value, - 'group_vars/__GLOBAL__', - overrides, orig_value) - ansible_prop.override_flags = override_flags - self.global_props.append(ansible_prop) - self.unique_global_props[key] = ansible_prop - self.unique_override_flags[key] = override_flags - - def _load_properties_hostvars(self): - host_dir = get_host_vars_dir() - hostnames = self._inventory.get_hostnames() - for hostfile in os.listdir(host_dir): - if hostfile not in hostnames: - # skip any host files that don't match existing hosts - continue - self.host_props[hostfile] = [] - with open(os.path.join(host_dir, hostfile)) as host_data: - host_contents = yaml.safe_load(host_data) - if host_contents is None: - continue - props = [] - for key, value in host_contents.items(): - overrides = False - override_flags = OverrideFlags() - if key in self.unique_override_flags: - override_flags = self.unique_override_flags[key] - orig_value = None - if key in self.unique_global_props: - overrides = True - override_flags.ovr_host = True - self.unique_override_flags[key] = override_flags - orig_value = self.unique_global_props[key].value - ansible_prop = AnsibleProperty(key, value, - hostfile, - overrides, orig_value, - 'host', hostfile) - props.append(ansible_prop) - self.host_props[hostfile] = props - - def _load_properties_groupvars(self): - group_dir = get_group_vars_dir() - groupnames = self._inventory.get_groupnames() - for groupfile in os.listdir(group_dir): - if groupfile not in groupnames: - # skip any files that don't match existing groups - continue - with open(os.path.join(group_dir, groupfile)) as group_data: - group_contents = yaml.safe_load(group_data) - if group_contents is None: - continue - props = [] - for key, value in group_contents.items(): - overrides = False - override_flags = OverrideFlags() - if key in self.unique_override_flags: - override_flags = self.unique_override_flags[key] - orig_value = None - if key in self.unique_global_props: - overrides = True - override_flags.ovr_group = True - self.unique_override_flags[key] = override_flags - orig_value = self.unique_global_props[key].value - ansible_prop = AnsibleProperty(key, value, - groupfile, - overrides, orig_value, - 'group', groupfile) - props.append(ansible_prop) - self.group_props[groupfile] = props - - def _load_inventory(self): - if not self._inventory: - self._inventory = Inventory.load() # nosec - - def get_host_list(self, host_list): - self._load_properties() - prop_list = [] - if host_list is not None: - for host_name in host_list: - host = self._inventory.get_host(host_name) - if host is None: - raise NotInInventory(u._('Host'), host_name) - if host_name in self.host_props: - prop_list += self.host_props[host_name] - else: - hosts = self._inventory.get_hosts() - for host in hosts: - if host.name in self.host_props: - prop_list += self.host_props[host.name] - return prop_list - - def get_group_list(self, group_list): - self._load_properties() - prop_list = [] - if group_list is not None: - for group_name in group_list: - group = self._inventory.get_group(group_name) - if group is None: - raise NotInInventory(u._('Group'), group_name) - if group_name in self.group_props: - prop_list += self.group_props[group_name] - else: - groups = self._inventory.get_groups() - for group in groups: - if group.name in self.group_props: - prop_list += self.group_props[group.name] - return prop_list - - def get_property_value(self, property_name): - self._load_properties() - prop_val = None - if property_name in self.unique_global_props: - prop = self.unique_global_props[property_name] - prop_val = prop.value - return prop_val - - def get_property(self, property_name): - self._load_properties() - return self.unique_global_props.get(property_name) - - def get_all_unique(self): - self._load_properties() - unique_list = [] - for _, value in self.unique_global_props.items(): - unique_list.append(value) - return sorted(unique_list, key=lambda x: x.name) - - def get_all_override_flags(self): - self._load_properties() - return self.unique_override_flags - - def set_property(self, property_dict): - change_property(self.globals_path, property_dict, - clear=False) - - def set_host_property(self, property_dict, hosts): - # if hosts is None set the property on all hosts - self._load_inventory() - host_list = [] - if hosts is None: - host_list = self._inventory.get_hosts() - else: - for host_name in hosts: - host = self._inventory.get_host(host_name) - if host is None: - raise NotInInventory(u._('Host'), host_name) - host_list.append(host) - try: - for host in host_list: - file_path = os.path.join(get_host_vars_dir(), host.name) - change_property(file_path, property_dict, - clear=False) - except Exception as e: - raise e - - def set_group_property(self, property_dict, groups): - # if groups is None set the property on all hosts - self._load_inventory() - group_list = [] - if groups is None: - group_list = self._inventory.get_groups() - else: - for group_name in groups: - group = self._inventory.get_group(group_name) - if group is None: - raise NotInInventory(u._('Group'), group_name) - group_list.append(group) - try: - for group in group_list: - tmp_dict = copy.copy(property_dict) - file_path = os.path.join(get_group_vars_dir(), group.name) - change_property(file_path, tmp_dict, - clear=False) - except Exception as e: - raise e - - def clear_property(self, property_list): - try: - change_property(self.globals_path, - self._list_to_dict(property_list), - clear=True) - except Exception as e: - raise e - - def clear_host_property(self, property_list, hosts): - # if hosts is None set the property on all hosts - self._load_inventory() - host_list = [] - if hosts is None: - host_list = self._inventory.get_hosts() - else: - for host_name in hosts: - host = self._inventory.get_host(host_name) - if host is None: - raise NotInInventory(u._('Host'), host_name) - host_list.append(host) - try: - for host in host_list: - file_path = os.path.join(get_host_vars_dir(), host.name) - change_property(file_path, self._list_to_dict(property_list), - clear=True) - except Exception as e: - raise e - - def clear_group_property(self, property_list, groups): - # if hosts is None set the property on all hosts - self._load_inventory() - group_list = [] - if groups is None: - group_list = self._inventory.get_groups() - else: - for group_name in groups: - group = self._inventory.get_group(group_name) - if group is None: - raise NotInInventory(u._('Group'), group_name) - group_list.append(group) - try: - for group in group_list: - file_path = os.path.join(get_group_vars_dir(), group.name) - change_property(file_path, self._list_to_dict(property_list), - clear=True) - except Exception as e: - raise e - - def _list_to_dict(self, property_list): - property_dict = {} - for key in property_list: - property_dict[key] = '' - return property_dict - - -class AnsibleProperty(object): - - def __init__(self, name, value, file_name, overrides=False, - orig_value=None, prop_type='global', target=None): - self.name = name - self.value = value - self.prop_type = prop_type - self.file_name = file_name - self.overrides = overrides - self.orig_value = orig_value - self.target = target - self.value_type = type(value) - - -class OverrideFlags(object): - - def __init__(self): - self.ovr_global = False - self.ovr_group = False - self.ovr_host = False diff --git a/kolla_cli/common/service.py b/kolla_cli/common/service.py deleted file mode 100644 index 0d9097e..0000000 --- a/kolla_cli/common/service.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from copy import copy - - -class Service(object): - class_version = 1 - - def __init__(self, name): - self.name = name - self._parentnames = [] - self._childnames = [] - self._groupnames = [] - self._supported = True - self._vars = {} - self.version = self.__class__.class_version - - def upgrade(self): - pass - - def add_parentname(self, parentname): - if parentname is not None and parentname not in self._parentnames: - self._parentnames.append(parentname) - - def remove_parentname(self, parentname): - if parentname in self._parentnames: - self._parentnames.remove(parentname) - - def get_parentnames(self): - return copy(self._parentnames) - - def add_groupname(self, groupname): - if groupname is not None and groupname not in self._groupnames: - self._groupnames.append(groupname) - - def remove_groupname(self, groupname): - if groupname in self._groupnames: - self._groupnames.remove(groupname) - - def set_groupnames(self, groupnames): - self._groupnames = groupnames - - def get_groupnames(self): - return copy(self._groupnames) - - def get_childnames(self): - return copy(self._childnames) - - def add_childname(self, childname): - if childname not in self._childnames: - self._childnames.append(childname) - - def remove_childname(self, childname): - if childname in self._childnames: - self._childnames.remove(childname) - - def set_supported(self, supported): - self._supported = supported - - def is_supported(self): - return self._supported - - def get_vars(self): - return self._vars.copy() diff --git a/kolla_cli/common/sshutils.py b/kolla_cli/common/sshutils.py deleted file mode 100644 index 3ac71ff..0000000 --- a/kolla_cli/common/sshutils.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging -import os.path -import paramiko -import traceback - -from kolla_cli.common.utils import get_admin_user -from kolla_cli.common.utils import get_kolla_cli_etc -from kolla_cli.common.utils import get_setup_user -import kolla_cli.i18n as u - -MIN_DOCKER_VERSION = '1.10.0' - -LOG = logging.getLogger(__name__) - - -def ssh_connect(net_addr, username, password): - try: - ssh_client = paramiko.SSHClient() - ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh_client.connect(hostname=net_addr, username=username, - password=password) - return ssh_client - except Exception: - _close_ssh_client(ssh_client) - raise Exception(traceback.format_exc()) - - -def ssh_setup_host(net_addr, password, setup_user=None): - admin_user = get_admin_user() - if setup_user is None: - setup_user = get_setup_user() - public_key = ssh_get_public_key() - ssh_client = None - - try: - ssh_client = ssh_connect(net_addr, setup_user, password) - # populate authorized keys file w/ public key - key_dir = os.path.join(os.path.expanduser('~%s' % admin_user), - '.ssh', 'authorized_keys') - cmd = ('/usr/bin/sudo su - %s -c "echo \'%s\' >> %s"' - % (admin_user, public_key, key_dir)) - _exec_ssh_cmd(cmd, ssh_client) - except Exception as e: - raise e - finally: - _close_ssh_client(ssh_client) - - -def _close_ssh_client(ssh_client): - if ssh_client: - try: - ssh_client.close() - except Exception: # nosec - pass - - -def _exec_ssh_cmd(cmd, ssh_client): - LOG.debug(cmd) - _, stdout, stderr = ssh_client.exec_command(cmd, get_pty=True) # nosec - msg = stdout.read() - errmsg = stderr.read() - LOG.debug('%s : %s' % (msg, errmsg)) - if errmsg: - LOG.warn( - u._LW('WARNING: command : {command})\nmessage : {message}') - .format(command=cmd, message=errmsg.strip())) - return msg, errmsg - - -def ssh_get_public_key(): - keyfile_path = os.path.join(get_kolla_cli_etc(), 'id_rsa.pub') - with open(keyfile_path, "r") as public_key_file: - public_key = public_key_file.read() - return public_key diff --git a/kolla_cli/common/subservice.py b/kolla_cli/common/subservice.py deleted file mode 100644 index 14443ce..0000000 --- a/kolla_cli/common/subservice.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from copy import copy - - -class SubService(object): - class_version = 1 - - def __init__(self, name): - self.name = name - - self._groupnames = [] - self._parent_servicename = None - - self._vars = {} - self.version = self.__class__.class_version - - def upgrade(self): - pass - - def add_groupname(self, groupname): - if groupname is not None and groupname not in self._groupnames: - self._groupnames.append(groupname) - - def remove_groupname(self, groupname): - if groupname in self._groupnames: - self._groupnames.remove(groupname) - - def get_groupnames(self): - return copy(self._groupnames) - - def set_parent_servicename(self, parent_svc_name): - self._parent_servicename = parent_svc_name - - def get_parent_servicename(self): - return copy(self._parent_servicename) - - def get_vars(self): - return self.vars.copy() diff --git a/kolla_cli/common/support.py b/kolla_cli/common/support.py deleted file mode 100644 index d44e5a3..0000000 --- a/kolla_cli/common/support.py +++ /dev/null @@ -1,222 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import logging -import os -import tarfile -import tempfile - -from kolla_cli.api.exceptions import FailedOperation -from kolla_cli.common.inventory import Inventory -from kolla_cli.common.properties import AnsibleProperties -from kolla_cli.common.utils import get_kolla_ansible_home -from kolla_cli.common.utils import get_kolla_cli_etc -from kolla_cli.common.utils import run_cmd - -LOG = logging.getLogger(__name__) - - -class HostLogs(object): - - def __init__(self, hostname, inventory, servicenames): - self.hostname = hostname - self.inventory = inventory - self.servicenames = servicenames - self.container_info = {} # container_id: container_img_name - self.filtered_servicenames = {} - - def load_container_info(self): - """get the list of containers on the host""" - hostname = self.hostname - err_msg, output = \ - self.inventory.run_ansible_command('-a "docker ps -a"', hostname) - if err_msg: - msg = 'Error accessing host %s : %s %s' % (hostname, err_msg, - output) - raise FailedOperation(msg) - - if not output: - msg = ('Host %s is not accessible.' % hostname) - raise FailedOperation(msg) - else: - if '>>' not in output: - msg = ('Host: %s. Invalid ansible return data: [%s].' - % (hostname, output)) - raise FailedOperation(msg) - - if 'NAMES' not in output: - msg = ('Host: %s. Invalid docker ps return data: [%s].' - % (hostname, output)) - raise FailedOperation(msg) - - ansible_properties = AnsibleProperties() - base_distro = \ - ansible_properties.get_property_value('kolla_base_distro') - install_type = \ - ansible_properties.get_property_value('kolla_install_type') - # typically this prefix will be "ol-openstack-" - container_prefix = base_distro + '-' + install_type + '-' - - # process ps output - containers = {} - - # the ps output is after the '>>' - output = output.split('>>', 1)[1] - LOG.info('docker ps -a on host: %s:\n%s' % (hostname, output)) - - lines = output.split('\n') - for line in lines: - tokens = line.split() - if len(tokens) < 2: - continue - cid = tokens[0] - image = tokens[1] - if container_prefix not in image: - # skip non-kolla containers - continue - name = image.split(container_prefix)[1] - name = name.split(':')[0] - containers[cid] = name - self.container_info = containers - - def get_log(self, container_id): - """read the container log""" - hostname = self.hostname - cmd = '-a "docker logs %s"' % container_id - err_msg, output = self.inventory.run_ansible_command(cmd, hostname) - if err_msg: - msg = 'Error accessing host %s : %s ' % (hostname, err_msg) - raise FailedOperation(msg) - - if not output: - msg = ('Host %s is not accessible.' % hostname) - raise FailedOperation(msg) - if '>>' not in output: - msg = ('Host: %s. Invalid ansible return data: [%s].' - % (hostname, output)) - raise FailedOperation(msg) - - # the log info is after the '>>' - output = output.split('>>', 1)[1] - return output - - def write_logs(self, dirname): - """write out the log files for all containers""" - for container_id, container_name in self.filtered_services.items(): - logdata = self.get_log(container_id) - if logdata: - logname = '%s_%s.log' % (container_name, container_id) - self.write_logfile(dirname, logname, logdata) - else: - LOG.warn('No log data found for service %s on host %s' - % (container_name, self.hostname)) - - def write_logfile(self, dirpath, logname, logdata): - """write out one log file""" - hostdir = os.path.join(dirpath, self.hostname) - if not os.path.exists(hostdir): - os.mkdir(hostdir) - fpath = os.path.join(hostdir, logname) - with open(fpath, 'w') as logfile: - logfile.write(logdata) - - def filter_services(self): - """filter services to only those of interest""" - services_subset = {} - for host_svcid, host_svcname in self.container_info.items(): - for servicename in self.servicenames: - if (host_svcname == servicename or - host_svcname.startswith(servicename + '-')): - services_subset[host_svcid] = host_svcname - self.filtered_services = services_subset - - -def get_logs(servicenames, hostname, dirname): - inventory = Inventory.load() - inventory.validate_hostnames([hostname]) - inventory.validate_servicenames(servicenames, client_filter=True) - - logs = HostLogs(hostname, inventory, servicenames) - logs.load_container_info() - logs.filter_services() - logs.write_logs(dirname) - - -def dump(dirpath): - """Dumps configuration data for debugging - - Dumps most files in /etc/kolla and /usr/share/kolla into a - tar file so be given to support / development to help with - debugging problems. - """ - kolla_home = get_kolla_ansible_home() - kolla_ansible = os.path.join(kolla_home, 'ansible') - kollacli_etc = get_kolla_cli_etc().rstrip('/') - ketc = 'kolla/etc/' - kshare = 'kolla/share/' - fd, dump_path = tempfile.mkstemp(dir=dirpath, prefix='kollacli_dump_', - suffix='.tgz') - os.close(fd) # avoid fd leak - with tarfile.open(dump_path, 'w:gz') as tar: - # Can't blanket add kolla_home because the .ssh dir is - # accessible by the kolla user only (not kolla group) - tar.add(kolla_ansible, - arcname=kshare + os.path.basename(kolla_ansible)) - - # Can't blanket add kolla_etc because the passwords.yml - # file is accessible by the kolla user only (not kolla group) - tar.add(kollacli_etc, - arcname=ketc + os.path.basename(kollacli_etc)) - - # add output of various commands - _add_cmd_info(tar) - - return dump_path - - -def _add_cmd_info(tar): - # run all the kollacli list commands - cmds = ['kolla-cli --version', - 'kolla-cli service listgroups', - 'kolla-cli service list', - 'kolla-cli group listservices', - 'kolla-cli group listhosts', - 'kolla-cli host list', - 'kolla-cli property list', - 'kolla-cli password list'] - - # collect the json inventory output - inventory = Inventory.load() - inv_path = inventory.create_json_gen_file() - cmds.append(inv_path) - - try: - fd, path = tempfile.mkstemp(suffix='.tmp') - os.close(fd) - with open(path, 'w') as tmp_file: - for cmd in cmds: - err_msg, output = run_cmd(cmd, False) - tmp_file.write('\n\n$ %s\n' % cmd) - if err_msg: - tmp_file.write('Error message: %s\n' % err_msg) - for line in output.split('\n'): - tmp_file.write(line + '\n') - - tar.add(path, arcname=os.path.join('kolla', 'cmds_output')) - except Exception as e: - raise e - finally: - if path: - os.remove(path) - inventory.remove_json_gen_file(inv_path) - return diff --git a/kolla_cli/common/utils.py b/kolla_cli/common/utils.py deleted file mode 100644 index 8b739ee..0000000 --- a/kolla_cli/common/utils.py +++ /dev/null @@ -1,665 +0,0 @@ -# Copyright(c) 2017, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import fcntl -import grp -import logging -import os -import pwd -import subprocess # nosec -import time -import yaml - -from kolla_cli.api.exceptions import InvalidArgument -from kolla_cli.api.exceptions import MissingArgument -from kolla_cli.commands.exceptions import CommandError -import kolla_cli.i18n as u - -LOG = logging.getLogger(__name__) - -private_key_string = 'private_key' -public_key_string = 'public_key' - - -def get_log_level(): - evar = os.environ.get('KOLLA_LOG_LEVEL', 'info') - if evar.lower() == 'debug': - level = logging.DEBUG - else: - level = logging.INFO - return level - - -def get_kolla_ansible_home(): - return os.environ.get("KOLLA_HOME", "/usr/share/kolla-ansible/") - - -def get_kolla_etc(): - return os.environ.get('KOLLA_ETC', '/etc/kolla/') - - -def get_kolla_cli_home(): - return os.path.join(get_kolla_ansible_home(), 'kolla-cli') - - -def get_kolla_cli_etc(): - return os.path.join(get_kolla_etc(), 'kolla-cli') - - -def get_group_vars_dir(): - return os.path.join(get_kolla_ansible_home(), 'ansible/group_vars') - - -def get_host_vars_dir(): - return os.path.join(get_kolla_ansible_home(), 'ansible/host_vars') - - -def get_tools_path(): - return os.environ.get( - 'KOLLA_TOOLS_DIR', os.path.join(get_kolla_cli_home(), 'tools')) - - -def get_kolla_actions_path(): - return os.path.join(get_tools_path(), 'kolla_actions.py') - - -def get_admin_uids(): - """get uid and gid of admin user""" - user_info = pwd.getpwnam(get_admin_user()) - uid = user_info.pw_uid - gid = user_info.pw_gid - return uid, gid - - -def get_property_list_length(): - envvar = 'KOLLA_PROP_LIST_LENGTH' - length_str = os.environ.get(envvar, '50') - try: - length = int(length_str) - except Exception: - raise InvalidArgument( - u._('Environmental variable ({env_var}) is not an ' - 'integer ({prop_length}).') - .format(env_var=envvar, prop_length=length_str)) - return length - - -def get_admin_user(): - return os.environ.get("KOLLA_CLI_ADMIN_USER", "root") - - -def get_setup_user(): - return os.environ.get("KOLLA_CLI_SETUP_USER", "root") - - -def get_lock_enabled(): - evar = os.environ.get('KOLLA_CLI_LOCK', 'true') - if evar.lower() == 'false': - return False - else: - return True - - -def get_ansible_command(playbook=False): - """Get the ansible command""" - cmd = 'ansible' - if playbook: - cmd = 'ansible-playbook' - return cmd - - -def run_cmd(cmd, print_output=True): - """run a system command - - return: - err_msg: - empty string=command succeeded not None=command failed - output: - string: all the output of the run command - """ - output = None - try: - process = subprocess.Popen(cmd, shell=True, # nosec - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - output, err = process.communicate() - except Exception as e: - err = str(e) - - err = safe_decode(err) - output = safe_decode(output) - if process is not None and process.returncode != 0: - err = (u._('Command failed. : {error}') - .format(error=err)) - if print_output: - LOG.info(output) - return err, output - - -def change_password(file_path, pname, pvalue=None, public_key=None, - private_key=None, clear=False): - """change password in passwords.yml file - - file_path: path to passwords file - pname: name of password - pvalue: value of password when not ssh key - public_key: public ssh key - private_key: private ssh key - clear: flag to clear password - - If key is not found, an error is returned. - If clear, and password exists, remove password. - If clear, and password is already empty, nothing is done. - If not clear, edit password in place. - - The passwords file contains both key-value pairs and key-dictionary - pairs. Type is maintained so you cannot change a key-dictionary - password to a key-value password or the other way around. - """ - read_data = sync_read_file(file_path) - file_pwds = yaml.safe_load(read_data) - # if the password file is empty file_pwds will be None after safe_load - if file_pwds is None: - file_pwds = {} - - if pname not in file_pwds.keys(): - raise Exception( - u._('unable to update password as it does not exist: {pname}') - .format(pname=pname)) - - ssh_password_type = is_ssh_password(file_pwds[pname]) - - if clear: - # clear - if pname in file_pwds: - if ssh_password_type: - file_pwds[pname] = {private_key_string: None, - public_key_string: None} - else: - file_pwds[pname] = None - else: - # edit - if private_key: - if not ssh_password_type: - raise Exception( - u._('unable to set non ssh type password to ssh value')) - file_pwds[pname] = {private_key_string: private_key, - public_key_string: public_key} - else: - if ssh_password_type: - raise Exception( - u._('unable to set ssh password type to non ssh value')) - if not pvalue: - pvalue = None - file_pwds[pname] = pvalue - - # dump Nones as empty strings instead of the value 'null' as this is how - # it looks when we read it. also, this will not work with safe_dump - yaml.add_representer(type(None), _empty_is_none) - write_data = yaml.dump(file_pwds, default_flow_style=False) - sync_write_file(file_path, write_data) - - -def clear_all_passwords(): - """clear all passwords in passwords.yml file""" - password_path = os.path.join(get_kolla_etc(), 'passwords.yml') - read_data = sync_read_file(password_path) - file_pwds = yaml.safe_load(read_data) - # if the password file is empty file_pwds will be None after safe_load - if file_pwds is None: - file_pwds = {} - - keys = file_pwds.keys() - for key in keys: - if is_ssh_password(file_pwds[key]): - file_pwds[key] = {private_key_string: None, - public_key_string: None} - else: - file_pwds[key] = None - - yaml.add_representer(type(None), _empty_is_none) - write_data = yaml.dump(file_pwds, default_flow_style=False) - sync_write_file(password_path, write_data) - - -def _empty_is_none(self, _): - return self.represent_scalar('tag:yaml.org,2002:null', '') - - -def is_ssh_password(password): - if password is not None: - if isinstance(password, dict): - password_keys = password.keys() - if (private_key_string in password_keys and - public_key_string in password_keys): - return True - return False - - -def change_property(file_path, property_dict, clear=False): - """change property with a file - - file_path: path to property file - property_dict: dictionary of property names and values - clear: flag to remove property - - If clear, and property exists, remove it from the property file. - If clear, and property doesn't exists, nothing is done. - If not clear, and key is not found, the new property will be appended. - If not clear, and key is found, edit property in place. - """ - cloned_dict = copy.copy(property_dict) - if not os.path.exists(file_path): - with open(file_path, 'a'): - os.utime(file_path, None) - try: - group_info = grp.getgrnam('kolla') - os.chown(file_path, -1, group_info.gr_gid) - except KeyError: - # ignore error if kolla user not present, needed - # for functional test - LOG.debug('Ignoring error- kolla user not defined') - - new_contents = [] - read_data = sync_read_file(file_path) - lines = read_data.split('\n') - last_line_empty = False - for line in lines: - line = line.rstrip() - - # yank spurious empty lines - if line: - last_line_empty = False - else: - if last_line_empty: - continue - last_line_empty = True - - split_line = line.split(':', 1) - if len(split_line) > 1: - split_key = split_line[0] - split_key.rstrip() - if split_key in cloned_dict: - if clear: - # clear existing property - continue - # edit existing property - value = cloned_dict[split_key] - line = _get_property_line(split_key, value) - - # clear out the key after we are done, all existing keys - # will be appended at the end (or for clear, ignored) - del cloned_dict[split_key] - new_contents.append(line) - if not clear: - # add new properties to file - for key, value in cloned_dict.items(): - line = _get_property_line(key, value) - - # when we are doing an append we want to avoid - # blank lines before the new entry - if new_contents[-1:][0] == '': - del new_contents[-1] - new_contents.append(line) - - # if the last line is blank, trim it off - if new_contents[-1:][0] == '': - del new_contents[-1] - write_data = '\n'.join(new_contents) + '\n' - sync_write_file(file_path, write_data) - - -def _get_property_line(key, value): - if type(value) is str: - line = '%s: "%s"' % (key, value) - else: - str_value = yaml.safe_dump(value).strip() - value_type = type(value) - if value_type is bool or value_type is int: - # yaml dump adds a newline and an ellipsis after - # a boolean or int value. This needs to be stripped. - str_value = str_value.replace('\n...', '') - line = '%s: %s' % (key, str_value) - return line - - -def sync_read_file(path, mode='r'): - """synchronously read file - - return file data - """ - lock = None - try: - if get_lock_enabled(): - lock = Lock(path, 'sync_read') - locked = lock.wait_acquire() - if not locked: - raise Exception( - u._('unable to read file {path} ' - 'as it was locked.') - .format(path=path)) - with open(path, mode) as data_file: - data = data_file.read() - finally: - if lock: - lock.release() - return safe_decode(data) - - -def sync_write_file(path, data, mode='w'): - """synchronously write file""" - ansible_lock = None - lock = None - try: - if get_lock_enabled(): - ansible_lock = Lock(owner='sync_write') - locked = ansible_lock.wait_acquire() - if not locked: - raise Exception( - u._('unable to get ansible lock while writing to {path} ' - 'as it was locked.') - .format(path=path)) - - lock = Lock(lockpath=path, owner='sync_write') - locked = lock.wait_acquire() - if not locked: - raise Exception( - u._('unable to write file {path} ' - 'as it was locked.') - .format(path=path)) - with open(path, mode) as data_file: - data_file.write(data) - finally: - if ansible_lock: - ansible_lock.release() - if lock: - lock.release() - - -def safe_decode(obj_to_decode): - """Convert bytes or strings to unicode string - - Converts strings, lists, or dictionaries to - unicode. - """ - if obj_to_decode is None: - return None - - if isinstance(obj_to_decode, list): - new_obj = [] - for text in obj_to_decode: - text = safe_decode(text) - new_obj.append(text) - elif isinstance(obj_to_decode, dict): - new_obj = {} - for key, value in obj_to_decode.items(): - key = safe_decode(key) - value = safe_decode(value) - new_obj[key] = value - else: - new_obj = obj_to_decode - if not isinstance(obj_to_decode, str): - # object is not unicode - new_obj = obj_to_decode.decode('utf-8') - return new_obj - - -def is_string_true(string): - """Return boolean True if string represents a true value (None is False)""" - true_values = ['yes', 'true'] - if string is not None and string.lower() in true_values: - return True - else: - return False - - -def convert_lists_to_string(tuples, parsed_args): - """convert lists to strings - - Because of the way cliff processes strings for tables, if a list - has non-ascii chars in it, they would display as unicode bytes - (\u0414\u0435\u043a\u0430\u0442). By converting - the list to string here, the proper non-ascii chars are displayed. - - This will only change the lists when the output is to a user visible - medium. It cannot be changed if the display output is json, yaml, etc. - """ - convert_types = ['table', 'csv', 'html', 'value'] - if parsed_args.formatter and parsed_args.formatter not in convert_types: - # not table output, leave it as-is - return tuples - - new_tuples = [] - for data_tuple in tuples: - new_items = [] - items = list(data_tuple) - for item in items: - if isinstance(item, list): - item = convert_list_to_string(item) - new_items.append(item) - data_tuple = tuple(new_items) - new_tuples.append(data_tuple) - return new_tuples - - -def convert_list_to_string(alist): - return '[' + ','.join(alist) + ']' - - -def check_arg(param, param_name, expected_type, none_ok=False, empty_ok=False, - display_param=True): - if param is None: - if none_ok: - return - # None arg - raise MissingArgument(param_name) - - if ((isinstance(param, str) or - isinstance(param, dict) or - isinstance(param, list)) and - not param and not empty_ok): - # empty string, dict or list - raise MissingArgument(param_name) - - # if expected type is None, skip the type checking - if expected_type is None: - return - - if not isinstance(param, expected_type): - # wrong type - if display_param: - raise InvalidArgument(u._('{name} ({param}) is not a {type}') - .format(name=param_name, param=param, - type=expected_type)) - else: - raise InvalidArgument(u._('{name} is not a {type}') - .format(name=param_name, - type=expected_type)) - - -def disallow_chars(param, param_name, chars): - if param is None: - return - - for char in chars: - if char in param: - raise InvalidArgument( - u._('{name} contains invalid character {chars}') - .format(name=param_name, chars=chars)) - - -def handers_action_result(job, status, verbose_level): - if verbose_level > 2: - LOG.info('\n\n' + 80 * '=') - LOG.info(u._('DEBUG command output:\n{out}') - .format(out=job.get_console_output())) - if status == 0: - if verbose_level > 1: - # log any ansible warnings - msg = job.get_error_message() - if msg: - LOG.warn(msg) - LOG.info(u._('Success')) - else: - raise CommandError(u._('Job failed:\n{msg}') - .format(msg=job.get_error_message())) - - -class Lock(object): - """Object which represents an exclusive resource lock - - flock usage is the default behavior but a separate pidfile mechanism - is also available. flock doesn't have the same orphaned lock issue - that pidfile usage does. both need to be tests on NFS. if flock - works then it seems better / less complicated for our needs. - """ - - def __init__(self, lockpath=None, owner='unknown owner', use_flock=True): - self.lockpath = lockpath or self.get_lockpath() - self.pid = str(os.getpid()) - self.fd = None - self.owner = owner - self.current_pid = -1 - self.current_owner = '' - self.use_flock = use_flock - - def get_lockpath(self): - return os.path.join(get_kolla_cli_home(), 'ansible.lock') - - def acquire(self): - try: - if self.use_flock: - return self._acquire_flock() - else: - return self._acquire_pidfile() - except IOError as e: - # IOError is the error you get when the file is - # already locked. (No such file returns an OSError.) - # This may be OK and is handled by the caller. - LOG.debug('Exception in acquiring lock. ' - 'path: %s pid: %s owner: %s error: %s' % - (self.lockpath, self.pid, self.owner, str(e))) - return False - except Exception as e: - raise e - - def _acquire_pidfile(self): - if not self.is_owned_by_me(): - fd = os.open(self.lockpath, os.O_CREAT | os.O_EXCL | os.O_RDWR) - with os.fdopen(fd, 'a') as f: - f.write(self.pid + '\n' + self.owner) - return self.is_owned_by_me() - - def _acquire_flock(self): - self.fd = os.open(self.lockpath, os.O_RDWR) - fcntl.flock(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB) - return True - - def wait_acquire(self, wait_duration=3, interval=0.1): - wait_time = 0 - while (wait_time < wait_duration): - if not self.acquire(): - time.sleep(interval) - wait_time += interval - else: - return True - return False - - def is_owned_by_me(self): - """Returns True if we own the lock or False otherwise""" - try: - if self.use_flock: - raise Exception(u._('Invalid use of is_owned_by_me while' - 'using flock')) - - if not os.path.exists(self.lockpath): - # lock doesn't exist, just return - return False - fd = os.open(self.lockpath, os.O_RDONLY) - with os.fdopen(fd, 'r') as f: - contents = f.read(2048).strip().split('\n') - if len(contents) > 0: - self.current_pid = contents[0] - if len(contents) > 1: - self.current_owner = contents[1] - - if contents[0] == str(self.pid): - return True - else: - return False - except Exception as e: - # it is ok to fail to acquire, we just return that we failed - LOG.debug('Exception in is_owned_by_me lock check. ' - 'path: %s pid: %s owner: %s error: %s' % - (self.lockpath, self.pid, self.owner, str(e))) - return False - - def release(self): - try: - if self.use_flock: - self._release_flock() - else: - self._release_pidfile() - except OSError: - # ignore release of an already released lock - pass - except Exception: - # this really shouldn't happen unless for some reason - # two areas in the same process try to release the lock - # at the same time and if that happens you want to see - # an error about it - LOG.error('Error releasing lock', exc_info=True) - return False - - def _release_pidfile(self): - if self.is_owned_by_me(): - os.remove(self.lockpath) - return True - - def _release_flock(self): - try: - fcntl.flock(self.fd, fcntl.LOCK_UN) - except Exception as e: - LOG.debug('Exception while releasing lock: %s' % str(e)) - finally: - os.close(self.fd) - return True - - -class PidManager(object): - @staticmethod - def get_child_pids(pid, child_pids=[]): - """get child pids of parent pid""" - # This ps command will return child pids of parent pid, separated by - # newlines. - err_msg, output = run_cmd('ps --ppid %s -o pid=""' % pid, - print_output=False) - - # err_msg is expected when pid has no children - if not err_msg: - output = output.strip() - - if '\n' in output: - ps_pids = output.split('\n') - else: - ps_pids = [output] - - if ps_pids: - child_pids.extend(ps_pids) - - # recurse through children to get all child pids - for ps_pid in ps_pids: - PidManager.get_child_pids(ps_pid, child_pids) - return child_pids diff --git a/kolla_cli/i18n.py b/kolla_cli/i18n.py deleted file mode 100644 index a1fa211..0000000 --- a/kolla_cli/i18n.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2012-2013 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -import oslo_i18n - -_translators = oslo_i18n.TranslatorFactory(domain='kolla-cli') - -# The primary translation function using the well-known name "_" -_ = _translators.primary - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical diff --git a/kolla_cli/shell.py b/kolla_cli/shell.py deleted file mode 100755 index fda7ff1..0000000 --- a/kolla_cli/shell.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""Command-line interface to Kolla""" -import logging -import os -import sys - -from cliff.app import App -from cliff.commandmanager import CommandManager - -import kolla_cli.i18n as u - -from kolla_cli.api.client import ClientApi -from kolla_cli.commands.exceptions import CommandError -from kolla_cli.common.inventory import INVENTORY_PATH -from kolla_cli.common.utils import get_kolla_cli_etc - -LOG = logging.getLogger(__name__) - -VERSION = '4.0' - - -class KollaCli(App): - def __init__(self): - super(KollaCli, self).__init__( - description=u._('Command-Line Client for OpenStack Kolla'), - version=VERSION, - command_manager=CommandManager('kolla.cli'), - ) - - inventory_path = os.path.join(get_kolla_cli_etc(), - INVENTORY_PATH) - if not self._is_inventory_present(inventory_path): - err_string = u._( - 'Required file ({inventory}) does not exist.\n' - 'Please re-install the kollacli to ' - 'recreate the file.').format(inventory=inventory_path) - raise CommandError(err_string) - - # set up logging and test that user running shell is part - # of kolla group - ClientApi() - - # paramiko log is very chatty, tune it down - logging.getLogger('paramiko').setLevel(logging.WARNING) - - self.dump_stack_trace = False - - def _is_inventory_present(self, inventory_path): - return os.path.isfile(inventory_path) - - -def main(argv=sys.argv[1:]): - shell = KollaCli() - return shell.run(argv) - - -if __name__ == "__main__": - sys.exit(main(sys.argv[1:])) diff --git a/kolla_cli/tests/__init__.py b/kolla_cli/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kolla_cli/tests/functional/README.txt b/kolla_cli/tests/functional/README.txt deleted file mode 100644 index f8a23d9..0000000 --- a/kolla_cli/tests/functional/README.txt +++ /dev/null @@ -1,19 +0,0 @@ -- As of change id: Id11cc1abcac6ac5b94176a1f17a8f5f82b6f00d5 -removed all tests which expected remote systems -to be available / configured. These tests should be -revived at some point using Tempest or something similar to run -more complete functional tests. - -- To run a single functional test, you will need to setup these -environmental variables and the needed file structure: - -export KOLLA_ETC=/tmp/kollaclitest/etc/kolla/ -export KOLLA_HOME=/tmp/kollaclitest/usr/share/kolla-ansible/ -export KOLLA_TOOLS_DIR=./tools/ - -./kolla_cli/tests/functional/functional_test_setup.sh - -Then you can run a single test, for eg: - -source .tox/functional/bin/activate -stestr run -n kolla_cli.tests.functional.test_deploy.TestFunctional.test_deploy diff --git a/kolla_cli/tests/functional/__init__.py b/kolla_cli/tests/functional/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kolla_cli/tests/functional/common.py b/kolla_cli/tests/functional/common.py deleted file mode 100644 index 954dac4..0000000 --- a/kolla_cli/tests/functional/common.py +++ /dev/null @@ -1,207 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -import logging -import os -import shutil -import subprocess -import sys -import testtools - -import kolla_cli.common.utils as utils - -from copy import copy -from shutil import copyfile - -from kolla_cli.api.client import ClientApi -from kolla_cli.api.exceptions import InvalidArgument - -CLIENT = ClientApi() -CLIENT.enable_console_logging(logging.DEBUG) - -ARG_LIST = { - bool: False, - list: [1, 2, 3], - str: 'qwerty', - dict: {'a': 1}, - int: 0, - } - -KOLLACLI_CMD_PATH = 'kolla_cli/shell.py' - - -class KollaCliTest(testtools.TestCase): - - saved_kolla_etc = '' - log = logging.getLogger(__name__) - - def setUp(self): - super(KollaCliTest, self).setUp() - - logging.basicConfig(stream=sys.stderr) - self.log.setLevel(logging.DEBUG) - self.log.info('\nStarting test: %s ***********************************' - % self._testMethodName) - - # switch to test path - etc_path = utils.get_kolla_cli_etc() - self.log.debug('etc for tests: %s' % etc_path) - - self._save_config() - - def tearDown(self): - super(KollaCliTest, self).tearDown() - self._restore_config() - - def run_cli_cmd(self, cmd, expect_error=False): - full_cmd = ('python %s %s' % (KOLLACLI_CMD_PATH, cmd)) - self.log.debug('running command: %s' % cmd) - (retval, msg) = self.run_command(full_cmd) - - if not expect_error: - self.assertEqual(0, retval, ('command failed: (%s), cmd: %s' - % (msg, full_cmd))) - return msg - - def run_command(self, cmd): - """run bash command - - return (retval, msg) - """ - # self.log.debug('run cmd: %s' % cmd) - msg = '' - process = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True) - (out, err) = process.communicate() - retval = process.returncode - - # the py dev debugger adds a string at the line start, remove it - if err: - msg = utils.safe_decode(err) - if out: - msg = msg + '\n' + utils.safe_decode(out) - if msg.startswith('pydev debugger'): - msg = msg.split('\n', 1)[1] - return (retval, msg) - - def check_types(self, method, expected_types): - # expected type is a list: - args = [] - for arg_type in expected_types: - args.append((arg_type, ARG_LIST[arg_type])) - for i in range(0, len(args)): - arg_type, _ = args[i] - for new_arg in ARG_LIST.values(): - new_args = copy(args) - if isinstance(new_arg, arg_type): - # this new type is the correct arg type, skip - continue - # substitute a valid type for an invalid one - new_args[i] = new_arg - self._check_invalid_arg(method, new_args) - - def _check_invalid_arg(self, method, args): - assert(len(args) <= 5) - try: - if len(args) == 1: - method(args[0]) - elif len(args) == 2: - method(args[0], args[1]) - elif len(args) == 3: - method(args[0], args[1], args[2]) - elif len(args) == 4: - method(args[0], args[1], args[2], args[3]) - elif len(args) == 5: - method(args[0], args[1], args[2], args[3], args[4]) - except InvalidArgument: - # success - return - except Exception as e: - self.assertTrue(False, - 'method: %s, arg: %s ' % (method, args) + - 'failed with the wrong exception: ' - '%s' % str(e)) - self.assertTrue(False, 'method: %s, arg: %s did not fail' - % (method, args)) - - # PRIVATE FUNCTIONS ---------------------------------------------------- - def _save_config(self): - """save config""" - # save inventory - src_path = os.path.join(utils.get_kolla_cli_etc(), - 'ansible', 'inventory.json') - dst_path = os.path.join('/tmp', 'inventory.json.utest.save') - copyfile(src_path, dst_path) - - # save group vars - ansible_dir = os.path.join(utils.get_kolla_ansible_home(), 'ansible') - groupdir = os.path.join(ansible_dir, 'group_vars') - self._save_dir(groupdir) - - # save host vars - hostdir = os.path.join(ansible_dir, 'host_vars') - self._save_dir(hostdir) - - def _restore_config(self): - """restore config""" - # restore inventory - dst_path = os.path.join(utils.get_kolla_cli_etc(), - 'ansible', 'inventory.json') - src_path = os.path.join('/tmp', 'inventory.json.utest.save') - copyfile(src_path, dst_path) - - # restore group vars - ansible_dir = os.path.join(utils.get_kolla_ansible_home(), 'ansible') - groupdir = os.path.join(ansible_dir, 'group_vars') - self._restore_dir(groupdir) - - # restore host vars - hostdir = os.path.join(ansible_dir, 'host_vars') - self._restore_dir(hostdir) - - def _save_dir(self, src_dir): - if not os.path.exists(src_dir): - return - dirname = os.path.basename(src_dir) - save_dir = os.path.join('/tmp', dirname + '.utest.save') - if os.path.exists(save_dir): - shutil.rmtree(save_dir) - os.mkdir(save_dir) - fnames = os.listdir(src_dir) - for fname in fnames: - src_path = os.path.join(src_dir, fname) - dst_path = os.path.join(save_dir, fname) - copyfile(src_path, dst_path) - - def _restore_dir(self, dst_dir): - # we do not have privs to write these files - ignore_list = ['all.yml'] - - dirname = os.path.basename(dst_dir) - save_dir = os.path.join('/tmp', dirname + '.utest.save') - sv_fnames = os.listdir(save_dir) - fnames = os.listdir(dst_dir) - # remove any new var files created by tests - for fname in fnames: - if fname not in sv_fnames: - os.remove(os.path.join(dst_dir, fname)) - # restore saved files - for sv_fname in sv_fnames: - if sv_fname in ignore_list: - continue - src_path = os.path.join(save_dir, sv_fname) - dst_path = os.path.join(dst_dir, sv_fname) - copyfile(src_path, dst_path) diff --git a/kolla_cli/tests/functional/functional_test_setup.sh b/kolla_cli/tests/functional/functional_test_setup.sh deleted file mode 100755 index 0b74896..0000000 --- a/kolla_cli/tests/functional/functional_test_setup.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Setup script for running kolla-cli functional tests. -# -# clean up files from last run -rm -f $KOLLA_ETC/kolla-cli/ansible/inventory.json -rm -f $KOLLA_HOME/ansible/group_vars/__GLOBAL__ -rm -f $KOLLA_HOME/kolla-cli/ansible.lock -rm -f $KOLLA_ETC/passwords.yml - -# setup the various files needed for the cli to run -mkdir -p $KOLLA_ETC/kolla-cli/ansible -touch $KOLLA_ETC/kolla-cli/ansible/inventory.json -mkdir -p $KOLLA_HOME/kolla-cli -touch $KOLLA_HOME/kolla-cli/ansible.lock - -# If it's not there, clone the kolla-ansible repo to get its ansible directory -# and then copy it over -mkdir -p $KOLLA_HOME/git -if [ ! -d $KOLLA_HOME/ansible ]; then - git clone https://github.com/openstack/kolla-ansible $KOLLA_HOME/git - cp -rf $KOLLA_HOME/git/ansible $KOLLA_HOME/ansible/ -fi - -# setup needed kolla-ansible files -cp $KOLLA_HOME/git/etc/kolla/passwords.yml $KOLLA_ETC/passwords.yml -mkdir -p $KOLLA_HOME/ansible/host_vars -touch $KOLLA_HOME/ansible/group_vars/__GLOBAL__ diff --git a/kolla_cli/tests/functional/inventory_test_file b/kolla_cli/tests/functional/inventory_test_file deleted file mode 100644 index 41f987d..0000000 --- a/kolla_cli/tests/functional/inventory_test_file +++ /dev/null @@ -1,5 +0,0 @@ -# Test ansible inventory -[aardvark] - -[chipmunk] - diff --git a/kolla_cli/tests/functional/test_client_upgrade.py b/kolla_cli/tests/functional/test_client_upgrade.py deleted file mode 100644 index 63a8d7f..0000000 --- a/kolla_cli/tests/functional/test_client_upgrade.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -import logging -import os -import shutil -import unittest - -from kolla_cli.api.client import ClientApi -from kolla_cli.common.ansible_inventory import AnsibleInventory -from kolla_cli.common.utils import get_kolla_cli_etc - -INV_NAME = 'inventory.json' - -CLIENT = ClientApi() -LOG = logging.getLogger(__name__) - - -class TestFunctional(KollaCliTest): - """Test description - - This test will look for old version inventory files in the local current - working directory. If none are found, it will look in the user's home - directory. If none are found there too, it will print a warning and skip - the test. - - Old version inventory files must be named inventory.json.v1, - inventory.json.v2, etc. - - An upgrade test will be run on each old version inventory file that is - found. - """ - def test_upgrade(self): - inv_fpaths = self._find_inv_fpaths() - if not inv_fpaths: - LOG.warning('No old version inventory files were found. ' - 'Skipping test.') - for inv_fpath in inv_fpaths: - version = self._get_version(inv_fpath) - self._replace_inventory(inv_fpath) - self._test_upgrade(version) - - def _get_version(self, inv_fpath): - try: - version = int(inv_fpath.split('.v')[1]) - except Exception: - raise Exception('Invalid version number on old inventory file: %s' - % inv_fpath) - return version - - def _find_inv_fpaths(self): - """find old version inventories - - Look in order at these locations: - - current working directory - - home directory - """ - fpaths = [] - search_dirs = [os.getcwd(), os.path.expanduser('~')] - for search_dir in search_dirs: - fpaths = self._get_inv_fpaths(search_dir) - if fpaths: - break - return fpaths - - def _get_inv_fpaths(self, inv_dir): - upg_inventory_paths = [] - fnames = os.listdir(inv_dir) - for fname in fnames: - if fname.startswith(INV_NAME + '.v'): - path = os.path.join(inv_dir, fname) - upg_inventory_paths.append(path) - return upg_inventory_paths - - def _replace_inventory(self, old_version_inv_path): - inv_path = os.path.join(get_kolla_cli_etc(), - 'ansible', 'inventory.json') - shutil.copyfile(old_version_inv_path, inv_path) - - def _test_upgrade(self, version): - hostname = 'test_host_upg' - - # This host add will cause the inventory to be upgraded - CLIENT.host_add([hostname]) - CLIENT.host_remove([hostname]) - - # run tests for each version: - if version <= 1: - self._test_v1_upgrade() - - if version <= 2: - self._test_v2_upgrade() - - def _test_v1_upgrade(self): - # this is a v1 inventory - # in v1 > v2, ceilometer was added, check that it's there - # and verify that all ceilometer groups are in the same groups - # as heat. - ansible_inventory = AnsibleInventory() - heat = CLIENT.service_get(['heat'])[0] - expected_groups = sorted(heat.get_groups()) - ceilometer = ansible_inventory.services['ceilometer'] - expected_services = ceilometer.get_sub_servicenames() - expected_services.append('ceilometer') - expected_services = sorted(expected_services) - services = CLIENT.service_get_all() - services_found = [] - - for service in services: - servicename = service.get_name() - if servicename.startswith('ceilometer'): - groups = sorted(service.get_groups()) - if servicename == 'ceilometer': - self.assertEqual(expected_groups, groups, - 'groups mismatch between ' - 'ceilometer ' - 'and %s' % servicename) - elif servicename == 'ceilometer-compute': - self.assertEqual(['compute'], groups, - 'groups mismatch between ' - 'ceilometer-compute ' - 'and %s' % servicename) - else: - # sub-services should have no groups (they inherit) - self.assertEqual([], groups, - '%s has unexpected groups' - % servicename) - services_found.append(servicename) - - services_found = sorted(services_found) - self.assertEqual(expected_services, services_found, - 'ceilometer subservices mismatch') - - def _test_v2_upgrade(self): - # this is a v2 inventory. In the v2 to v3 upgrade, all subservices were - # fixed up to have a parent service - services = CLIENT.service_get_all() - servicenames = [] - for service in services: - servicenames.append(service.name) - if '-' in service.name: - # this is a subservice - parent = service.get_parent() - self.assertIsNotNone(parent, - 'subservice: %s, is missing its parent' - % service.name) - - # ceilometer-alarms were removed in kolla v3.0.1, - # check that they're gone - self.assertNotIn('ceilometer-alarm-evaluator', servicenames, - 'ceilometer-alarm-evaluator still exists.') - self.assertNotIn('ceilometer-alarm-notifier', servicenames, - 'ceilometer-alarm-notifier still exists.') - - # aodh and ceph were added in 3.0.1 - self.assertIn('aodh', servicenames, 'aodh not in inventory') - self.assertIn('ceph', servicenames, 'ceph not in inventory') - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_config.py b/kolla_cli/tests/functional/test_config.py deleted file mode 100644 index 4c89738..0000000 --- a/kolla_cli/tests/functional/test_config.py +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -import os -import unittest - -import kolla_cli.api.properties - -from kolla_cli.api.client import ClientApi -from kolla_cli.tests.functional.common import KollaCliTest - -CLIENT = ClientApi() - - -class TestFunctional(KollaCliTest): - - def test_config_reset(self): - # test global property reset - # set a property and make sure it was set correctly - property_dict = {'test': 'test'} - CLIENT.property_set(property_dict) - fetched_properties = CLIENT.property_get() - fetched_dict = self._properties_to_dict(fetched_properties) - self.assertIs(self._in_dict(property_dict, fetched_dict), True, - 'property set failed') - - # now clear the config and make sure the property we just - # set is now gone - CLIENT.config_reset() - fetched_properties = CLIENT.property_get() - fetched_dict = self._properties_to_dict(fetched_properties) - self.assertIs(self._in_dict(property_dict, fetched_dict), False, - 'global property reset config failed') - - # test host property reset - host_list = ['test'] - CLIENT.host_add(host_list) - CLIENT.property_set(property_dict, - kolla_cli.api.properties.HOST_TYPE) - fetched_properties = CLIENT.property_get( - kolla_cli.api.properties.HOST_TYPE, host_list) - fetched_dict = self._properties_to_dict(fetched_properties) - self.assertIs(self._in_dict(property_dict, fetched_dict), True, - 'host property set failed') - - CLIENT.config_reset() - # need to add back in the host 'test' or the property - # get call will fail after a reset - CLIENT.host_add(host_list) - fetched_properties = CLIENT.property_get( - kolla_cli.api.properties.HOST_TYPE, host_list) - fetched_dict = self._properties_to_dict(fetched_properties) - self.assertIs(self._in_dict(property_dict, fetched_dict), False, - 'host property reset config failed') - - # test group property reset - group_list = ['control'] - CLIENT.property_set(property_dict, - kolla_cli.api.properties.GROUP_TYPE) - fetched_properties = CLIENT.property_get( - kolla_cli.api.properties.GROUP_TYPE, group_list) - fetched_dict = self._properties_to_dict(fetched_properties) - self.assertIs(self._in_dict(property_dict, fetched_dict), True, - 'group property set failed') - - CLIENT.config_reset() - fetched_properties = CLIENT.property_get( - kolla_cli.api.properties.GROUP_TYPE, group_list) - fetched_dict = self._properties_to_dict(fetched_properties) - self.assertIs(self._in_dict(property_dict, fetched_dict), False, - 'group property reset config failed') - - # test host reset - # add a host and make sure it was added correctly - host_list = ['test'] - CLIENT.host_add(host_list) - fetched_hosts = CLIENT.host_get_all() - fetched_list = self._hosts_to_list(fetched_hosts) - self.assertIs(set(host_list).issubset(fetched_list), True, - 'host set failed') - - # now clear the config and make sure the host we just - # added is now gone - CLIENT.config_reset() - fetched_hosts = CLIENT.host_get_all() - fetched_list = self._hosts_to_list(fetched_hosts) - self.assertIs(set(host_list).issubset(fetched_list), False, - 'inventory reset config failed') - - # need to populate the password file or many other tests will fail - CLIENT.password_init() - - def test_config_import_inventory(self): - # test config import of a different inventory file - expected_group_names = ['chipmunk', 'aardvark'] - test_inventory_path = os.path.join( - os.getcwd(), 'kolla_cli', 'tests', 'functional', - 'inventory_test_file') - CLIENT.config_import_inventory(file_path=test_inventory_path) - groups = CLIENT.group_get_all() - self.assertEqual(len(groups), len(expected_group_names)) - for group in groups: - self.assertIn(group.name, expected_group_names) - - # need to reset the inventory back to its defaults - CLIENT.config_reset() - - @staticmethod - def _properties_to_dict(props): - property_dict = {} - for prop in props: - property_dict[prop.name] = prop.value - return property_dict - - @staticmethod - def _hosts_to_list(hosts): - host_list = [] - for host in hosts: - host_list.append(host.name) - return host_list - - @staticmethod - def _in_dict(base, target): - base_keys = base.keys() - target_keys = target.keys() - if set(base_keys).issubset(target_keys) is False: - return False - - for key in base.keys(): - target_value = target.get(key, None) - if target_value != base[key]: - return False - - return True - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_deploy.py b/kolla_cli/tests/functional/test_deploy.py deleted file mode 100644 index 34d1c22..0000000 --- a/kolla_cli/tests/functional/test_deploy.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -from kolla_cli.api.client import ClientApi -from kolla_cli.common.ansible_inventory import AnsibleInventory -from kolla_cli.common.inventory import Inventory - -import json -import unittest - -CLIENT = ClientApi() -UNREACHABLE = 'UNREACHABLE!' - - -class TestFunctional(KollaCliTest): - - def test_json_generator(self): - self.run_cli_cmd('setdeploy local') - - host1 = 'host_test1' - self.run_cli_cmd('host add %s' % host1) - - inventory = Inventory.load() - - path = inventory.create_json_gen_file() - (retval, msg) = self.run_command(path) - inventory.remove_json_gen_file(path) - self.assertEqual(0, retval, 'json generator command failed: %s' % msg) - - self.assertNotEqual('', msg, 'json generator returned no data: %s' - % msg) - - self.assertIn(host1, msg, '%s not in json_gen output: %s' - % (host1, msg)) - - ansible_inventory = AnsibleInventory() - services = ansible_inventory.services - for servicename, service in services.items(): - self.assertIn(servicename, msg, '%s not in json_gen output: %s' - % (servicename, msg)) - - # verify that json output is valid. This will throw if invalid json - try: - json.loads(msg) - except Exception: - self.assertTrue(False, 'invalid json: %s' % msg) - remote_msg = '"ansible_ssh_user": "root"' - local_msg = '"ansible_connection": "local"' - - # verify that setdeploy local worked: - self.assertIn(local_msg, msg, '%s not in local json_gen output: %s' - % (local_msg, msg)) - self.assertNotIn(remote_msg, msg, '%s in local json_gen output: %s' - % (remote_msg, msg)) - - # verify that setdeploy remote worked: - CLIENT.set_deploy_mode(remote_mode=True) - inventory = Inventory.load() - path = inventory.create_json_gen_file() - (retval, msg) = self.run_command(path) - inventory.remove_json_gen_file(path) - self.assertEqual(0, retval, 'json generator command failed: %s' % msg) - - self.assertIn(remote_msg, msg, '%s not in remote json_gen output: %s' - % (remote_msg, msg)) - self.assertNotIn(local_msg, msg, '%s in remote json_gen output: %s' - % (local_msg, msg)) - - def test_json_filtering(self): - - hosts = ['host_test1', 'host_test2', 'host_test3'] - groups = ['control', 'network', 'storage'] - - for host in hosts: - self.run_cli_cmd('host add %s' % host) - for groupname in groups: - group = CLIENT.group_get([groupname])[0] - group.add_host(host) - - inventory = Inventory.load() - - # filter by host- include all hosts - inv_filter = {'deploy_hosts': hosts} - path = inventory.create_json_gen_file(inv_filter) - self.log.info('run command: %s' % path) - (retval, msg) = self.run_command(path) - inventory.remove_json_gen_file(path) - self.assertEqual(0, retval, 'json generator command failed: %s' % msg) - - self.check_json(msg, groups, hosts, groups, hosts) - - # filter by host- to first host - included_host = hosts[0] - inv_filter = {'deploy_hosts': [included_host]} - path = inventory.create_json_gen_file(inv_filter) - self.log.info('run command: %s' % path) - (retval, msg) = self.run_command(path) - inventory.remove_json_gen_file(path) - self.assertEqual(0, retval, 'json generator command failed: %s' % msg) - self.check_json(msg, groups, hosts, groups, [included_host]) - - # filter by group- include all groups - inv_filter = {'deploy_groups': groups} - path = inventory.create_json_gen_file(inv_filter) - self.log.info('run command: %s' % path) - (retval, msg) = self.run_command(path) - inventory.remove_json_gen_file(path) - self.assertEqual(0, retval, 'json generator command failed: %s' % msg) - self.check_json(msg, groups, hosts, groups, hosts) - - # filter by group- to first group - included_group = groups[0] - inv_filter = {'deploy_groups': [included_group]} - path = inventory.create_json_gen_file(inv_filter) - self.log.info('run command: %s' % path) - (retval, msg) = self.run_command(path) - inventory.remove_json_gen_file(path) - self.assertEqual(0, retval, 'json generator command failed: %s' % msg) - self.check_json(msg, groups, hosts, [included_group], hosts) - - def test_deploy(self): - # test will start with no hosts in the inventory - # deploy will throw an exception if it fails - # disable all services first as without it empty groups cause errors - enable_service_props = {} - for service in CLIENT.service_get_all(): - service_name = service.name.replace('-', '_') - enable_service_props['enable_%s' % service_name] = 'no' - CLIENT.property_set(enable_service_props) - - msg = '' - CLIENT.set_deploy_mode(remote_mode=False) - job = CLIENT.deploy(hostnames=[]) - job.wait() - msg = job.get_console_output() - self.assertEqual(job.get_status(), 0, - 'error performing whole host deploy %s' % msg) - - # test deploy with timeout - msg = self.run_cli_cmd('action deploy --timeout .001', - expect_error=True) - self.assertIn('timed out', msg) - - def test_upgrade(self): - # test will upgrade an environment with no hosts, mostly a NOP, - # but it will go through the client code paths. - self.run_cli_cmd('action upgrade -v') - - msg = '' - # run rabbitmq service deploy - try: - CLIENT.host_add(['dummy_host']) - CLIENT.set_deploy_mode(remote_mode=True) - job = CLIENT.upgrade() - job.wait() - msg = job.get_console_output() - self.assertEqual(job.get_status(), 1, - 'upgrade succeeded unexpectedly: %s' - % msg) - self.assertIn(UNREACHABLE, msg) - except Exception as e: - raise e - finally: - CLIENT.host_remove(['dummy_host']) - - def test_pull(self): - # test will upgrade an environment with no hosts, mostly a NOP, - # but it will go through the client code paths. - self.run_cli_cmd('action pull -v') - - CLIENT.host_add(['test_pull_host']) - CLIENT.set_deploy_mode(remote_mode=True) - job = CLIENT.pull() - job.wait() - msg = job.get_console_output() - self.assertEqual(job.get_status(), 1, - 'pull succeeded unexpectedly: %s' - % msg) - self.assertIn(UNREACHABLE, msg) - - def check_json(self, msg, groups, hosts, included_groups, included_hosts): - err_msg = ('included groups: %s\n' % included_groups + - 'included hosts: %s\n' % included_hosts) - inv_dict = json.loads(msg) - for group in groups: - group_hosts = inv_dict[group]['hosts'] - for host in hosts: - if group in included_groups and host in included_hosts: - self.assertIn(host, group_hosts, err_msg + - '%s not in %s' % (host, group_hosts)) - else: - self.assertNotIn(host, group_hosts, err_msg + - '%s still in %s' % (host, group_hosts)) - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_destroy.py b/kolla_cli/tests/functional/test_destroy.py deleted file mode 100644 index cc35b14..0000000 --- a/kolla_cli/tests/functional/test_destroy.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -from kolla_cli.api.client import ClientApi - -import random -import time -import unittest - -TEST_GROUP_NAME = 'test_group' -CLIENT = ClientApi() - -NOT_KNOWN = 'Name or service not known' -UNREACHABLE = 'UNREACHABLE!' - - -class TestFunctional(KollaCliTest): - - def test_destroy(self): - - # use a non-existent host. - # This will generate expected exceptions in all host access - # commands. - hostnames = ['test_deploy_host1'] - CLIENT.host_add(hostnames) - - # add host to a new deploy group - CLIENT.group_add([TEST_GROUP_NAME]) - group = CLIENT.group_get([TEST_GROUP_NAME])[0] - for hostname in hostnames: - group.add_host(hostname) - - # destroy services, initialize server - self.log.info('Start destroy #1') - job = CLIENT.host_destroy(hostnames, destroy_type='kill', - include_data=True, verbose_level=2) - self._process_job(job, 'destroy #1') - - self.log.info('updating various properties for the test') - - # the following deploy will fail if we don't disable all the - # services first - enable_service_props = {} - for service in CLIENT.service_get_all(): - service_name = service.name.replace('-', '_') - enable_service_props['enable_%s' % service_name] = 'no' - CLIENT.property_set(enable_service_props) - - # test killing a deploy - self.log.info('Kill a deployment') - job = CLIENT.deploy() - time.sleep(random.randint(5, 8)) - job.kill() - self._process_job(job, 'deploy-kill', - expect_kill=True) - - # do a deploy of a limited set of services - self.log.info('Start a deployment') - job = CLIENT.deploy() - self._process_job(job, 'deploy') - - self.log.info('Start destroy #3, include data') - job = CLIENT.host_destroy(hostnames, destroy_type='stop', - include_data=True) - self._process_job(job, 'destroy #3') - - def _process_job(self, job, descr, expect_kill=False): - status = job.wait() - output = job.get_console_output() - self.log.info('job is complete. status: %s, err: %s' - % (status, output)) - if expect_kill: - self.assertEqual(2, status, 'Job %s does not have killed status %s' - % (descr, output)) - else: - self.assertEqual(1, status, 'Job %s ' % descr + - 'succeeded when it should have failed') - self.assertIn(UNREACHABLE, output, - 'Job %s: No hosts, but got wrong error: %s' - % (descr, output)) - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_group.py b/kolla_cli/tests/functional/test_group.py deleted file mode 100644 index 53231fa..0000000 --- a/kolla_cli/tests/functional/test_group.py +++ /dev/null @@ -1,246 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -import json -import unittest - -from kolla_cli.api.client import ClientApi -from kolla_cli.api.exceptions import NotInInventory -from kolla_cli.common.ansible_inventory import AnsibleInventory - -CLIENT = ClientApi() - - -class TestFunctional(KollaCliTest): - - def test_group_add_remove(self): - groups = self.get_default_groups() - - # check default group list - self.check_group(groups) - - tg1 = 'test_group_t1' - tg2 = 'test_group_t2' - - self.run_cli_cmd('group add %s' % tg1) - groups[tg1] = { - 'Services': [], - 'Hosts': []} - self.check_group(groups) - - self.run_cli_cmd('group add %s' % tg2) - groups[tg2] = { - 'Services': [], - 'Hosts': []} - self.check_group(groups) - - self.run_cli_cmd('group remove %s' % tg2) - del groups[tg2] - self.check_group(groups) - - self.run_cli_cmd('group remove %s' % tg1) - del groups[tg1] - self.check_group(groups) - - def test_group_add_host(self): - groups = self.get_default_groups() - - host1 = 'test_host1' - host2 = 'test_host2' - groupname = 'control' - - group = groups[groupname] - hosts = group['Hosts'] - - self.run_cli_cmd('host add %s' % host1) - - hosts.append(host1) - self.run_cli_cmd('group addhost %s %s' % (groupname, host1)) - self.check_group(groups) - - self.run_cli_cmd('host add %s' % host2) - - hosts.append(host2) - self.run_cli_cmd('group addhost %s %s' % (groupname, host2)) - self.check_group(groups) - - self.run_cli_cmd('group removehost %s %s' % (groupname, host2)) - hosts.remove(host2) - self.check_group(groups) - - self.run_cli_cmd('group removehost %s %s' % (groupname, host1)) - hosts.remove(host1) - self.check_group(groups) - - def test_add_group_to_service(self): - groups = self.get_default_groups() - - groupname = 'network' - service1 = 'keystone' - service2 = 'heat-api' - - self.run_cli_cmd('service addgroup %s %s' % (service1, groupname)) - groups[groupname]['Services'].append(service1) - self.check_group(groups) - - self.run_cli_cmd('service addgroup %s %s' % (service2, groupname)) - groups[groupname]['Services'].append(service2) - self.check_group(groups) - - self.run_cli_cmd('service removegroup %s %s' - % (service2, groupname)) - groups[groupname]['Services'].remove(service2) - self.check_group(groups) - - self.run_cli_cmd('service removegroup %s %s' - % (service1, groupname)) - groups[groupname]['Services'].remove(service1) - self.check_group(groups) - - def test_group_api(self): - # check some of the api not exercised by the CLI - groupname1 = 'group_test1' - groupname2 = 'group_test2' - exp_groups = sorted([groupname1, groupname1, groupname2]) - CLIENT.group_add(exp_groups) - groups = CLIENT.group_get([groupname1]) - groupnames = [] - for group in groups: - groupnames.append(group.name) - self.assertIn(groupname1, groupnames, 'group %s is missing in %s' - % (groupname1, groupnames)) - self.assertNotIn(groupname2, groupnames, 'group %s is unexpectedly in ' - '%s' % (groupname2, groupnames)) - groups = CLIENT.group_get(exp_groups) - groupnames = [] - for group in groups: - groupnames.append(group.name) - self.assertEqual(exp_groups, sorted(groupnames), 'groups mismatch') - - CLIENT.group_remove(exp_groups) - try: - CLIENT.group_get(exp_groups) - self.assertTrue(False, 'Failed to raise NotInInventory exception') - except NotInInventory: - pass - except Exception as e: - raise e - - hostname1 = 'testhost1' - CLIENT.group_add([groupname1]) - group1 = CLIENT.group_get([groupname1])[0] - CLIENT.host_add([hostname1]) - group1.add_host(hostname1) - hostnames = group1.get_hosts() - self.assertIn(hostname1, hostnames, 'missing hostname') - group1.add_service('nova') - servicenames = group1.get_services() - self.assertIn('nova', servicenames, 'missing servicename') - - # check the type checking logic - self.check_types(CLIENT.group_add, [list]) - self.check_types(CLIENT.group_remove, [list]) - - def check_group(self, groups): - """check groups - - group listhosts -f json: - [{"Group Name": "compute", "Hosts": []}, - {"Group Name": "control", "Hosts": ["ub-target1"]}, - {"Group Name": "network", "Hosts": []}] - - group listservices -f json: - [{"Group Name": "compute", "Services": []}, - {"Group Name": "control", - "Services": ["glance", "keystone", "mysqlcluster", - "nova", "rabbitmq"]}, - {"Group Name": "network", - "Services": ["haproxy", "neutron"]}] - """ - # check hosts in groups - msg = self.run_cli_cmd('group listhosts -f json') - cli_groups = json.loads(msg) - self.assertEqual(len(cli_groups), len(groups), - '# of groups in cli not equal to expected groups.' + - '\n\nexpected: %s, \n\ncli: %s' - % (groups, cli_groups)) - - for cli_group in cli_groups: - cli_hosts = cli_group['Hosts'] - for group_name, info in groups.items(): - if group_name != cli_group['Group']: - continue - group_hosts = info['Hosts'] - self.assertEqual(len(cli_hosts), len(group_hosts), - 'Group: %s. # of hosts in cli ' % group_name + - 'not equal to expected hosts, ' + - '\n\nexpected: %s, \n\ncli: %s' - % (group_hosts, cli_hosts)) - - for group_host in group_hosts: - self.assertIn(group_host, cli_hosts, - 'Group: %s' % group_name + - '\n\nexpected_hosts: %s, \n\nnot in cli: %s ' - % (group_host, cli_hosts)) - - # check services in group - msg = self.run_cli_cmd('group listservices -f json') - cli_groups = json.loads(msg) - - for cli_group in cli_groups: - cli_services = cli_group['Services'] - for group_name, info in groups.items(): - if group_name != cli_group['Group']: - continue - group_services = info['Services'] - self.assertEqual(len(cli_services), len(group_services), - 'Group: %s. # of services in cli' - % group_name + - ' not equal to expected services,' + - '\nexpected: %s, \ncli: %s' - % (sorted(group_services), - sorted(cli_services))) - for group_service in group_services: - self.assertIn(group_service, cli_services, - 'Group: %s' % group_name + - '\nexpected_services: %s, \nnot in cli: %s ' - % (sorted(group_services), - sorted(cli_services))) - - def get_default_groups(self): - """get default groups - - return a dict: - {groupname: { - Services: [svc1, svc2...], - Hosts: []}} - """ - ansible_inventory = AnsibleInventory() - groupnames = ansible_inventory.groups - groups = {} - for groupname in groupnames: - groups[groupname] = {'Services': [], - 'Hosts': []} - - for servicename, service in ansible_inventory.services.items(): - if groupname in service.get_groupnames(): - groups[groupname]['Services'].append(servicename) - - return groups - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_host.py b/kolla_cli/tests/functional/test_host.py deleted file mode 100644 index 497794d..0000000 --- a/kolla_cli/tests/functional/test_host.py +++ /dev/null @@ -1,196 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -import json -import os -import unittest -import yaml - -from kolla_cli.api.client import ClientApi -from kolla_cli.api.exceptions import NotInInventory -from kolla_cli.api.host import Host - -TEST_YML_FNAME = 'unittest_hosts_setup.yml' - -CLIENT = ClientApi() - - -class TestFunctional(KollaCliTest): - - def test_host_add_remove(self): - hosts = {} - - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - host1 = 'host_test1' - host2 = 'host_test2' - - group1 = 'control' - - hosts[host1] = Host(host1) - self.run_cli_cmd('host add %s' % host1) - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - hosts[host2] = Host(host2) - self.run_cli_cmd('host add %s' % host2) - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - del hosts[host2] - self.run_cli_cmd('host remove %s' % host2) - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - del hosts[host1] - self.run_cli_cmd('host remove %s' % host1) - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - # check remove all - hosts[host1] = Host(host1) - self.run_cli_cmd('host add %s' % host1) - hosts[host2] = Host(host2) - self.run_cli_cmd('host add %s' % host2) - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - hosts.clear() - self.run_cli_cmd('host remove all') - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - # check groups in host list - hosts[host1] = Host(host1, [group1]) - self.run_cli_cmd('host add %s' % host1) - self.run_cli_cmd('group addhost %s %s' % (group1, host1)) - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - # removing group by resetting host1 to new Host with no groups - hosts[host1] = Host(host1) - self.run_cli_cmd('group removehost %s %s' % (group1, host1)) - msg = self.run_cli_cmd('host list -f json') - self._check_cli_output(hosts, msg) - - def test_host_api(self): - # check some of the api not exercised by the CLI - host1 = 'host_test1' - host2 = 'host_test2' - exp_hosts = sorted([host1, host2]) - CLIENT.host_add(exp_hosts) - hosts = CLIENT.host_get([host1]) - hostnames = [] - for host in hosts: - hostnames.append(host.name) - self.assertIn(host1, hostnames, 'host %s is missing in %s' - % (host1, hostnames)) - self.assertNotIn(host2, hostnames, 'host %s is unexpectedly in %s' - % (host2, hostnames)) - hosts = CLIENT.host_get(exp_hosts) - hostnames = [] - for host in hosts: - hostnames.append(host.name) - self.assertEqual(exp_hosts, sorted(hostnames), 'hosts mismatch') - - CLIENT.host_remove(exp_hosts) - try: - CLIENT.host_get(exp_hosts) - self.assertTrue(False, 'Failed to raise NotInInventory exception') - except NotInInventory: - pass - except Exception as e: - raise e - - # check the type checking logic - self.check_types(CLIENT.host_add, [list]) - self.check_types(CLIENT.host_remove, [list]) - self.check_types(CLIENT.host_setup, [dict]) - self.check_types(CLIENT.host_ssh_check, [list]) - self.check_types(CLIENT.host_destroy, [list, str, int, bool]) - - def test_host_list_nonascii(self): - hostname = 'host_test1' - CLIENT.host_add([hostname]) - - # this is a groupname in cyrillic chars - groupname1 = u'\u0414\u0435\u043a\u0430\u0442' - groupname2 = 'test_group2' # ascii groupname - groupnames = [groupname1, groupname2] - CLIENT.group_add(groupnames) - groups = CLIENT.group_get(groupnames) - for group in groups: - group.add_host(hostname) - -# TODO(bmace) -- test currently broken -# msg = self.run_cli_cmd('host list') -# self.assertIn(groupname1, msg) -# self.assertNotIn("u'\u0414\u0435\u043a\u0430\u0442'", msg, 'groupname ' -# 'incorrectly appearing as unicode bytes in output') -# self.assertNotIn("u'test_group2'", msg, 'unicode escape text is ' -# 'incorrectly displayed in host list output') - - def _check_cli_output(self, exp_hosts, cli_output): - """Verify cli data against model data - - The host list cli output looks like this: - - $ host list -f json - [{"Host": "foo", "Groups": ["control", "network"]}] - """ - # check for any host in cli output that shouldn't be there - cli_hosts = json.loads(cli_output) - - if not exp_hosts: - if len(cli_hosts) == 1: - cli_hostname = cli_hosts[0]['Host'] - if not cli_hostname: - # both cli and expected hosts are None - return - - for cli_host in cli_hosts: - cli_hostname = cli_host['Host'] - self.assertIn(cli_hostname, exp_hosts, - 'unexpected host: %s, found in cli output: %s' - % (cli_hostname, cli_output)) - - # check that all expected hosts are in the output - for exp_host in exp_hosts.values(): - exp_host_found = False - for cli_host in cli_hosts: - if exp_host.get_name() == cli_host['Host']: - exp_host_found = True - cli_groups = cli_host['Groups'] - exp_groups = exp_host.get_groups() - self.assertEqual(exp_groups, cli_groups) - - self.assertTrue(exp_host_found, - 'hostname: %s not in cli output: \n%s' - % (exp_host.get_name(), cli_output)) - - def write_yml(self, yml_dict): - yml = yaml.dump(yml_dict) - with open(self.get_yml_path(), 'w') as yml_file: - yml_file.write(yml) - - def get_yml_path(self): - home = os.path.expanduser('~') - return os.path.join(home, TEST_YML_FNAME) - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_password.py b/kolla_cli/tests/functional/test_password.py deleted file mode 100644 index 4226e19..0000000 --- a/kolla_cli/tests/functional/test_password.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -import os -import unittest - -from kolla_cli.api import client -from kolla_cli.common.utils import get_kolla_etc -from kolla_cli.tests.functional.common import KollaCliTest - -CLIENT = client.ClientApi() - -PUBLIC_KEY = ( - 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqusDp5jpkbng3sRue8gZV6/PCQp9' - 'ogUd5/OZ3sh9VgdaigHoYUfXZElTZLlkL71tD9WZJr69PDwmG/nE4quba8rLcDY2wC0' - 'qjq+r06ExhlRu4ivy7OxT29s8FSe8Uht9Pz8ahnXxddLF55yTbC81XrSXDBFc6Nnogz' - '+g6GgXVKtwTkm5g3K+qix5zVECu8zzawBR/s+v0dkDxKwSY8XOG6JZlMUndaDaikZZi' - 'qp8KAOJpajM77aCfDkY3VZGFBCJiEGLVDhFrtXuBI9I0YzX4j9pZZWpSzkM/FwlPjDR' - 'SW1C9MAAFLoEQTN4j1Z5hkDNXDsr49wJBi+jjQ0FPMMvfJktrznRuO2fUa9W2iilOrv' - '1PyrknssmW1iYXiWJ5Bq8A9sKE1r7Nbdjhcjskp77X57tNjtarRUcj3FqGjC8pv+k92' - '9Y+FvkXbjpBsHpdMFh8BlM+EnwnsjkiQpmjLv8bpeeQooLyQQmZn94zY73bbGrsjzXe' - 'OhOTDnKAS14hxCnBlEbudHB4erp/5Nj+A8UVAT0KXPM+mkDrum/dsvV0wnvBicAVt/a' - 'tmkwDKJqXDmj4elNe8/jTXSYHpTDo29xtcGpka9AtWarmnt8QkRuieD1xSXsEUQswjq' - 'aQD2ikitKt/hEyCmT+7fy4yYKK35kukUj5qV85A8O/hOYf5vFjtRw==') - -PRIVATE_KEY = ( - '-----BEGIN RSA PRIVATE KEY-----\n' - 'MIIJKAIBAAKCAgEAqrrA6eY6ZG54N7EbnvIGVevzwkKfaIFHefzmd7IfVYHWooB6\n' - 'GFH12RJU2S5ZC+9bQ/VmSa+vTw8Jhv5xOKrm2vKy3A2NsAtKo6vq9OhMYZUbuIr8\n' - 'uzsU9vbPBUnvFIbfT8/GoZ18XXSxeeck2wvNV60lwwRXOjZ6IPoOhoF1SrcE5JuY\n' - 'Nyvqosec1RArvM82sAUf7Pr9HZA8SsEmPFzhuiWZTFJ3Wg2opGWYqqfCgDiaWozO\n' - '+2gnw5GN1WRhQQiYhBi1Q4Ra7V7gSPSNGM1+I/aWWVqUs5DPxcJT4w0UltQvTAAB\n' - 'S6BEEzeI9WeYZAzVw7K+PcCQYvo40NBTzDL3yZLa850bjtn1GvVtoopTq79T8q5J\n' - '7LJltYmF4lieQavAPbChNa+zW3Y4XI7JKe+1+e7TY7Wq0VHI9xahowvKb/pPdvWP\n' - 'hb5F246QbB6XTBYfAZTPhJ8J7I5IkKZoy7/G6XnkKKC8kEJmZ/eM2O922xq7I813\n' - 'joTkw5ygEteIcQpwZRG7nRweHq6f+TY/gPFFQE9ClzzPppA67pv3bL1dMJ7wYnAF\n' - '69VedCYMSoYIHpcN80w9it/6Cfm8niAy3v9e0icSVEsvkzcV6eFjLggY1DQ9WBPN\n' - 'MR4LKGNDuxEWeZAQi+A6Ejclx1KKBhL/E4SNj3ev4/5glaMjzSIUpA4415o=\n' - '-----END RSA PRIVATE KEY-----' - ) - - -class TestFunctional(KollaCliTest): - - def test_password_set_clear(self): - # test list - msg = self.run_cli_cmd('password list') - key = 'database_password' - value = '-' - ok = self._password_value_exists(key, value, msg) - self.assertTrue(ok, 'list failed. Password (%s/%s) not in output: %s' - % (key, value, msg)) - - # test setting empty password - self.run_cli_cmd('password set %s --insecure' % key) - msg = self.run_cli_cmd('password list') - ok = self._password_value_exists(key, '-', msg) - self.assertTrue(ok, 'set empty password failed. Password ' + - '(%s/-) not in output: %s' % - (key, msg)) - - # test setting None password - CLIENT.password_set(key, None) - msg = self.run_cli_cmd('password list') - ok = self._password_value_exists(key, '-', msg) - self.assertTrue(ok, 'set None password failed. Password ' + - '(%s/-) not in output: %s' % - (key, msg)) - - # test clear - key = 'database_password' - value = '-' - self.run_cli_cmd('password clear %s' % key) - msg = self.run_cli_cmd('password list') - ok = self._password_value_exists(key, value, msg) - self.assertTrue(ok, 'clear password failed. Password ' + - '(%s/%s) not in output: %s' % - (key, value, msg)) - - # test setting an ssh key - key = 'nova_ssh_key' - CLIENT.password_set_sshkey(key, PRIVATE_KEY, PUBLIC_KEY) - keynames = CLIENT.password_get_names() - self.assertIn(key, keynames, 'ssh key not in passwords') - - # test modify non-ssh password - key = 'database_password' - value = '-' - self.run_cli_cmd('password set %s --insecure %s' % (key, value)) - msg = self.run_cli_cmd('password list') - ok = self._password_value_exists(key, value, msg) - self.assertTrue(ok, 'set modify password failed. Password ' + - '(%s/%s) not in output: %s' % - (key, value, msg)) - - # test to make sure that saves / loads aren't doing something - # bad to the password file size - CLIENT.password_clear(key) - # snapshot file size with key cleared - password_file_path = os.path.join(get_kolla_etc(), 'passwords.yml') - size_start = os.path.getsize(password_file_path) - # set and clear password - CLIENT.password_set(key, value) - CLIENT.password_clear(key) - size_end = os.path.getsize(password_file_path) - self.assertEqual(size_start, size_end, 'password file size changed ' + - 'during set/clear (%s/%s)' % (size_start, size_end)) - - # make sure to end the test with the password init, as some other - # non-password related tests require that all passwords in the file - # be populated - CLIENT.password_init() - - def _password_value_exists(self, key, value, cli_output): - """Verify cli data against model data""" - # check for any host in cli output that shouldn't be there - cli_lines = cli_output.split('\n') - for cli_line in cli_lines: - if key in cli_line and value in cli_line: - return True - return False - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_property.py b/kolla_cli/tests/functional/test_property.py deleted file mode 100644 index 6dc1fc1..0000000 --- a/kolla_cli/tests/functional/test_property.py +++ /dev/null @@ -1,294 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -import json -import os -import unittest - -from kolla_cli.common.utils import get_group_vars_dir -from kolla_cli.common.utils import get_host_vars_dir -from kolla_cli.common.utils import get_kolla_ansible_home - -from kolla_cli.common.inventory import Inventory - - -class TestFunctional(KollaCliTest): - - def test_properties(self): - # test global properties - self._properties_test() - - # test single group vars - group = 'prop_test_group1' - self.run_cli_cmd('group add %s' % group) - self._properties_test(groups=['control']) - - # test single host vars - host = 'prop_test_host1' - self.run_cli_cmd('host add %s' % host) - self._properties_test(hosts=[host]) - - # test multiple group vars - groups = [group] - group = 'prop_test_group2' - groups.append(group) - self.run_cli_cmd('group add %s' % group) - self._properties_test(groups=groups) - - # test multiple host vars - hosts = [host] - host = 'prop_test_host2' - hosts.append(host) - self.run_cli_cmd('host add %s' % host) - self._properties_test(hosts=hosts) - - # test all group vars - self._properties_test(groups=['all']) - - # test all host vars - self._properties_test(hosts=['all']) - - # test property override output - ovr_key = 'enable_haproxy' - ovr_value = 'no' - - # clear property values before test - self.run_cli_cmd('property clear %s' % ovr_key) - self.run_cli_cmd('property clear %s --host=all' % ovr_key) - self.run_cli_cmd('property clear %s --group=all' % ovr_key) - - # global property override test - self.run_cli_cmd('property set %s %s' % (ovr_key, ovr_value)) - json_str = self.run_cli_cmd('property list -f json') - msg = self._override_test(json_str, ovr_key, ovr_value, '*--') - self.assertEqual(msg, '', 'override check failed: %s' % msg) - - # host property override test - self.run_cli_cmd('property set %s %s --host=%s' % - (ovr_key, ovr_value, host)) - json_str = self.run_cli_cmd('property list -f json --host=%s' % host) - msg = self._override_test(json_str, ovr_key, - ovr_value, '*-H', host=host) - self.assertEqual(msg, '', 'host override check failed: %s' % msg) - - # group property override test - self.run_cli_cmd('property set %s %s --group=%s' % - (ovr_key, ovr_value, group)) - json_str = self.run_cli_cmd('property list -f json --group=%s' % group) - msg = self._override_test(json_str, ovr_key, - ovr_value, '*GH', group=group) - self.assertEqual(msg, '', 'group override check failed: %s' % msg) - - # check that group_var files are deleted - # when groups are deleted - for group in groups: - path = os.path.join(get_group_vars_dir(), group) - self.assertTrue(os.path.exists(path)) - self.run_cli_cmd('group remove %s' % group) - self.assertFalse(os.path.exists(path)) - - # check that host_var files are deleted - # when hosts are deleted - for host in hosts: - path = os.path.join(get_host_vars_dir(), host) - self.assertTrue(os.path.exists(path)) - self.run_cli_cmd('host remove %s' % host) - self.assertFalse(os.path.exists(path)) - - def _properties_test(self, groups=[], hosts=[]): - switch = '' - if groups: - switch = '--groups' - dir_name = 'group_vars' - elif hosts: - switch = '--hosts' - dir_name = 'host_vars' - - key = 'TeStKeY' - value = 'TeStVaLuE:123:abc' - - # initialize keys - targets_csv = '' - targets = groups + hosts - if 'all' in groups: - inv = Inventory.load() - targets = inv.get_groupnames() - targets_csv = 'all' - elif 'all' in hosts: - inv = Inventory.load() - targets = inv.get_hostnames() - targets_csv = 'all' - - comma = '' - sizes = {} # key = path, value = [size1, size2, etc] - for target in targets: - self.run_cli_cmd('property clear %s %s %s' - % (switch, target, key)) - if targets_csv != 'all': - targets_csv += comma + target - comma = ',' - path = os.path.join(get_kolla_ansible_home(), - 'ansible', dir_name, target) - sizes[path] = [os.path.getsize(path)] - if not switch: - self.run_cli_cmd('property clear %s' % key) - path = os.path.join(get_kolla_ansible_home(), - 'ansible/group_vars/__GLOBAL__') - sizes[path] = [os.path.getsize(path)] - - # test append - self.run_cli_cmd('property set %s %s %s %s' - % (switch, targets_csv, key, value)) - if switch: - msg = self.run_cli_cmd('property list -f json %s all' - % (switch)) - else: - msg = self.run_cli_cmd('property list -f json') - err_msg = self._check_property_values(key, value, msg, targets) - self.assertEqual(err_msg, '', - 'set failed property not in output: %s, %s (%s %s)' - % (key, value, switch, targets_csv)) - - bad_path = self._is_size_ok(sizes, 0, '<', 1) - self.assertIsNone(bad_path, 'Size of file %s did not ' % bad_path + - 'increase after append (%s %s)' - % (switch, targets_csv)) - - # test modify existing - value += '2' - self.run_cli_cmd('property set %s %s %s %s' - % (switch, targets_csv, key, value)) - msg = self.run_cli_cmd('property list --all -f json %s %s' - % (switch, targets_csv)) - err_msg = self._check_property_values(key, value, msg, targets) - self.assertEqual(err_msg, '', - 'set failed property not in output: %s, %s (%s %s)' - % (key, value, switch, targets_csv)) - bad_path = self._is_size_ok(sizes, 1, '<', 2) - self.assertIsNone(bad_path, 'Size of file %s did not ' % bad_path + - 'increase after modify (%s %s)' - % (switch, targets_csv)) - - # test clear - self.run_cli_cmd('property clear %s %s %s' - % (switch, targets_csv, key)) - msg = self.run_cli_cmd('property list --long -f json %s %s' - % (switch, targets_csv)) - err_msg = self._check_property_values(key, value, msg, targets) - self.assertTrue('missing' in err_msg, - 'clear failed, property still in output: ' + - '%s, %s (%s %s)' - % (key, value, switch, targets_csv)) - bad_path = self._is_size_ok(sizes, 0, '=', 3) - self.assertIsNone(bad_path, 'Size of file %s is ' % bad_path + - 'different from initial size ' - '(%s %s %s)' - % (switch, targets_csv, str(sizes))) - - # test setting empty string - value = '""' - self.run_cli_cmd('property set %s %s %s %s' - % (switch, targets_csv, key, value)) - msg = self.run_cli_cmd('property list --all -f json %s %s' - % (switch, targets_csv)) - err_msg = self._check_property_values(key, value, msg, targets) - self.assertTrue('missing' in err_msg, - 'clear failed, property still in output: ' + - '%s, %s (%s %s)' - % (key, value, switch, targets_csv)) - self.run_cli_cmd('property clear %s %s %s' - % (switch, targets_csv, key)) - - def _check_property_values(self, key, value, json_str, - targets=[]): - """Verify cli data against model data""" - error_msg = '' - props = json.loads(json_str.strip()) - if not targets: - # simple property check - ok = False - for prop in props: - if (prop['Property Name'] == key and - prop['Property Value'] == value): - ok = True - if not ok: - error_msg = '%s:%s is missing in __GLOBAL__' - else: - target_map = {} - for target in targets: - target_map[target] = 'missing' - for prop in props: - if 'Group' in prop and prop['Group'] == target: - if (prop['Property Name'] == key and - prop['Property Value'] == value): - target_map[target] = 'ok' - elif 'Host' in prop and prop['Host'] == target: - if (prop['Property Name'] == key and - prop['Property Value'] == value): - target_map[target] = 'ok' - for target, state in target_map.items(): - if state == 'missing': - error_msg += ('%s:%s is missing in %s\n output:%s\n' - % (key, value, target, json_str)) - return error_msg - - def _is_size_ok(self, sizes, idx0, comparator, idx1): - bad_path = None - for path, path_sizes in sizes.items(): - if idx1 > len(path_sizes) - 1: - # get new sizes - sizes[path].append(os.path.getsize(path)) - if comparator == '=': - if sizes[path][idx0] != sizes[path][idx1]: - bad_path = path - break - elif comparator == '<': - if sizes[path][idx0] >= sizes[path][idx1]: - bad_path = path - break - return bad_path - - def _override_test(self, json_str, key, value, ovr_string, - host=None, group=None): - error_msg = '' - props = json.loads(json_str.strip()) - for prop in props: - if group is not None: - if prop['Group'] == group: - error_msg = self._check_override_value(prop, key, - value, ovr_string) - elif host is not None: - if prop['Host'] == host: - error_msg = self._check_override_value(prop, key, - value, ovr_string) - else: - error_msg = self._check_override_value(prop, key, - value, ovr_string) - return error_msg - - def _check_override_value(self, prop, key, value, ovr_string): - error_msg = '' - if(prop['Property Name'] == key and - prop['Property Value'] == value and - prop['OVR'] != ovr_string): - error_msg = ('override value mismatch for ' - 'key:%s value:%s ovr:%s target:%s' % - (key, value, prop['OVR'], ovr_string)) - return error_msg - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_reconfigure.py b/kolla_cli/tests/functional/test_reconfigure.py deleted file mode 100644 index c700f96..0000000 --- a/kolla_cli/tests/functional/test_reconfigure.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -from kolla_cli.api.client import ClientApi - -import unittest - -CLIENT = ClientApi() - - -class TestFunctional(KollaCliTest): - - def test_reconfigure(self): - # test will start with no hosts in the inventory - # reconfigure will throw an exception if it fails - # disable all services first as without it empty groups cause errors - enable_service_props = {} - for service in CLIENT.service_get_all(): - service_name = service.name.replace('-', '_') - enable_service_props['enable_%s' % service_name] = 'no' - CLIENT.property_set(enable_service_props) - - msg = '' - try: - job = CLIENT.reconfigure() - job.wait() - msg = job.get_console_output() - self.assertEqual(job.get_status(), 0, - 'error performing reconfigure: %s' % msg) - except Exception as e: - self.assertEqual(0, 1, - 'unexpected exception in reconfigure %s, %s' - % (e.message, msg)) - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_service.py b/kolla_cli/tests/functional/test_service.py deleted file mode 100644 index 16aef64..0000000 --- a/kolla_cli/tests/functional/test_service.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -import json -import unittest - -from kolla_cli.api.client import ClientApi -from kolla_cli.common.ansible_inventory import AnsibleInventory -from kolla_cli.common.inventory import Inventory - -CLIENT = ClientApi() - - -class TestFunctional(KollaCliTest): - - def test_service_api(self): - service1 = 'nova' - service2 = 'nova-api' - exp_services = sorted([service1, service1, service2]) - servicenames = [] - services = CLIENT.service_get(exp_services) - for service in services: - servicenames.append(service.name) - servicenames = sorted(servicenames) - self.assertEqual(exp_services, servicenames, 'services mis-match') - - def test_service_list(self): - """$ kolla-cli service list -f json - - [{"Service": "barbican", "Children": ["barbican-keystone-listener" - "barbican-worker", "barbican-api"]}, {"Service": "barbican-api" - "Children": []}, {"Service": "barbican-keystone-listener", - "Children": []}, {"Service": "barbican-worker"...] - """ - msg = self.run_cli_cmd('service list -f json') - cli_services = json.loads(msg) - ansible_inventory = AnsibleInventory() - ansible_inventory_services = [] - ansible_inventory_service_names = [] - for service in ansible_inventory.services.values(): - if service.is_supported(): - ansible_inventory_services.append(service) - ansible_inventory_service_names.append(service.name) - num_services = len(ansible_inventory_services) - self.assertEqual(num_services, len(cli_services), - '# of cli services != expected services.' + - '\n\nexpected services: %s' - % ansible_inventory_service_names + - '\n\ncli services: %s' % cli_services) - - def test_listgroups(self): - """$ kolla-cli service listgroups - - +------------------------+-------------------------+ \ - | Service | Groups | \ - +------------------------+-------------------------+ \ - | cinder | ['control', 'control2'] | \ - | cinder-api | | \ - | cinder-backup | ['storage'] | \ - | cinder-scheduler | | \ - | cinder-volume | ['storage'] | \ - | glance | ['control', 'control2'] | \ - | glance-api | | \ - | glance-registry | | \ - ... - - """ - msg = self.run_cli_cmd('service listgroups -f json') - cli_services = json.loads(msg) - - ansible_inventory = AnsibleInventory() - ansible_inventory_services = [] - ansible_inventory_service_names = [] - for service in ansible_inventory.services.values(): - if service.is_supported(): - ansible_inventory_services.append(service) - ansible_inventory_service_names.append(service.name) - num_services = len(ansible_inventory_services) - self.assertEqual(num_services, len(cli_services), - '# of cli services (%s) ' % len(cli_services) + - '!= # of expected services (%s).' % num_services + - '\n\ncli services: %s' % cli_services) - - def test_service_add_group(self): - servicename = 'cinder' - new_group = 'network' - - inventory = Inventory.load() - service = inventory.get_service(servicename) - groupnames = service.get_groupnames() - - # add new group to a service - self.run_cli_cmd('service addgroup %s %s' % (servicename, new_group)) - - msg = self.run_cli_cmd('service listgroups -f json') - cli_services = json.loads(msg) - cli_service = '' - for svc in cli_services: - if svc['Service'] == servicename: - cli_service = svc - break - self.assertNotEqual(cli_service, '', - 'service: %s, ' % servicename + - 'not found in cli_services: \n%s' - % cli_service) - cli_groups = cli_service['Groups'] - groupnames.append(new_group) - self.assertEqual(groupnames, cli_groups, - 'service: %s, ' % service + - 'expected groups: %s, ' % groupnames + - 'cli_groups: %s' % cli_groups) - - # remove that group - self.run_cli_cmd('service removegroup %s %s' % (servicename, - new_group)) - groupnames.remove(new_group) - - msg = self.run_cli_cmd('service listgroups -f json') - cli_services = json.loads(msg) - for svc in cli_services: - if svc['Service'] == servicename: - cli_service = svc - break - self.assertNotEqual(cli_service, '', - 'service: %s, ' % servicename + - 'not found in cli_services: \n%s' - % cli_service) - cli_groups = cli_service['Groups'] - expected_groups = groupnames - self.assertEqual(expected_groups, cli_groups, - 'service: %s, ' % service + - 'expected groups: %s, ' % expected_groups + - 'cli_groups: %s' % cli_groups) - - # add new group to a service which has a parent - servicename = 'glance-api' - new_group = 'control' - self.run_cli_cmd('service addgroup %s %s' % (servicename, new_group)) - - msg = self.run_cli_cmd('service listgroups -f json') - cli_services = json.loads(msg) - for svc in cli_services: - if svc['Service'] == servicename: - cli_service = svc - break - self.assertNotEqual(cli_service, '', - 'service: %s, ' % servicename + - 'not found in cli_services: \n%s' - % cli_service) - cli_groups = cli_service['Groups'] - expected_groups = ['%s' % new_group] - self.assertEqual(expected_groups, cli_groups, - 'service: %s, ' % service + - 'expected groups: %s, ' % expected_groups + - 'cli_groups: %s' % cli_groups) - - # remove that group - self.run_cli_cmd('service removegroup %s %s' % (servicename, - new_group)) - - msg = self.run_cli_cmd('service listgroups -f json') - cli_services = json.loads(msg) - for svc in cli_services: - if svc['Service'] == servicename: - cli_service = svc - break - self.assertNotEqual(cli_service, '', - 'service: %s, ' % service + - 'not found in cli_services: \n%s' - % cli_service) - cli_groups = cli_service['Groups'] - expected_groups = [] - self.assertEqual(expected_groups, cli_groups, - 'service: %s, ' % servicename + - 'expected groups: %s, ' % expected_groups + - 'cli_groups: %s' % cli_groups) - - test_group = 'testgroup' - self.run_cli_cmd('group add %s' % test_group) - self.run_cli_cmd('service addgroup cinder %s' % test_group) - self.run_cli_cmd('group remove %s' % test_group) - msg = self.run_cli_cmd('service listgroups -f json') - self.assertNotIn(test_group, msg, - 'Group: %s, still listed in services: %s' - % (test_group, msg)) - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_stop.py b/kolla_cli/tests/functional/test_stop.py deleted file mode 100644 index 92487b7..0000000 --- a/kolla_cli/tests/functional/test_stop.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -from kolla_cli.api.client import ClientApi - -import unittest - -TEST_GROUP_NAME = 'test_group' -CLIENT = ClientApi() - -NOT_KNOWN = 'Name or service not known' - - -class TestFunctional(KollaCliTest): - - def test_stop(self): - # No physical hosts in config, use a non-existent host. - # This will generate expected exceptions in all host access - # commands. - hostnames = ['test_deploy_host1'] - CLIENT.host_add(hostnames) - - # add host to a new deploy group - CLIENT.group_add([TEST_GROUP_NAME]) - group = CLIENT.group_get([TEST_GROUP_NAME])[0] - for hostname in hostnames: - group.add_host(hostname) - - # stop services, initialize server - self.log.info('Start stop #1') - job = CLIENT.stop(1, hostnames) - self._process_job(job, 'stop #1') - - self.log.info('updating various properties for the test') - - # disable services so the test is quicker - enable_service_props = {} - for service in CLIENT.service_get_all(): - service_name = service.name.replace('-', '_') - enable_service_props['enable_%s' % service_name] = 'no' - CLIENT.property_set(enable_service_props) - - # do a deploy of a limited set of services - self.log.info('Start a deployment') - job = CLIENT.deploy() - self._process_job(job, 'deploy') - - self.log.info('Start stop #2') - job = CLIENT.stop(1, hostnames) - self._process_job(job, 'stop #2') - - def _process_job(self, job, descr, expect_kill=False): - status = job.wait() - output = job.get_console_output() - self.log.info('job is complete. status: %s, err: %s' - % (status, output)) - if expect_kill: - self.assertEqual(2, status, 'Job %s does not have killed status %s' - % (descr, output)) - else: - self.assertEqual(1, status, 'Job %s ' % descr + - 'succeeded when it should have failed') - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/functional/test_support.py b/kolla_cli/tests/functional/test_support.py deleted file mode 100644 index 11f3092..0000000 --- a/kolla_cli/tests/functional/test_support.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -from kolla_cli.tests.functional.common import KollaCliTest - -import os -import shutil -import tarfile -import unittest - -from kolla_cli.api.client import ClientApi -from kolla_cli.common.utils import get_tools_path -from kolla_cli.common.utils import safe_decode - -LOGS_PREFIX = '/tmp/kolla_support_logs_' -CLIENT = ClientApi() - -LOGDIR = '/tmp/utest_kolla_logs' - - -class TestFunctional(KollaCliTest): - - def test_log_collector(self): - hostnames = ['test_host1'] - CLIENT.host_add(hostnames) - - zip_path = '' - try: - path = os.path.join(get_tools_path(), - 'log_collector.py') - - # run the log_collector tool - retval, msg = self.run_command('/usr/bin/python %s %s' - % (path, 'all')) - - # no host, this should fail - self.assertIn('error', msg.lower()) - except Exception as e: - raise e - finally: - if zip_path and os.path.exists(zip_path): - os.remove(zip_path) - - def test_log_collector_api(self): - if os.path.exists(LOGDIR): - shutil.rmtree(LOGDIR) - os.mkdir(LOGDIR) - - hostnames = ['test_host1'] - CLIENT.host_add(hostnames) - - services = CLIENT.service_get_all() - service_names = [] - for service in services: - service_names.append(service.name) - try: - for hostname in hostnames: - CLIENT.support_get_logs(service_names, safe_decode(hostname), - LOGDIR) - raise Exception('get_logs command succeeded without physical ' - 'hosts') - except Exception as e: - self.assertIn('UNREACHABLE', str(e), - 'unexpected failure in get_logs: %s' % str(e)) - finally: - if os.path.exists(LOGDIR): - shutil.rmtree(LOGDIR) - - def test_dump(self): - check_files = [ - 'kolla/etc/kolla-cli/ansible/inventory.json', - 'kolla/share/ansible/site.yml', - ] - # dump success output is: - # dump successful to /tmp/kollacli_dump_Umxu6d.tgz - dump_path = None - try: - msg = self.run_cli_cmd('dump') - self.assertIn('/', msg, 'path not found in dump output: %s' % msg) - - dump_path = '/' + msg.strip().split('/', 1)[1] - is_file = os.path.isfile(dump_path) - self.assertTrue(is_file, - 'dump file not found at %s' % dump_path) - with tarfile.open(dump_path, 'r') as tar: - file_paths = tar.getnames() - - for check_file in check_files: - self.assertIn(check_file, file_paths, - 'dump: check file: %s, not in files:\n%s' - % (check_file, file_paths)) - except Exception as e: - raise e - finally: - if dump_path and os.path.exists(dump_path): - os.remove(dump_path) - - -if __name__ == '__main__': - unittest.main() diff --git a/kolla_cli/tests/unit/__init__.py b/kolla_cli/tests/unit/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/kolla_cli/tests/unit/common.py b/kolla_cli/tests/unit/common.py deleted file mode 100644 index d4d8cc4..0000000 --- a/kolla_cli/tests/unit/common.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import testtools - -from kolla_cli.api.group import Group -from kolla_cli.api.host import Host -from kolla_cli.api.service import Service -from kolla_cli.common.ansible.job import AnsibleJob -from kolla_cli import shell - - -class KollaCliUnitTest(testtools.TestCase): - - def run_cli_command(self, command_string): - # return 0 if command succeeded, non-0 if failed - args = command_string.split() - return shell.main(args) - - def get_fake_job(self): - return AnsibleJob(None, None, None, None) - - def get_fake_host(self, hostname='foo'): - return Host(hostname) - - def get_fake_group(self, groupname='group1', servicenames=[], - hostnames=[]): - return Group(groupname, servicenames, hostnames) - - def get_fake_service(self, servicename='service1', parentnames=[], - childnames=[], groupnames=[]): - return Service(servicename, parentnames, childnames, groupnames) diff --git a/kolla_cli/tests/unit/test_deploy_cmd.py b/kolla_cli/tests/unit/test_deploy_cmd.py deleted file mode 100644 index ca662e3..0000000 --- a/kolla_cli/tests/unit/test_deploy_cmd.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.deploy') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_deploy(self, _, mock_get_status, mock_deploy): - mock_get_status.return_value = 0 - mock_deploy.return_value = self.get_fake_job() - ret = self.run_cli_command('action deploy') - self.assertEqual(ret, 0) - mock_deploy.assert_called_once_with(None, False, 1, None) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.deploy') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_deploy_with_services(self, _, mock_get_status, mock_deploy): - mock_get_status.return_value = 0 - mock_deploy.return_value = self.get_fake_job() - services = ['foo', 'bar'] - ret = self.run_cli_command( - 'action deploy --services {}'.format(','.join(services))) - self.assertEqual(ret, 0) - mock_deploy.assert_called_once_with(None, False, 1, services) diff --git a/kolla_cli/tests/unit/test_genconfig_cmd.py b/kolla_cli/tests/unit/test_genconfig_cmd.py deleted file mode 100644 index aebbcdf..0000000 --- a/kolla_cli/tests/unit/test_genconfig_cmd.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.genconfig') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_genconfig(self, _, mock_get_status, mock_genconfig): - mock_get_status.return_value = 0 - mock_genconfig.return_value = self.get_fake_job() - ret = self.run_cli_command('action genconfig') - self.assertEqual(ret, 0) - mock_genconfig.assert_called_once_with(1, [], []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.genconfig') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_genconfig_with_hosts(self, - _, - mock_get_status, - mock_genconfig): - mock_get_status.return_value = 0 - mock_genconfig.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - ret = self.run_cli_command( - 'action genconfig --hosts {hosts}'.format( - hosts=','.join(hostnames))) - self.assertEqual(ret, 0) - mock_genconfig.assert_called_once_with(1, hostnames, []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.genconfig') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_genconfig_with_services(self, - _, - mock_get_status, - mock_genconfig): - mock_get_status.return_value = 0 - mock_genconfig.return_value = self.get_fake_job() - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action genconfig --services {services}'.format( - services=','.join(services))) - self.assertEqual(ret, 0) - mock_genconfig.assert_called_once_with(1, [], services) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.genconfig') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_genconfig_with_hosts_and_services(self, - _, - mock_get_status, - mock_genconfig): - mock_get_status.return_value = 0 - mock_genconfig.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action genconfig --hosts {hosts} --services {services}'.format( - hosts=','.join(hostnames), services=','.join(services))) - self.assertEqual(ret, 0) - mock_genconfig.assert_called_once_with(1, hostnames, services) diff --git a/kolla_cli/tests/unit/test_group_cmd.py b/kolla_cli/tests/unit/test_group_cmd.py deleted file mode 100644 index 7cb6769..0000000 --- a/kolla_cli/tests/unit/test_group_cmd.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.client.ClientApi.group_add') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_group_add(self, _, mock_add): - groupname = 'group1' - ret = self.run_cli_command('group add %s' % groupname) - self.assertEqual(ret, 0) - mock_add.assert_called_once_with([groupname]) - - @mock.patch('kolla_cli.api.client.ClientApi.group_remove') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_group_remove(self, _, mock_remove): - groupname = 'group1' - ret = self.run_cli_command('group remove %s' % groupname) - self.assertEqual(ret, 0) - mock_remove.assert_called_once_with([groupname]) - - @mock.patch('kolla_cli.api.client.ClientApi.group_get_all') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_group_listhosts(self, _, mock_group_get_all): - # list all groups and their hosts - hostname = 'foo' - groupname = 'group1' - fake_group = self.get_fake_group(groupname, hostnames=[hostname]) - mock_group_get_all.return_value = [fake_group] - ret = self.run_cli_command('group listhosts') - self.assertEqual(ret, 0) - mock_group_get_all.assert_called_once_with() - - @mock.patch('kolla_cli.api.group.Group.add_host') - @mock.patch('kolla_cli.api.client.ClientApi.group_get') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_group_addhost(self, _, mock_group_get, mock_group_add_host): - hostname = 'foo' - groupname = 'group1' - fake_group = self.get_fake_group(groupname) - mock_group_get.return_value = [fake_group] - ret = self.run_cli_command('group addhost %s %s' - % (groupname, hostname)) - self.assertEqual(ret, 0) - mock_group_get.assert_called_once_with([groupname]) - mock_group_add_host.assert_called_once_with(hostname) - - @mock.patch('kolla_cli.api.group.Group.remove_host') - @mock.patch('kolla_cli.api.client.ClientApi.group_get') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_group_removehost(self, _, mock_group_get, - mock_group_remove_host): - hostname = 'foo' - groupname = 'group1' - fake_group = self.get_fake_group(groupname, hostnames=[hostname]) - mock_group_get.return_value = [fake_group] - ret = self.run_cli_command('group removehost %s %s' - % (groupname, hostname)) - self.assertEqual(ret, 0) - mock_group_get.assert_called_once_with([groupname]) - mock_group_remove_host.assert_called_once_with(hostname) - - @mock.patch('kolla_cli.api.client.ClientApi.group_get_all') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_group_listservices(self, _, mock_group_get_all): - # list all groups and their services - servicename = 'service1' - groupname = 'group1' - fake_group = self.get_fake_group(groupname, - servicenames=[servicename]) - mock_group_get_all.return_value = [fake_group] - ret = self.run_cli_command('group listservices') - self.assertEqual(ret, 0) - mock_group_get_all.assert_called_once_with() diff --git a/kolla_cli/tests/unit/test_host_cmd.py b/kolla_cli/tests/unit/test_host_cmd.py deleted file mode 100644 index cc30d3e..0000000 --- a/kolla_cli/tests/unit/test_host_cmd.py +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.client.ClientApi.host_add') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_host_add(self, _, mock_add): - hostname = 'foo' - ret = self.run_cli_command('host add %s' % hostname) - self.assertEqual(ret, 0) - mock_add.assert_called_once_with([hostname]) - - @mock.patch('kolla_cli.api.client.ClientApi.host_remove') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_host_remove(self, _, mock_remove): - hostname = 'foo' - ret = self.run_cli_command('host remove %s' % hostname) - self.assertEqual(ret, 0) - mock_remove.assert_called_once_with([hostname]) - - @mock.patch('kolla_cli.api.client.ClientApi.host_get_all') - @mock.patch('kolla_cli.api.client.ClientApi.host_get') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_host_list(self, _, mock_get, mock_get_all): - # get all hosts - mock_get_all.return_value = [] - ret = self.run_cli_command('host list') - self.assertEqual(ret, 0) - mock_get_all.assert_called_once_with() - - # get a specific host - hostname = 'foo' - mock_get.return_value = [] - ret = self.run_cli_command('host list %s' % hostname) - self.assertEqual(ret, 0) - mock_get.assert_called_once_with([hostname]) - - @mock.patch('kolla_cli.commands.host.HostDestroy._is_ok_to_delete_data', - return_value='y') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.api.client.ClientApi.host_get_all') - @mock.patch('kolla_cli.api.client.ClientApi.host_destroy') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_host_destroy(self, _, mock_destroy, mock_get_all, - mock_get_status, mock_prompt): - hostname = 'foo' - mock_get_all.return_value = [self.get_fake_host(hostname)] - mock_destroy.return_value = self.get_fake_job() - mock_get_status.return_value = 0 - - # default destroy hostname - ret = self.run_cli_command('host destroy %s' % hostname) - self.assertEqual(ret, 0) - mock_destroy.assert_called_once_with([hostname], 'kill', 1, - False, False) - # destroy all - mock_destroy.reset_mock() - ret = self.run_cli_command('host destroy all') - self.assertEqual(ret, 0) - mock_destroy.assert_called_once_with([hostname], 'kill', 1, - False, False) - # destroy --stop - mock_destroy.reset_mock() - ret = self.run_cli_command('host destroy %s --stop' % hostname) - self.assertEqual(ret, 0) - mock_destroy.assert_called_once_with([hostname], 'stop', 1, - False, False) - # destroy --includedata - mock_destroy.reset_mock() - ret = self.run_cli_command('host destroy %s --includedata' % hostname) - self.assertEqual(ret, 0) - mock_destroy.assert_called_once_with([hostname], 'kill', 1, - True, False) - - # destroy --removeimages - mock_destroy.reset_mock() - ret = self.run_cli_command('host destroy %s --removeimages' - % hostname) - self.assertEqual(ret, 0) - mock_destroy.assert_called_once_with([hostname], 'kill', 1, - False, True) - - @mock.patch('kolla_cli.commands.host.LOG.info') - @mock.patch('kolla_cli.api.client.ClientApi.host_get_all') - @mock.patch('kolla_cli.api.client.ClientApi.host_ssh_check') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_host_ssh_check(self, _, mock_ssh_check, mock_get_all, mock_log): - hostname = 'foo' - check_ok_response = {hostname: {'success': True}} - check_bad_response = {hostname: {'success': False, 'msg': 'FAILED'}} - mock_get_all.return_value = [self.get_fake_host(hostname)] - - # host check hostname (success) - mock_ssh_check.return_value = check_ok_response - ret = self.run_cli_command('host check %s' % hostname) - self.assertEqual(ret, 0) - mock_ssh_check.assert_called_once_with([hostname]) - mock_log.assert_called_once_with('Host %s: success ' % hostname) - - # host check all (success) - mock_ssh_check.reset_mock() - mock_log.reset_mock() - mock_ssh_check.return_value = check_ok_response - ret = self.run_cli_command('host check all') - self.assertEqual(ret, 0) - mock_ssh_check.assert_called_once_with([hostname]) - mock_log.assert_called_once_with('Host %s: success ' % hostname) - - # host check hostname (fail) - mock_ssh_check.reset_mock() - mock_log.reset_mock() - mock_ssh_check.return_value = check_bad_response - ret = self.run_cli_command('host check %s' % hostname) - self.assertEqual(ret, 1) - mock_ssh_check.assert_called_once_with([hostname]) - mock_log.assert_called_once_with('Host %s: failed- FAILED' % hostname) - - @mock.patch('kolla_cli.commands.host.HostSetup._get_yml_data') - @mock.patch('getpass.getpass') - @mock.patch('kolla_cli.commands.host.ClientApi.host_ssh_check') - @mock.patch('kolla_cli.commands.host.ClientApi.host_setup') - @mock.patch('kolla_cli.api.client.ClientApi.host_get_all') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_host_setup(self, _, mock_get_all, mock_setup, mock_ssh_check, - mock_passwd, mock_yml): - password = 'PASSWORD' - hostname = 'foo' - mock_get_all.return_value = [self.get_fake_host(hostname)] - mock_passwd.return_value = password - - # single host setup (host not yet setup) - mock_ssh_check.return_value = {hostname: {'success': False}} - ret = self.run_cli_command('host setup %s' % hostname) - self.assertEqual(ret, 0) - mock_ssh_check.assert_called_once_with([hostname]) - mock_setup.assert_called_once_with({hostname: {'password': password}}) - - # single host setup --insecure (host already setup) - mock_ssh_check.reset_mock() - mock_setup.reset_mock() - mock_ssh_check.return_value = {hostname: {'success': True}} - ret = self.run_cli_command('host setup %s --insecure %s' - % (hostname, password)) - self.assertEqual(ret, 0) - mock_ssh_check.assert_called_once_with([hostname]) - mock_setup.assert_not_called() - - # multi-host setup - mock_ssh_check.reset_mock() - mock_setup.reset_mock() - fake_path = '/bogus' - mock_yml.return_value = {hostname: {'password': password}} - ret = self.run_cli_command('host setup --file %s' % fake_path) - self.assertEqual(ret, 0) - mock_setup.assert_called_once_with({hostname: {'password': password}}) - mock_yml.assert_called_once_with(fake_path) - mock_ssh_check.assert_not_called() diff --git a/kolla_cli/tests/unit/test_prechecks_cmd.py b/kolla_cli/tests/unit/test_prechecks_cmd.py deleted file mode 100644 index 6ee4413..0000000 --- a/kolla_cli/tests/unit/test_prechecks_cmd.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.prechecks') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_prechecks(self, _, mock_get_status, mock_prechecks): - mock_get_status.return_value = 0 - mock_prechecks.return_value = self.get_fake_job() - ret = self.run_cli_command('action prechecks') - self.assertEqual(ret, 0) - mock_prechecks.assert_called_once_with(1, [], []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.prechecks') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_prechecks_with_hosts(self, _, mock_get_status, mock_prechecks): - mock_get_status.return_value = 0 - mock_prechecks.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - ret = self.run_cli_command( - 'action prechecks --hosts {hosts}'.format( - hosts=','.join(hostnames))) - self.assertEqual(ret, 0) - mock_prechecks.assert_called_once_with(1, hostnames, []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.prechecks') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_prechecks_with_services(self, _, mock_get_status, mock_prechecks): - mock_get_status.return_value = 0 - mock_prechecks.return_value = self.get_fake_job() - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action prechecks --service {services}'.format( - services=','.join(services))) - self.assertEqual(ret, 0) - mock_prechecks.assert_called_once_with(1, [], services) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.prechecks') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_prechecks_with_hosts_and_services(self, _, mock_get_status, - mock_prechecks): - mock_get_status.return_value = 0 - mock_prechecks.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action prechecks --hosts {hosts} --service {services}'.format( - hosts=','.join(hostnames), services=','.join(services))) - self.assertEqual(ret, 0) - mock_prechecks.assert_called_once_with(1, hostnames, services) diff --git a/kolla_cli/tests/unit/test_pull_cmd.py b/kolla_cli/tests/unit/test_pull_cmd.py deleted file mode 100644 index 579b518..0000000 --- a/kolla_cli/tests/unit/test_pull_cmd.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.pull') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_pull(self, _, mock_get_status, mock_pull): - mock_get_status.return_value = 0 - mock_pull.return_value = self.get_fake_job() - ret = self.run_cli_command('action pull') - self.assertEqual(ret, 0) - mock_pull.assert_called_once_with(1, [], []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.pull') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_pull_with_hosts(self, _, - mock_get_status, - mock_pull): - mock_get_status.return_value = 0 - mock_pull.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - ret = self.run_cli_command( - 'action pull --hosts {hosts}'.format( - hosts=','.join(hostnames))) - self.assertEqual(ret, 0) - mock_pull.assert_called_once_with(1, hostnames, []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.pull') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_pull_with_services(self, _, - mock_get_status, - mock_pull): - mock_get_status.return_value = 0 - mock_pull.return_value = self.get_fake_job() - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action pull --services {services}'.format( - services=','.join(services))) - self.assertEqual(ret, 0) - mock_pull.assert_called_once_with(1, [], services) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.pull') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_pull_with_hosts_and_services(self, _, - mock_get_status, - mock_pull): - mock_get_status.return_value = 0 - mock_pull.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action pull --hosts {hosts} --services {services}'.format( - hosts=','.join(hostnames), services=','.join(services))) - self.assertEqual(ret, 0) - mock_pull.assert_called_once_with(1, hostnames, services) diff --git a/kolla_cli/tests/unit/test_reconfigure_cmd.py b/kolla_cli/tests/unit/test_reconfigure_cmd.py deleted file mode 100644 index 4ab9c77..0000000 --- a/kolla_cli/tests/unit/test_reconfigure_cmd.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.reconfigure') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_reconfigure(self, _, mock_get_status, mock_reconfigure): - mock_get_status.return_value = 0 - mock_reconfigure.return_value = self.get_fake_job() - ret = self.run_cli_command('action reconfigure') - self.assertEqual(ret, 0) - mock_reconfigure.assert_called_once_with(1, [], []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.reconfigure') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_reconfigure_with_hosts(self, - _, - mock_get_status, - mock_reconfigure): - mock_get_status.return_value = 0 - mock_reconfigure.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - ret = self.run_cli_command( - 'action reconfigure --hosts {hosts}'.format( - hosts=','.join(hostnames))) - self.assertEqual(ret, 0) - mock_reconfigure.assert_called_once_with(1, hostnames, []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.reconfigure') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_reconfigure_with_services(self, - _, - mock_get_status, - mock_reconfigure): - mock_get_status.return_value = 0 - mock_reconfigure.return_value = self.get_fake_job() - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action reconfigure --services {services}'.format( - services=','.join(services))) - self.assertEqual(ret, 0) - mock_reconfigure.assert_called_once_with(1, [], services) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.reconfigure') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_reconfigure_with_hosts_and_services(self, - _, - mock_get_status, - mock_reconfigure): - mock_get_status.return_value = 0 - mock_reconfigure.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action reconfigure --hosts {hosts} --services {services}'.format( - hosts=','.join(hostnames), services=','.join(services))) - self.assertEqual(ret, 0) - mock_reconfigure.assert_called_once_with(1, hostnames, services) diff --git a/kolla_cli/tests/unit/test_service_cmd.py b/kolla_cli/tests/unit/test_service_cmd.py deleted file mode 100644 index 2d36ecb..0000000 --- a/kolla_cli/tests/unit/test_service_cmd.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - - @mock.patch('cliff.lister.Lister.produce_output') - @mock.patch('kolla_cli.api.client.ClientApi.service_get_all') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_service_list(self, _, mock_service_get_all, mock_cliff): - # list all services, check that output is sorted properly - servicename1 = 'service1' - servicename2 = 'service2' - childnames = ['child2', 'child1'] - fake_service1 = self.get_fake_service(servicename1, - childnames=childnames) - fake_service2 = self.get_fake_service(servicename2, - childnames=childnames) - mock_service_get_all.return_value = [fake_service2, fake_service1] - ret = self.run_cli_command('service list') - self.assertEqual(ret, 0) - mock_service_get_all.assert_called_once_with() - - expected_childnames = '[child1,child2]' - mock_cliff.assert_called_once_with( - mock.ANY, ('Service', 'Children'), - [(servicename1, expected_childnames), - (servicename2, expected_childnames) - ]) - - @mock.patch('kolla_cli.api.client.ClientApi.service_get_all') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_service_grouplist(self, _, mock_service_get_all): - # list all services with their groups - servicename = 'service1' - groupname = 'group1' - fake_service = self.get_fake_service(servicename, - groupnames=[groupname]) - mock_service_get_all.return_value = [fake_service] - ret = self.run_cli_command('service listgroups') - self.assertEqual(ret, 0) - mock_service_get_all.assert_called_once_with() - - @mock.patch('kolla_cli.api.group.Group.add_service') - @mock.patch('kolla_cli.api.client.ClientApi.group_get') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_service_addgroup(self, _, mock_group_get, - mock_group_add_service): - servicename = 'service1' - groupname = 'group1' - fake_group = self.get_fake_group(groupname) - mock_group_get.return_value = [fake_group] - ret = self.run_cli_command('service addgroup %s %s' - % (servicename, groupname)) - self.assertEqual(ret, 0) - mock_group_get.assert_called_once_with([groupname]) - mock_group_add_service.assert_called_once_with(servicename) - - @mock.patch('kolla_cli.api.group.Group.remove_service') - @mock.patch('kolla_cli.api.client.ClientApi.group_get') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_service_removegroup(self, _, mock_group_get, - mock_group_remove_service): - servicename = 'service1' - groupname = 'group1' - fake_group = self.get_fake_group(groupname, - servicenames=[servicename]) - mock_group_get.return_value = [fake_group] - ret = self.run_cli_command('service removegroup %s %s' - % (servicename, groupname)) - self.assertEqual(ret, 0) - mock_group_get.assert_called_once_with([groupname]) - mock_group_remove_service.assert_called_once_with(servicename) diff --git a/kolla_cli/tests/unit/test_stop_cmd.py b/kolla_cli/tests/unit/test_stop_cmd.py deleted file mode 100644 index 499f7cc..0000000 --- a/kolla_cli/tests/unit/test_stop_cmd.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.stop') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_stop(self, _, mock_get_status, mock_stop): - mock_get_status.return_value = 0 - mock_stop.return_value = self.get_fake_job() - ret = self.run_cli_command('action stop') - self.assertEqual(ret, 0) - mock_stop.assert_called_once_with(1, [], []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.stop') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_stop_with_hosts(self, _, mock_get_status, mock_stop): - mock_get_status.return_value = 0 - mock_stop.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - ret = self.run_cli_command('action stop --hosts {hosts}'.format( - hosts=','.join(hostnames))) - self.assertEqual(ret, 0) - mock_stop.assert_called_once_with(1, hostnames, []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.stop') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_stop_with_services(self, _, mock_get_status, mock_stop): - mock_get_status.return_value = 0 - mock_stop.return_value = self.get_fake_job() - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action stop --service {services}'.format( - services=','.join(services))) - self.assertEqual(ret, 0) - mock_stop.assert_called_once_with(1, [], services) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.stop') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_stop_with_hosts_and_services(self, _, mock_get_status, - mock_stop): - mock_get_status.return_value = 0 - mock_stop.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action stop --hosts {hosts} --service {services}'.format( - hosts=','.join(hostnames), services=','.join(services))) - self.assertEqual(ret, 0) - mock_stop.assert_called_once_with(1, hostnames, services) diff --git a/kolla_cli/tests/unit/test_upgrade_cmd.py b/kolla_cli/tests/unit/test_upgrade_cmd.py deleted file mode 100644 index d05272a..0000000 --- a/kolla_cli/tests/unit/test_upgrade_cmd.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2018 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from unittest import mock - -from kolla_cli.tests.unit.common import KollaCliUnitTest - - -class TestUnit(KollaCliUnitTest): - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.upgrade') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_upgrade(self, _, mock_get_status, mock_upgrade): - mock_get_status.return_value = 0 - mock_upgrade.return_value = self.get_fake_job() - ret = self.run_cli_command('action upgrade') - self.assertEqual(ret, 0) - mock_upgrade.assert_called_once_with(1, [], []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.upgrade') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_upgrade_with_hosts(self, _, mock_get_status, mock_upgrade): - mock_get_status.return_value = 0 - mock_upgrade.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - ret = self.run_cli_command( - 'action upgrade --hosts {hosts}'.format( - hosts=','.join(hostnames))) - self.assertEqual(ret, 0) - mock_upgrade.assert_called_once_with(1, hostnames, []) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.upgrade') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_upgrade_with_services(self, _, mock_get_status, mock_upgrade): - mock_get_status.return_value = 0 - mock_upgrade.return_value = self.get_fake_job() - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action upgrade --service {services}'.format( - services=','.join(services))) - self.assertEqual(ret, 0) - mock_upgrade.assert_called_once_with(1, [], services) - - @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.upgrade') - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_upgrade_with_hosts_and_services(self, _, mock_get_status, - mock_upgrade): - mock_get_status.return_value = 0 - mock_upgrade.return_value = self.get_fake_job() - hostnames = ['host1', 'host2'] - services = ['service1', 'service2'] - ret = self.run_cli_command( - 'action upgrade --hosts {hosts} --service {services}'.format( - hosts=','.join(hostnames), services=','.join(services))) - self.assertEqual(ret, 0) - mock_upgrade.assert_called_once_with(1, hostnames, services) diff --git a/lower-constraints.txt b/lower-constraints.txt deleted file mode 100644 index 7d3803e..0000000 --- a/lower-constraints.txt +++ /dev/null @@ -1,102 +0,0 @@ -alabaster==0.7.10 -ansible==2.5.0 -appdirs==1.4.3 -asn1crypto==0.24.0 -bandit==1.1.0 -bashate==0.5.1 -beautifulsoup4==4.6.0 -certifi==2018.1.18 -cffi==1.11.5 -chardet==3.0.4 -cliff==2.11.0 -cliff-tablib==2.0 -cmd2==0.8.1 -coverage==4.0 -cryptography==2.1 -debtcollector==1.19.0 -decorator==4.2.1 -deprecation==2.0 -doc8==0.6.0 -docker-pycreds==0.2.2 -docker==2.4.2 -docutils==0.14 -dogpile.cache==0.6.5 -dulwich==0.19.0 -extras==1.0.0 -fixtures==3.0.0 -gitdb2==2.0.3 -GitPython==2.1.8 -idna==2.6 -imagesize==1.0.0 -iso8601==0.1.12 -Jinja2==2.10 -jmespath==0.9.3 -jsonpatch==1.21 -jsonpickle==0.9 -jsonpointer==2.0 -jsonschema==2.6.0 -keystoneauth1==3.4.0 -linecache2==1.0.0 -MarkupSafe==1.0 -monotonic==1.4 -mox3==0.25.0 -mypy==0.600 -msgpack==0.5.6 -munch==2.2.0 -netaddr==0.7.18 -netifaces==0.10.6 -openstackdocstheme==1.18.1 -openstacksdk==0.12.0 -os-client-config==1.29.0 -os-service-types==1.2.0 -osc-lib==1.10.0 -oslo.config==5.2.0 -oslo.context==2.20.0 -oslo.i18n==3.20.0 -oslo.log==3.36.0 -oslo.serialization==2.25.0 -oslo.utils==3.33.0 -oslotest==3.2.0 -packaging==17.1 -paramiko==2.6.0 -pbr==2.0.0 -prettytable==0.7.1 -pycparser==2.18 -Pygments==2.2.0 -pyinotify==0.9.6 -pyOpenSSL==17.5.0 -pyparsing==2.2.0 -pyperclip==1.6.0 -python-ceilometerclient==2.5.0 -python-dateutil==2.7.0 -python-glanceclient==2.9.1 -python-keystoneclient==3.15.0 -python-mimeparse==1.6.0 -python-neutronclient==6.7.0 -python-novaclient==10.1.0 -python-openstackclient==3.12.0 -python-subunit==1.2.0 -pytz==2013.6 -PyYAML==3.12 -reno==2.5.0 -requests==2.18.4 -requestsexceptions==1.4.0 -restructuredtext-lint==1.1.3 -rfc3986==1.2.0 -setuptools==21.0.0 -simplejson==3.13.2 -smmap2==2.0.3 -snowballstemmer==1.2.1 -Sphinx==1.6.2 -sphinxcontrib-websupport==1.0.1 -stevedore==1.28.0 -stestr==2.0.0 -testscenarios==0.4 -testtools==2.2.0 -traceback2==1.4.0 -typing==3.6.6 -unittest2==1.1.0 -urllib3==1.22 -warlock==1.3.0 -websocket-client==0.47.0 -wrapt==1.10.11 diff --git a/releasenotes/notes/add-reno-f5e9ff4d9ccfa716.yaml b/releasenotes/notes/add-reno-f5e9ff4d9ccfa716.yaml deleted file mode 100644 index a7cce39..0000000 --- a/releasenotes/notes/add-reno-f5e9ff4d9ccfa716.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Start using reno. diff --git a/releasenotes/notes/deprecate-in-ussuri-cycle-df7341b2a1e90997.yaml b/releasenotes/notes/deprecate-in-ussuri-cycle-df7341b2a1e90997.yaml deleted file mode 100644 index b0732fc..0000000 --- a/releasenotes/notes/deprecate-in-ussuri-cycle-df7341b2a1e90997.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -prelude: > - Kolla CLI is deprecated in the Ussuri cycle due to general lack of interest. - The deliverable is expected to leave OpenStack governance in the next - (Victoria) cycle. If you use this project and are able to help support it, - please contact the Kolla team. diff --git a/releasenotes/notes/drop-py-2-7-311423474c63c9c5.yaml b/releasenotes/notes/drop-py-2-7-311423474c63c9c5.yaml deleted file mode 100644 index d483927..0000000 --- a/releasenotes/notes/drop-py-2-7-311423474c63c9c5.yaml +++ /dev/null @@ -1,5 +0,0 @@ -upgrade: - - | - Python 2.7 support has been dropped. Last release of kolla-cli - to support py2.7 is OpenStack Train. The minimum version of Python now - supported by kolla-cli is Python 3.6. diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index a2cb225..0000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,189 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - -# -- Path setup -------------------------------------------------------------- - -# 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. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = u'kolla-cli' -copyright = u'2019, Kolla developers' -author = u'Kolla-cli developers' - -# The short X.Y version -version = u'1.0' -# The full version, including alpha/beta/rc tags -release = u'1.0' - - -# -- 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 = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'native' - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom 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'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'KollacliReleaseNotesdoc' - - -# -- 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': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# 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 = [ - (master_doc, 'kolla.tex', u'kolla Documentation', - u'Kolla developers', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'kolla', u'kolla Documentation', - [author], 1) -] - - -# -- 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 = [ - (master_doc, 'kolla', u'kolla Documentation', - author, 'kolla', 'One line description of project.', - 'Miscellaneous'), -] - - -# -- Options for Epub output ------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = project - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -# -# epub_identifier = '' - -# A unique identification for the text. -# -# epub_uid = '' - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index 5958ed9..0000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. kolla documentation master file, created by - sphinx-quickstart on Tue Aug 6 14:08:15 2019. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Kolla-cli Release Notes documentation -================================================ - -.. toctree:: - :maxdepth: 2 - - unreleased - ussuri - train - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`search` diff --git a/releasenotes/source/train.rst b/releasenotes/source/train.rst deleted file mode 100644 index 5839003..0000000 --- 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 875030f..0000000 --- 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 e21e50e..0000000 --- a/releasenotes/source/ussuri.rst +++ /dev/null @@ -1,6 +0,0 @@ -=========================== -Ussuri Series Release Notes -=========================== - -.. release-notes:: - :branch: stable/ussuri diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 106d350..0000000 --- a/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -cliff>=2.11.0 # Apache-2.0 -cliff-tablib>=2.0 # Apache-2.0 -docker>=2.4.2 # Apache-2.0 -jsonpickle>=0.9 # BSD -oslo.i18n>=3.20.0 # Apache-2.0 -paramiko>=2.6.0 # LGPL -pbr!=2.1.0,>=2.0.0 # Apache-2.0 -docker>=2.4.2 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 0665291..0000000 --- a/setup.cfg +++ /dev/null @@ -1,73 +0,0 @@ -[metadata] -name = kolla-cli -summary = Command Line Interface for Kolla-Ansible -description-file = - README.rst -author = OpenStack -author-email = openstack-discuss@lists.openstack.org -home-page = https://docs.openstack.org/kolla-cli/latest/ -python-requires = >=3.6 -license = Apache License, Version 2.0 -classifier = - Environment :: OpenStack - Intended Audience :: Developers - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: Implementation :: CPython - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - -[files] -packages = - kolla_cli - -[entry_points] -console_scripts = - kolla-cli = kolla_cli.shell:main - -kolla.cli = - action_check = kolla_cli.commands.kolla_action:Check - action_deploy = kolla_cli.commands.kolla_action:Deploy - action_genconfig = kolla_cli.commands.kolla_action:Genconfig - action_prechecks = kolla_cli.commands.kolla_action:Prechecks - action_postdeploy = kolla_cli.commands.kolla_action:PostDeploy - action_pull = kolla_cli.commands.kolla_action:Pull - action_reconfigure = kolla_cli.commands.kolla_action:Reconfigure - action_stop = kolla_cli.commands.kolla_action:Stop - action_upgrade = kolla_cli.commands.kolla_action:Upgrade - certificate_init = kolla_cli.commands.kolla_action:CertificateInit - config_reset = kolla_cli.commands.config:ConfigReset - config_import = kolla_cli.commands.config:ConfigImport - dump = kolla_cli.commands.support:Dump - getdeploy = kolla_cli.commands.mode:Getdeploy - group_add = kolla_cli.commands.group:GroupAdd - group_addhost = kolla_cli.commands.group:GroupAddhost - group_list = kolla_cli.commands.group:GroupList - group_listhosts = kolla_cli.commands.group:GroupListhosts - group_listservices = kolla_cli.commands.group:GroupListservices - group_remove = kolla_cli.commands.group:GroupRemove - group_removehost = kolla_cli.commands.group:GroupRemovehost - host_add = kolla_cli.commands.host:HostAdd - host_check = kolla_cli.commands.host:HostCheck - host_destroy = kolla_cli.commands.host:HostDestroy - host_list = kolla_cli.commands.host:HostList - host_remove = kolla_cli.commands.host:HostRemove - host_setup = kolla_cli.commands.host:HostSetup - password_clear = kolla_cli.commands.password:PasswordClear - password_init = kolla_cli.commands.password:PasswordInit - password_list = kolla_cli.commands.password:PasswordList - password_set = kolla_cli.commands.password:PasswordSet - password_setkey = kolla_cli.commands.password:PasswordSetKey - property_clear = kolla_cli.commands.property:PropertyClear - property_list = kolla_cli.commands.property:PropertyList - property_set = kolla_cli.commands.property:PropertySet - service_addgroup = kolla_cli.commands.service:ServiceAddGroup - service_list = kolla_cli.commands.service:ServiceList - service_listgroups = kolla_cli.commands.service:ServiceListGroups - service_removegroup = kolla_cli.commands.service:ServiceRemoveGroup - setdeploy = kolla_cli.commands.mode:Setdeploy diff --git a/setup.py b/setup.py deleted file mode 100755 index cd35c3c..0000000 --- a/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import setuptools - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 957d473..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,20 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -# Hacking already pins down pep8, pyflakes and flake8 - -hacking>=3.0.1,<3.1.0 # Apache-2.0 - -ansible>=2.5.0 -# security linter -bandit>=1.1.0,<1.6.0 # Apache-2.0 -coverage>=4.0 -doc8>=0.6.0 # Apache-2.0 -fixtures>=3.0.0 -mypy>=0.6 -oslo.utils>=3.33.0 # Apache-2.0 -oslotest>=3.2.0 # Apache-2.0 -stestr>=2.0.0 # Apache-2.0 -pexpect>=4.0.1 -testtools>=2.2.0 -typing>=3.6 diff --git a/tools/kolla_actions.py b/tools/kolla_actions.py deleted file mode 100755 index adc9795..0000000 --- a/tools/kolla_actions.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import getopt -import os -import signal -import subprocess -import sys -import yaml - -from kolla_cli.common.utils import change_password -from kolla_cli.common.utils import clear_all_passwords -from kolla_cli.common.utils import get_kolla_ansible_home -from kolla_cli.common.utils import get_kolla_cli_etc -from kolla_cli.common.utils import get_kolla_etc - - -def _init_keys(path): - cmd = 'kolla-genpwd' - if not os.path.exists(path): - raise Exception('The path %s does not exist' % path) - - cmd = ' '.join((cmd, '-p', path)) - (_, err) = subprocess.Popen(cmd, shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE).communicate() - if err: - raise Exception('Error running %s: %s' % (cmd, err)) - - -def _get_empty_keys(path): - """get empty keys - - print string with keys that have empty pwd values - """ - ok_empty = ['docker_registry_password'] - empty_keys = '' - with open(path, 'r') as f: - pwd_data = f.read() - pwds = yaml.safe_load(pwd_data) - comma = '' - if pwds: - for pwd_key, pwd_val in pwds.items(): - is_empty = False - if not pwd_val and pwd_key not in ok_empty: - is_empty = True - elif isinstance(pwd_val, dict): - if not pwd_val.get('private_key', None): - is_empty = True - elif not pwd_val.get('public_key', None): - is_empty = True - if is_empty: - empty_keys = ''.join([empty_keys, comma, pwd_key]) - comma = ',' - if empty_keys: - print(empty_keys) - - -def _print_pwd_keys(path): - keys_str = '' - prefix = '' - with open(path, 'r') as f: - pwd_data = f.read() - pwds = yaml.safe_load(pwd_data) - if pwds: - for pwd_key in pwds.keys(): - keys_str = ''.join([keys_str, prefix, pwd_key]) - prefix = ',' - print(keys_str) - - -def _password_cmd(argv): - """password command - - args for password command: - -p path # path to passwords.yaml - -k key # key of password - -v value # value of password (if not ssh keys) - -r private key value # ssh private key - -u public key value # ssh public key - -c # flag to clear the password - -l # print to stdout a csv string of the existing keys - -e # get keys of passwords with empty values - -i # init empty keys and ssh keys - """ - opts, _ = getopt.getopt(argv[2:], 'p:k:v:r:u:clei') - path = '' - pwd_key = '' - pwd_value = '' - pwd_ssh_private = '' - pwd_ssh_public = '' - clear_flag = False - list_flag = False - empty_flag = False - init_flag = False - for opt, arg in opts: - if opt == '-p': - path = arg - elif opt == '-k': - pwd_key = arg - elif opt == '-v': - pwd_value = arg - elif opt == '-r': - pwd_ssh_private = arg.replace('"', '') - elif opt == '-u': - pwd_ssh_public = arg.replace('"', '') - elif opt == '-c': - clear_flag = True - elif opt == '-l': - list_flag = True - elif opt == '-e': - empty_flag = True - elif opt == '-i': - init_flag = True - if init_flag: - # init empty keys - _init_keys(path) - elif list_flag: - # print the password keys - _print_pwd_keys(path) - elif empty_flag: - # get empty passwords - _get_empty_keys(path) - else: - # edit/clear a password - change_password(path, pwd_key, pvalue=pwd_value, - private_key=pwd_ssh_private, - public_key=pwd_ssh_public, clear=clear_flag) - - -def _job_cmd(argv): - """jobs command - - args for job command - -t # terminate action - -p pid # process pid - """ - opts, _ = getopt.getopt(argv[2:], 'tp:') - pid = None - term_flag = False - for opt, arg in opts: - if opt == '-p': - pid = arg - elif opt == '-t': - term_flag = True - - if term_flag: - try: - os.kill(int(pid), signal.SIGKILL) - except Exception as e: - raise Exception('%s, pid %s' % (str(e), pid)) - - -def _config_reset_cmd(): - """config_reset command - - args for config_reset command - - none - """ - kolla_etc = get_kolla_etc() - kolla_home = get_kolla_ansible_home() - kollacli_etc = get_kolla_cli_etc() - - group_vars_path = os.path.join(kolla_home, 'ansible/group_vars') - host_vars_path = os.path.join(kolla_home, 'ansible/host_vars') - globals_path = os.path.join(group_vars_path, '__GLOBAL__') - inventory_path = os.path.join(kollacli_etc, 'ansible/inventory.json') - - # truncate global property and inventory files - with open(globals_path, 'w') as globals_file: - globals_file.truncate() - - with open(inventory_path, 'w') as inventory_file: - inventory_file.truncate() - - # clear all passwords - clear_all_passwords() - - # nuke all files under the kolla etc base, skipping everything - # in the kolla-cli directory and the globals.yml and passwords.yml files - for dir_path, dir_names, file_names in os.walk(kolla_etc, topdown=False): - if 'kolla-cli' not in dir_path: - for dir_name in dir_names: - if dir_name != 'kolla-cli': - os.rmdir(os.path.join(dir_path, dir_name)) - - for file_name in file_names: - if file_name == 'passwords.yml' or file_name == 'globals.yml': - continue - os.remove(os.path.join(dir_path, file_name)) - - # nuke all property files under the kolla-ansible base other than - # all.yml and the global property file which we truncate above - for dir_path, _, file_names in os.walk(group_vars_path): - for file_name in file_names: - if (file_name != '__GLOBAL__' and - file_name != 'all.yml'): - os.remove(os.path.join(dir_path, file_name)) - - for dir_path, _, file_names in os.walk(host_vars_path): - for file_name in file_names: - os.remove(os.path.join(dir_path, file_name)) - - -def main(): - """perform actions on behalf of kolla user - - sys.argv: - sys.argv[1] # command - - Supported commands: - - password - - job - - config_reset - """ - if len(sys.argv) <= 1: - raise Exception('Invalid number of parameters') - - command = sys.argv[1] - if command == 'password': - _password_cmd(sys.argv) - elif command == 'job': - _job_cmd(sys.argv) - elif command == 'config_reset': - _config_reset_cmd() - else: - raise Exception('Invalid command %s' % command) - - -if __name__ == '__main__': - main() diff --git a/tools/log_collector.py b/tools/log_collector.py deleted file mode 100755 index d9833c2..0000000 --- a/tools/log_collector.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python -# Copyright(c) 2016, Oracle and/or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import shutil -import sys -import tarfile -import tempfile -import traceback - -from kolla_cli.api.client import ClientApi - -tar_file_descr = None - -CLIENT = ClientApi() - -LOGDIR = '/tmp/container_logs' - - -def get_logs_from_host(host): - try: - service_names = [] - services = CLIENT.service_get_all() - for service in services: - service_names.append(service.name) - - print('Adding container logs from host: %s' % host) - CLIENT.support_get_logs(service_names, host, LOGDIR) - except Exception as e: - print('Error getting logs on host: %s: %s' % (host, str(e))) - - -def dump_kolla_info(): - print('Getting kolla client logs') - dump_path = None - try: - dump_path = CLIENT.support_dump('/tmp') - tar_file_descr.add(dump_path) - except Exception: - print('ERROR: running dump command %s' % traceback.format_exc()) - finally: - if dump_path and os.path.exists(dump_path): - os.remove(dump_path) - - -def main(): - """collect docker logs from servers - - $ command is $ log_collector.py - """ - global tar_file_descr - - help_msg = 'Usage: log_collector.py ' - hosts = [] - if len(sys.argv) == 2: - if '-h' == sys.argv[1] or '--help' == sys.argv[1]: - print(help_msg) - sys.exit(0) - elif 'all' == sys.argv[1]: - # get logs from all hosts - hosts = [] - host_objs = CLIENT.host_get_all() - for host_obj in host_objs: - hosts.append(host_obj.name) - else: - # get logs from specified hosts - hostnames = sys.argv[1].split(',') - for host in hostnames: - if host not in hosts: - hosts.append(host) - else: - print(help_msg) - sys.exit(1) - - # open tar file for storing logs - fd, tar_path = tempfile.mkstemp(prefix='kolla_support_logs_', - suffix='.tgz') - os.close(fd) # avoid fd leak - - with tarfile.open(tar_path, 'w:gz') as tar_file_descr: - # clear out old logs - if os.path.exists(LOGDIR): - shutil.rmtree(LOGDIR) - os.mkdir(LOGDIR) - - # gather logs from selected hosts - try: - for host in hosts: - get_logs_from_host(host) - - # tar up all the container logs - tar_file_descr.add(LOGDIR, arcname='container_logs') - finally: - # remove uncompressed logs - if os.path.exists(LOGDIR): - shutil.rmtree(LOGDIR) - - # gather dump output from kolla-cli - dump_kolla_info() - - print('Log collection complete. Logs are at %s' % tar_path) - - -if __name__ == '__main__': - main() diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 90644f3..0000000 --- a/tox.ini +++ /dev/null @@ -1,127 +0,0 @@ -[tox] -minversion = 3.1 -skipsdist = True -envlist = py37,pep8,mypy -ignore_basepython_conflict = True - -[testenv] -basepython = python3 -usedevelop=True -whitelist_externals = - find - bash - make - mkdir - mypy - rm -deps = -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY - OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_LOG_CAPTURE OS_TEST_TIMEOUT - PYTHON OS_TEST_PATH LISTOPT IDOPTION -commands = - find . -type f -name "*.py[c|o]" -delete -o -type l -name "*.py[c|o]" -delete - find . -type d -name "__pycache__" -delete - # run stestr test - stestr run {posargs} - -[testenv:debug] -description = Allows to run unit-test with debug mode enabled -setenv = - KOLLA_ETC = /tmp/kollaclitest/etc/kolla - KOLLA_HOME = /tmp/kollaclitest/usr/share/kolla-ansible - KOLLA_TOOLS_DIR = {toxinidir}/tools -commands = - {toxinidir}/kolla_cli/tests/functional/functional_test_setup.sh - bash -c "pushd /tmp/kollaclitest/usr/share/kolla-ansible/git; python setup.py install; popd" - oslo_debug_helper -t {toxinidir}/kolla_cli/tests {posargs} - -[testenv:functional] -setenv = - OS_TEST_PATH = ./kolla_cli/tests/functional - KOLLA_ETC = /tmp/kollaclitest/etc/kolla - KOLLA_HOME = /tmp/kollaclitest/usr/share/kolla-ansible - KOLLA_TOOLS_DIR = {toxinidir}/tools -commands = - find . -type f -name "*.py[c|o]" -delete -o -type l -name "*.py[c|o]" -delete - find . -type d -name "__pycache__" -delete - {toxinidir}/kolla_cli/tests/functional/functional_test_setup.sh - bash -c "pushd /tmp/kollaclitest/usr/share/kolla-ansible/git; python setup.py install; popd" - stestr run {posargs} --serial - -[testenv:functional-py36] -basepython = python3.6 -setenv = {[testenv:functional]setenv} -commands = {[testenv:functional]commands} - -[testenv:functional-py37] -basepython = python3.7 -setenv = {[testenv:functional]setenv} -commands = {[testenv:functional]commands} - -[testenv:pep8] -deps = {[testenv]deps} -commands = - flake8 {posargs} - doc8 doc/source - {[testenv:bandit]commands} - -[testenv:mypy] -skip_install = true -commands = - mypy --ignore-missing-imports kolla_cli - -[testenv:venv] -commands = {posargs} - -[flake8] -show-source = True -exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build - -[testenv:bandit] -# Run security linter -commands = bandit -r kolla_cli -x tests - -[testenv:docs] -deps = - {[testenv]deps} - -r{toxinidir}/doc/requirements.txt -commands = - rm -rf doc/build - sphinx-build -W --keep-going -b html doc/source doc/build/html - -[testenv:pdf-docs] -deps = {[testenv:docs]deps} -commands = - rm -rf doc/build/pdf - mkdir -p doc/build/pdf/_static - sphinx-build -W --keep-going -b latex doc/source doc/build/pdf - make -C doc/build/pdf - -[testenv:releasenotes] -deps = - {[testenv]deps} - -r{toxinidir}/doc/requirements.txt -commands = - rm -rf releasenotes/build - sphinx-build -a -E -W -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html - -[testenv:cover] -setenv = VIRTUAL_ENV={envdir} - NOSE_WITH_COVERAGE=1 - NOSE_COVER_BRANCHES=1 - NOSE_COVER_HTML=1 - NOSE_COVER_HTML_DIR={toxinidir}/cover - PYTHON=coverage run --source kolla_cli --parallel-mode -commands = - stestr run {posargs} - coverage combine - coverage html -d cover - coverage xml -o cover/coverage.xml - -[testenv:lower-constraints] -deps = - -c{toxinidir}/lower-constraints.txt - -r{toxinidir}/test-requirements.txt - -r{toxinidir}/requirements.txt