From 6fb491028eba10b5a8931aa573d4e6267acb23ce Mon Sep 17 00:00:00 2001 From: Thomas Woerner <twoerner@redhat.com> Date: Thu, 8 Oct 2020 12:01:34 +0200 Subject: [PATCH] New script utils/ansible-doc-test This script can check modules in roles and also plugins folder to have a valid documentation section. It is using anisble-doc internally. usage: Usage: ansible-doc-test [options] [path] optional arguments: -h, --help show this help message and exit -v increase output verbosity There are different verbose levels: -v Shows the modules that are tested at the moment. -vv Shows the modules and also the doc output. You can use the script to check specific modules, roles or modules in roles. Here are some examples: Test specific module with verbose level 1: $ utils/ansible-doc-test -vv plugins/modules/ipauser.py Test all modules in plugins folder: $ utils/ansible-doc-test -v plugins Test ipaserver_prepare.py in ipaserver role: $ utils/ansible-doc-test -v roles/ipaserver/library/ipaserver_prepare.py Test all modules in ipaserver role: $ utils/ansible-doc-test -v roles/ipaserver Test all roles: $ utils/ansible-doc-test -v roles Test all roles and modules in plugins: $ utils/ansible-doc-test -v --- utils/ansible-doc-test | 159 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100755 utils/ansible-doc-test diff --git a/utils/ansible-doc-test b/utils/ansible-doc-test new file mode 100755 index 00000000..a7c29853 --- /dev/null +++ b/utils/ansible-doc-test @@ -0,0 +1,159 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Authors: +# Thomas Woerner <twoerner@redhat.com> +# +# Copyright (C) 2020 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import os.path +import sys +import argparse +import subprocess + + +def run_ansible_doc(role, module, verbose=False): + playbook_dir, module_path = get_playbook_dir(role, module) + + command = ["ansible-doc", + "--playbook-dir=%s" % playbook_dir, + "--type=module", + "-vvv", + module] + process = subprocess.run(command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout = process.stdout.decode("utf8") + stderr = process.stderr.decode("utf8") + if process.returncode != 0 or "WARNING" in stderr: + print("%s\n%s" % (module_path, stderr)) + print("%s\n%s" % (module_path, stdout)) + return 1 + elif verbose == 1: + print(module_path) + elif verbose > 1: + print("%s\n%s" % (module_path, stdout)) + return 0 + + +def get_playbook_dir(role, module): + if module is None: + raise IOError("module is not set") + + if role is not None: + playbook_dir = "roles/%s" % role + module_path = "%s/library/%s" % (playbook_dir, module) + if not os.path.isfile(module_path): + raise IOError("No module '%s' in role '%s'" % (module, role)) + else: + playbook_dir = "." + module_path = "plugins/modules/%s" % module + if not os.path.isfile(module_path): + raise IOError("No module '%s'" % module) + + return playbook_dir, module_path + + +def ansible_doc_test(path, verbose): + role = None + module = None + only_roles = False + only_modules = False + + if path is not None: + if path.startswith("roles/") and len(path) > 6: + _path = path[6:].split("/") + role = _path[0] + if len(_path) == 2 and _path[1] == "": + pass + elif len(_path) == 3 and _path[1] == "library": + module = _path[2] + if module == "": + module = None + elif len(_path) > 1: + print("The given path '%s' is not valid." % path) + sys.exit(1) + + elif path in ["roles", "roles/"]: + # roles only + only_roles = True + elif path.startswith("plugins/modules/") and len(path) > 16: + _path = path[16:].split("/") + if len(_path) == 1: + module = _path[0] + else: + print("The given path '%s' is not valid." % path) + sys.exit(1) + elif path in ["plugins", "plugins/", + "plugins/modules", "plugins/modules/"]: + only_modules = True + else: + print("The given path '%s' is not valid." % path) + sys.exit(1) + + errors = 0 + try: + if role and not os.path.isdir("roles/%s" % role): + raise IOError("No role '%s'" % role) + + if module: + errors += run_ansible_doc(role, module, verbose) + elif role: + # All modules in role + modules = os.listdir("roles/%s/library" % role) + for _module in modules: + if _module.endswith(".py"): + errors += run_ansible_doc(role, _module, verbose) + else: + if not only_modules: + # All roles and plugins + roles = os.listdir("roles/") + for _role in roles: + if not os.path.isdir("roles/%s" % _role): + continue + modules = os.listdir("roles/%s/library" % _role) + for _module in modules: + if _module.endswith(".py"): + errors += run_ansible_doc(_role, _module, verbose) + if not only_roles: + modules = os.listdir("plugins/modules") + for _module in modules: + if _module.endswith(".py"): + errors += run_ansible_doc(None, _module, verbose) + except IOError as e: + print(str(e)) + errors += 1 + + return errors + + +usage = "Usage: ansible-doc-test [options] [path]" +parser = argparse.ArgumentParser(usage=usage) +parser.add_argument("-v", dest="verbose", action="count", + help="increase output verbosity", default=0) +options, args = parser.parse_known_args() + +errors = 0 + +for arg in args: + errors += ansible_doc_test(arg, options.verbose) +if len(args) == 0: + errors += ansible_doc_test(None, options.verbose) + +if errors != 0: + sys.exit(1) -- GitLab