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 0b5b428..267e233 100644 --- a/README.rst +++ b/README.rst @@ -1,132 +1,5 @@ -========= -Kolla-CLI -========= +This project is no longer maintained. -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. +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 a0e3dde568bf5bed927e51634f136164ea9a8340". -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-dev@lists.openstack.org with the tagline [kolla] 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 e7de513..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,22 +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! -===================================== - -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/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 f687298..0000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,20 +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 - 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/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