ansible-core 2.17.4__py3-none-any.whl → 2.18.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/__main__.py +2 -17
- ansible/cli/__init__.py +3 -15
- ansible/cli/config.py +187 -24
- ansible/cli/console.py +1 -1
- ansible/cli/doc.py +38 -16
- ansible/cli/galaxy.py +30 -53
- ansible/cli/inventory.py +2 -2
- ansible/cli/pull.py +2 -2
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -10
- ansible/config/base.yml +127 -57
- ansible/config/manager.py +89 -11
- ansible/constants.py +32 -9
- ansible/errors/__init__.py +5 -0
- ansible/executor/interpreter_discovery.py +1 -1
- ansible/executor/play_iterator.py +16 -0
- ansible/executor/playbook_executor.py +1 -4
- ansible/executor/powershell/become_wrapper.ps1 +4 -5
- ansible/executor/powershell/bootstrap_wrapper.ps1 +2 -3
- ansible/executor/powershell/exec_wrapper.ps1 +1 -1
- ansible/executor/powershell/module_manifest.py +2 -2
- ansible/executor/task_executor.py +50 -39
- ansible/executor/task_queue_manager.py +1 -1
- ansible/executor/task_result.py +1 -1
- ansible/galaxy/api.py +3 -4
- ansible/galaxy/collection/__init__.py +21 -10
- ansible/galaxy/collection/concrete_artifact_manager.py +2 -2
- ansible/galaxy/collection/galaxy_api_proxy.py +10 -16
- ansible/galaxy/collection/gpg.py +17 -23
- ansible/galaxy/data/COPYING +7 -0
- ansible/galaxy/data/apb/Dockerfile.j2 +1 -0
- ansible/galaxy/data/apb/Makefile.j2 +1 -0
- ansible/galaxy/data/apb/README.md +7 -3
- ansible/galaxy/data/apb/apb.yml.j2 +1 -0
- ansible/galaxy/data/apb/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/playbooks/deprovision.yml.j2 +1 -0
- ansible/galaxy/data/apb/playbooks/provision.yml.j2 +1 -0
- ansible/galaxy/data/apb/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/apb/tests/ansible.cfg +1 -0
- ansible/galaxy/data/apb/tests/inventory +1 -0
- ansible/galaxy/data/apb/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/apb/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/collections_galaxy_meta.yml +1 -0
- ansible/galaxy/data/container/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/container/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/container/meta/container.yml.j2 +1 -0
- ansible/galaxy/data/container/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/container/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/container/tests/ansible.cfg +1 -0
- ansible/galaxy/data/container/tests/inventory +1 -0
- ansible/galaxy/data/container/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/container/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/default/collection/README.md.j2 +1 -0
- ansible/galaxy/data/default/collection/galaxy.yml.j2 +1 -0
- ansible/galaxy/data/default/collection/meta/runtime.yml +1 -0
- ansible/galaxy/data/default/collection/plugins/README.md.j2 +1 -0
- ansible/galaxy/data/default/role/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/handlers/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/default/role/tests/inventory +1 -0
- ansible/galaxy/data/default/role/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/default/role/vars/main.yml.j2 +1 -0
- ansible/galaxy/data/network/cliconf_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/defaults/main.yml.j2 +1 -0
- ansible/galaxy/data/network/library/example_command.py.j2 +1 -0
- ansible/galaxy/data/network/library/example_config.py.j2 +1 -0
- ansible/galaxy/data/network/library/example_facts.py.j2 +1 -0
- ansible/galaxy/data/network/meta/main.yml.j2 +1 -0
- ansible/galaxy/data/network/module_utils/example.py.j2 +1 -0
- ansible/galaxy/data/network/netconf_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/tasks/main.yml.j2 +1 -0
- ansible/galaxy/data/network/terminal_plugins/example.py.j2 +1 -0
- ansible/galaxy/data/network/tests/inventory +1 -0
- ansible/galaxy/data/network/tests/test.yml.j2 +1 -0
- ansible/galaxy/data/network/vars/main.yml.j2 +1 -0
- ansible/galaxy/dependency_resolution/providers.py +3 -3
- ansible/galaxy/role.py +1 -1
- ansible/galaxy/token.py +20 -8
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +0 -0
- ansible/module_utils/_internal/_concurrent/__init__.py +0 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +28 -0
- ansible/module_utils/_internal/_concurrent/_futures.py +21 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +2 -2
- ansible/module_utils/basic.py +14 -11
- ansible/module_utils/common/collections.py +1 -1
- ansible/module_utils/common/file.py +0 -6
- ansible/module_utils/common/process.py +22 -9
- ansible/module_utils/common/text/converters.py +5 -8
- ansible/module_utils/common/text/formatters.py +20 -4
- ansible/module_utils/common/validation.py +33 -25
- ansible/module_utils/compat/paramiko.py +6 -1
- ansible/module_utils/compat/selinux.py +2 -2
- ansible/module_utils/connection.py +8 -24
- ansible/module_utils/csharp/Ansible.Become.cs +14 -25
- ansible/module_utils/csharp/Ansible.Process.cs +1 -1
- ansible/module_utils/distro/__init__.py +1 -1
- ansible/module_utils/distro/_distro.py +8 -4
- ansible/module_utils/facts/collector.py +2 -0
- ansible/module_utils/facts/default_collectors.py +3 -1
- ansible/module_utils/facts/hardware/aix.py +54 -52
- ansible/module_utils/facts/hardware/darwin.py +37 -34
- ansible/module_utils/facts/hardware/freebsd.py +55 -15
- ansible/module_utils/facts/hardware/hpux.py +3 -0
- ansible/module_utils/facts/hardware/linux.py +101 -57
- ansible/module_utils/facts/hardware/netbsd.py +3 -0
- ansible/module_utils/facts/hardware/openbsd.py +4 -1
- ansible/module_utils/facts/hardware/sunos.py +7 -1
- ansible/module_utils/facts/network/aix.py +16 -17
- ansible/module_utils/facts/network/fc_wwn.py +4 -1
- ansible/module_utils/facts/network/hpux.py +21 -4
- ansible/module_utils/facts/network/iscsi.py +7 -8
- ansible/module_utils/facts/network/linux.py +0 -2
- ansible/module_utils/facts/other/facter.py +9 -4
- ansible/module_utils/facts/other/ohai.py +5 -5
- ansible/module_utils/facts/packages.py +49 -7
- ansible/module_utils/facts/sysctl.py +33 -31
- ansible/module_utils/facts/system/distribution.py +1 -1
- ansible/module_utils/facts/system/local.py +12 -22
- ansible/module_utils/facts/system/service_mgr.py +3 -1
- ansible/module_utils/facts/system/systemd.py +47 -0
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/splitter.py +1 -1
- ansible/modules/add_host.py +1 -1
- ansible/modules/apt.py +43 -32
- ansible/modules/apt_key.py +6 -6
- ansible/modules/apt_repository.py +23 -14
- ansible/modules/assemble.py +7 -2
- ansible/modules/assert.py +4 -4
- ansible/modules/blockinfile.py +3 -6
- ansible/modules/command.py +1 -1
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +13 -10
- ansible/modules/deb822_repository.py +16 -17
- ansible/modules/debconf.py +9 -9
- ansible/modules/debug.py +1 -1
- ansible/modules/dnf.py +79 -164
- ansible/modules/dnf5.py +48 -31
- ansible/modules/dpkg_selections.py +2 -2
- ansible/modules/expect.py +2 -2
- ansible/modules/fetch.py +2 -2
- ansible/modules/file.py +5 -3
- ansible/modules/find.py +40 -12
- ansible/modules/gather_facts.py +4 -2
- ansible/modules/get_url.py +29 -24
- ansible/modules/git.py +35 -35
- ansible/modules/group.py +71 -1
- ansible/modules/hostname.py +2 -4
- ansible/modules/include_vars.py +5 -5
- ansible/modules/iptables.py +13 -16
- ansible/modules/known_hosts.py +16 -13
- ansible/modules/lineinfile.py +1 -4
- ansible/modules/meta.py +6 -1
- ansible/modules/mount_facts.py +651 -0
- ansible/modules/package_facts.py +63 -80
- ansible/modules/pause.py +4 -3
- ansible/modules/pip.py +14 -14
- ansible/modules/replace.py +1 -4
- ansible/modules/rpm_key.py +31 -11
- ansible/modules/service.py +8 -8
- ansible/modules/service_facts.py +20 -5
- ansible/modules/set_stats.py +1 -1
- ansible/modules/setup.py +3 -3
- ansible/modules/stat.py +3 -3
- ansible/modules/subversion.py +1 -1
- ansible/modules/systemd.py +16 -10
- ansible/modules/systemd_service.py +16 -10
- ansible/modules/sysvinit.py +4 -4
- ansible/modules/unarchive.py +35 -22
- ansible/modules/uri.py +24 -18
- ansible/modules/user.py +145 -12
- ansible/modules/validate_argument_spec.py +3 -3
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +136 -179
- ansible/parsing/dataloader.py +2 -2
- ansible/parsing/mod_args.py +11 -10
- ansible/parsing/vault/__init__.py +8 -3
- ansible/parsing/yaml/constructor.py +10 -8
- ansible/parsing/yaml/objects.py +1 -1
- ansible/playbook/base.py +12 -23
- ansible/playbook/helpers.py +4 -0
- ansible/playbook/loop_control.py +8 -0
- ansible/playbook/play.py +4 -22
- ansible/playbook/play_context.py +0 -16
- ansible/playbook/playbook_include.py +2 -2
- ansible/playbook/role/__init__.py +2 -2
- ansible/playbook/task.py +1 -1
- ansible/plugins/__init__.py +2 -0
- ansible/plugins/action/__init__.py +7 -9
- ansible/plugins/action/reboot.py +2 -2
- ansible/plugins/become/__init__.py +1 -1
- ansible/plugins/callback/__init__.py +44 -3
- ansible/plugins/callback/default.py +1 -1
- ansible/plugins/cliconf/__init__.py +1 -1
- ansible/plugins/connection/paramiko_ssh.py +2 -80
- ansible/plugins/connection/psrp.py +33 -82
- ansible/plugins/connection/ssh.py +0 -8
- ansible/plugins/connection/winrm.py +46 -1
- ansible/plugins/doc_fragments/connection_pipelining.py +2 -2
- ansible/plugins/doc_fragments/constructed.py +10 -10
- ansible/plugins/doc_fragments/default_callback.py +8 -8
- ansible/plugins/doc_fragments/files.py +5 -5
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +6 -6
- ansible/plugins/doc_fragments/return_common.py +1 -1
- ansible/plugins/doc_fragments/shell_common.py +2 -10
- ansible/plugins/doc_fragments/shell_windows.py +0 -9
- ansible/plugins/doc_fragments/url.py +2 -2
- ansible/plugins/doc_fragments/url_windows.py +4 -5
- ansible/plugins/doc_fragments/validate.py +1 -1
- ansible/plugins/filter/core.py +2 -0
- ansible/plugins/filter/human_to_bytes.yml +9 -0
- ansible/plugins/filter/password_hash.yml +1 -1
- ansible/plugins/filter/strftime.yml +1 -1
- ansible/plugins/filter/to_nice_json.yml +7 -3
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +1 -1
- ansible/plugins/loader.py +0 -11
- ansible/plugins/lookup/config.py +1 -1
- ansible/plugins/lookup/csvfile.py +21 -9
- ansible/plugins/lookup/env.py +8 -9
- ansible/plugins/lookup/ini.py +10 -1
- ansible/plugins/lookup/random_choice.py +2 -2
- ansible/plugins/lookup/url.py +7 -2
- ansible/plugins/shell/__init__.py +15 -20
- ansible/plugins/shell/powershell.py +9 -6
- ansible/plugins/strategy/__init__.py +16 -7
- ansible/plugins/test/core.py +23 -1
- ansible/plugins/test/issubset.yml +1 -1
- ansible/plugins/test/subset.yml +1 -1
- ansible/plugins/test/timedout.yml +20 -0
- ansible/plugins/test/vault_encrypted.yml +6 -6
- ansible/plugins/test/vaulted_file.yml +19 -0
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -8
- ansible/utils/collection_loader/_collection_finder.py +23 -55
- ansible/utils/display.py +44 -31
- ansible/utils/jsonrpc.py +1 -1
- ansible/utils/listify.py +1 -5
- ansible/utils/path.py +3 -0
- ansible/utils/vars.py +18 -27
- ansible/vars/manager.py +7 -150
- ansible/vars/plugins.py +1 -1
- ansible_core-2.18.0b1.dist-info/Apache-License.txt +202 -0
- {ansible_core-2.17.4.dist-info → ansible_core-2.18.0b1.dist-info}/METADATA +36 -23
- ansible_core-2.18.0b1.dist-info/MIT-license.txt +14 -0
- ansible_core-2.18.0b1.dist-info/PSF-license.txt +48 -0
- {ansible_core-2.17.4.dist-info → ansible_core-2.18.0b1.dist-info}/RECORD +311 -306
- {ansible_core-2.17.4.dist-info → ansible_core-2.18.0b1.dist-info}/WHEEL +1 -1
- {ansible_core-2.17.4.dist-info → ansible_core-2.18.0b1.dist-info}/entry_points.txt +1 -1
- ansible_core-2.18.0b1.dist-info/simplified_bsd.txt +8 -0
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +5 -4
- ansible_test/_data/completion/windows.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -2
- ansible_test/_data/requirements/constraints.txt +1 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.in +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +4 -4
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.import.txt +1 -1
- ansible_test/_data/requirements/sanity.integration-aliases.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +5 -7
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +2 -2
- ansible_test/_data/requirements/sanity.validate-modules.txt +3 -3
- ansible_test/_data/requirements/sanity.yamllint.in +1 -0
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/ansible_util.py +8 -35
- ansible_test/_internal/ci/azp.py +1 -1
- ansible_test/_internal/classification/__init__.py +0 -2
- ansible_test/_internal/cli/parsers/key_value_parsers.py +3 -0
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -1
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +1 -1
- ansible_test/_internal/commands/sanity/__init__.py +96 -19
- ansible_test/_internal/commands/sanity/pylint.py +20 -24
- ansible_test/_internal/completion.py +2 -0
- ansible_test/_internal/constants.py +0 -1
- ansible_test/_internal/coverage_util.py +1 -2
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/host_configs.py +10 -0
- ansible_test/_internal/host_profiles.py +9 -13
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +5 -14
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +40 -0
- ansible_test/_internal/util_common.py +5 -1
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.json +3 -1
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +6 -3
- ansible_test/_util/controller/sanity/code-smell/empty-init.json +0 -2
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -19
- ansible_test/_util/controller/sanity/shellcheck/exclude.txt +1 -0
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +67 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +27 -5
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +0 -0
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/injector/python.py +5 -0
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +6 -0
- ansible_test/_util/target/sanity/import/importer.py +1 -1
- ansible_test/_util/target/setup/bootstrap.sh +6 -17
- ansible_test/_util/target/setup/requirements.py +14 -20
- ansible_test/config/config.yml +1 -1
- ansible_core-2.17.4.data/scripts/ansible-test +0 -44
- ansible_test/_data/requirements/sanity.mypy.in +0 -10
- ansible_test/_data/requirements/sanity.mypy.txt +0 -18
- ansible_test/_internal/commands/sanity/mypy.py +0 -274
- ansible_test/_util/controller/sanity/mypy/ansible-core.ini +0 -116
- ansible_test/_util/controller/sanity/mypy/ansible-test.ini +0 -27
- ansible_test/_util/controller/sanity/mypy/modules.ini +0 -92
- ansible_test/_util/controller/sanity/mypy/packaging.ini +0 -20
- {ansible_core-2.17.4.dist-info → ansible_core-2.18.0b1.dist-info}/COPYING +0 -0
- {ansible_core-2.17.4.dist-info → ansible_core-2.18.0b1.dist-info}/top_level.txt +0 -0
ansible/__main__.py
CHANGED
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import argparse
|
|
6
|
-
import importlib
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
6
|
|
|
10
7
|
from importlib.metadata import distribution
|
|
11
8
|
|
|
@@ -19,22 +16,10 @@ def main():
|
|
|
19
16
|
ep_map = {_short_name(ep.name): ep for ep in dist.entry_points if ep.group == 'console_scripts'}
|
|
20
17
|
|
|
21
18
|
parser = argparse.ArgumentParser(prog='python -m ansible', add_help=False)
|
|
22
|
-
parser.add_argument('entry_point', choices=list(ep_map)
|
|
19
|
+
parser.add_argument('entry_point', choices=list(ep_map))
|
|
23
20
|
args, extra = parser.parse_known_args()
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
ansible_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
27
|
-
source_root = os.path.join(ansible_root, 'test', 'lib')
|
|
28
|
-
|
|
29
|
-
if os.path.exists(os.path.join(source_root, 'ansible_test', '_internal', '__init__.py')):
|
|
30
|
-
# running from source, use that version of ansible-test instead of any version that may already be installed
|
|
31
|
-
sys.path.insert(0, source_root)
|
|
32
|
-
|
|
33
|
-
module = importlib.import_module('ansible_test._util.target.cli.ansible_test_cli_stub')
|
|
34
|
-
main = module.main
|
|
35
|
-
else:
|
|
36
|
-
main = ep_map[args.entry_point].load()
|
|
37
|
-
|
|
22
|
+
main = ep_map[args.entry_point].load()
|
|
38
23
|
main([args.entry_point] + extra)
|
|
39
24
|
|
|
40
25
|
|
ansible/cli/__init__.py
CHANGED
|
@@ -11,9 +11,9 @@ import sys
|
|
|
11
11
|
|
|
12
12
|
# Used for determining if the system is running a new enough python version
|
|
13
13
|
# and should only restrict on our documented minimum versions
|
|
14
|
-
if sys.version_info < (3,
|
|
14
|
+
if sys.version_info < (3, 11):
|
|
15
15
|
raise SystemExit(
|
|
16
|
-
'ERROR: Ansible requires Python 3.
|
|
16
|
+
'ERROR: Ansible requires Python 3.11 or newer on the controller. '
|
|
17
17
|
'Current version: %s' % ''.join(sys.version.splitlines())
|
|
18
18
|
)
|
|
19
19
|
|
|
@@ -167,19 +167,7 @@ class CLI(ABC):
|
|
|
167
167
|
else:
|
|
168
168
|
display.v(u"No config file found; using defaults")
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
for deprecated in C.config.DEPRECATED:
|
|
172
|
-
name = deprecated[0]
|
|
173
|
-
why = deprecated[1]['why']
|
|
174
|
-
if 'alternatives' in deprecated[1]:
|
|
175
|
-
alt = ', use %s instead' % deprecated[1]['alternatives']
|
|
176
|
-
else:
|
|
177
|
-
alt = ''
|
|
178
|
-
ver = deprecated[1].get('version')
|
|
179
|
-
date = deprecated[1].get('date')
|
|
180
|
-
collection_name = deprecated[1].get('collection_name')
|
|
181
|
-
display.deprecated("%s option, %s%s" % (name, why, alt),
|
|
182
|
-
version=ver, date=date, collection_name=collection_name)
|
|
170
|
+
C.handle_config_noise(display)
|
|
183
171
|
|
|
184
172
|
@staticmethod
|
|
185
173
|
def split_vault_id(vault_id):
|
ansible/cli/config.py
CHANGED
|
@@ -9,9 +9,10 @@ from __future__ import annotations
|
|
|
9
9
|
from ansible.cli import CLI
|
|
10
10
|
|
|
11
11
|
import os
|
|
12
|
-
import yaml
|
|
13
12
|
import shlex
|
|
14
13
|
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
import yaml
|
|
15
16
|
|
|
16
17
|
from collections.abc import Mapping
|
|
17
18
|
|
|
@@ -21,7 +22,7 @@ import ansible.plugins.loader as plugin_loader
|
|
|
21
22
|
from ansible import constants as C
|
|
22
23
|
from ansible.cli.arguments import option_helpers as opt_help
|
|
23
24
|
from ansible.config.manager import ConfigManager, Setting
|
|
24
|
-
from ansible.errors import AnsibleError, AnsibleOptionsError
|
|
25
|
+
from ansible.errors import AnsibleError, AnsibleOptionsError, AnsibleRequiredOptionError
|
|
25
26
|
from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
|
|
26
27
|
from ansible.module_utils.common.json import json_dump
|
|
27
28
|
from ansible.module_utils.six import string_types
|
|
@@ -34,6 +35,9 @@ from ansible.utils.path import unfrackpath
|
|
|
34
35
|
display = Display()
|
|
35
36
|
|
|
36
37
|
|
|
38
|
+
_IGNORE_CHANGED = frozenset({'_terms', '_input'})
|
|
39
|
+
|
|
40
|
+
|
|
37
41
|
def yaml_dump(data, default_flow_style=False, default_style=None):
|
|
38
42
|
return yaml.dump(data, Dumper=AnsibleDumper, default_flow_style=default_flow_style, default_style=default_style)
|
|
39
43
|
|
|
@@ -49,6 +53,37 @@ def get_constants():
|
|
|
49
53
|
return get_constants.cvars
|
|
50
54
|
|
|
51
55
|
|
|
56
|
+
def _ansible_env_vars(varname):
|
|
57
|
+
''' return true or false depending if variable name is possibly a 'configurable' ansible env variable '''
|
|
58
|
+
return all(
|
|
59
|
+
[
|
|
60
|
+
varname.startswith("ANSIBLE_"),
|
|
61
|
+
not varname.startswith(("ANSIBLE_TEST_", "ANSIBLE_LINT_")),
|
|
62
|
+
varname not in ("ANSIBLE_CONFIG", "ANSIBLE_DEV_HOME"),
|
|
63
|
+
]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _get_evar_list(settings):
|
|
68
|
+
data = []
|
|
69
|
+
for setting in settings:
|
|
70
|
+
if 'env' in settings[setting] and settings[setting]['env']:
|
|
71
|
+
for varname in settings[setting]['env']:
|
|
72
|
+
data.append(varname.get('name'))
|
|
73
|
+
return data
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _get_ini_entries(settings):
|
|
77
|
+
data = {}
|
|
78
|
+
for setting in settings:
|
|
79
|
+
if 'ini' in settings[setting] and settings[setting]['ini']:
|
|
80
|
+
for kv in settings[setting]['ini']:
|
|
81
|
+
if not kv['section'] in data:
|
|
82
|
+
data[kv['section']] = set()
|
|
83
|
+
data[kv['section']].add(kv['key'])
|
|
84
|
+
return data
|
|
85
|
+
|
|
86
|
+
|
|
52
87
|
class ConfigCLI(CLI):
|
|
53
88
|
""" Config command line class """
|
|
54
89
|
|
|
@@ -99,9 +134,13 @@ class ConfigCLI(CLI):
|
|
|
99
134
|
init_parser.add_argument('--disabled', dest='commented', action='store_true', default=False,
|
|
100
135
|
help='Prefixes all entries with a comment character to disable them')
|
|
101
136
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
137
|
+
validate_parser = subparsers.add_parser('validate',
|
|
138
|
+
help='Validate the configuration file and environment variables. '
|
|
139
|
+
'By default it only checks the base settings without accounting for plugins (see -t).',
|
|
140
|
+
parents=[common])
|
|
141
|
+
validate_parser.set_defaults(func=self.execute_validate)
|
|
142
|
+
validate_parser.add_argument('--format', '-f', dest='format', action='store', choices=['ini', 'env'] , default='ini',
|
|
143
|
+
help='Output format for init')
|
|
105
144
|
|
|
106
145
|
def post_process_args(self, options):
|
|
107
146
|
options = super(ConfigCLI, self).post_process_args(options)
|
|
@@ -113,6 +152,10 @@ class ConfigCLI(CLI):
|
|
|
113
152
|
|
|
114
153
|
super(ConfigCLI, self).run()
|
|
115
154
|
|
|
155
|
+
# initialize each galaxy server's options from known listed servers
|
|
156
|
+
self._galaxy_servers = [s for s in C.GALAXY_SERVER_LIST or [] if s] # clean list, reused later here
|
|
157
|
+
C.config.load_galaxy_server_defs(self._galaxy_servers)
|
|
158
|
+
|
|
116
159
|
if context.CLIARGS['config_file']:
|
|
117
160
|
self.config_file = unfrackpath(context.CLIARGS['config_file'], follow=False)
|
|
118
161
|
b_config = to_bytes(self.config_file)
|
|
@@ -226,11 +269,17 @@ class ConfigCLI(CLI):
|
|
|
226
269
|
'''
|
|
227
270
|
build a dict with the list requested configs
|
|
228
271
|
'''
|
|
272
|
+
|
|
229
273
|
config_entries = {}
|
|
230
274
|
if context.CLIARGS['type'] in ('base', 'all'):
|
|
231
275
|
# this dumps main/common configs
|
|
232
276
|
config_entries = self.config.get_configuration_definitions(ignore_private=True)
|
|
233
277
|
|
|
278
|
+
# for base and all, we include galaxy servers
|
|
279
|
+
config_entries['GALAXY_SERVERS'] = {}
|
|
280
|
+
for server in self._galaxy_servers:
|
|
281
|
+
config_entries['GALAXY_SERVERS'][server] = self.config.get_configuration_definitions('galaxy_server', server)
|
|
282
|
+
|
|
234
283
|
if context.CLIARGS['type'] != 'base':
|
|
235
284
|
config_entries['PLUGINS'] = {}
|
|
236
285
|
|
|
@@ -239,6 +288,7 @@ class ConfigCLI(CLI):
|
|
|
239
288
|
for ptype in C.CONFIGURABLE_PLUGINS:
|
|
240
289
|
config_entries['PLUGINS'][ptype.upper()] = self._list_plugin_settings(ptype)
|
|
241
290
|
elif context.CLIARGS['type'] != 'base':
|
|
291
|
+
# only for requested types
|
|
242
292
|
config_entries['PLUGINS'][context.CLIARGS['type']] = self._list_plugin_settings(context.CLIARGS['type'], context.CLIARGS['args'])
|
|
243
293
|
|
|
244
294
|
return config_entries
|
|
@@ -358,7 +408,7 @@ class ConfigCLI(CLI):
|
|
|
358
408
|
elif default is None:
|
|
359
409
|
default = ''
|
|
360
410
|
|
|
361
|
-
if context.CLIARGS
|
|
411
|
+
if context.CLIARGS.get('commented', False):
|
|
362
412
|
entry['key'] = ';%s' % entry['key']
|
|
363
413
|
|
|
364
414
|
key = desc + '\n%s=%s' % (entry['key'], default)
|
|
@@ -408,13 +458,13 @@ class ConfigCLI(CLI):
|
|
|
408
458
|
|
|
409
459
|
entries = []
|
|
410
460
|
for setting in sorted(config):
|
|
411
|
-
changed = (config[setting].origin not in ('default', 'REQUIRED'))
|
|
461
|
+
changed = (config[setting].origin not in ('default', 'REQUIRED') and setting not in _IGNORE_CHANGED)
|
|
412
462
|
|
|
413
463
|
if context.CLIARGS['format'] == 'display':
|
|
414
464
|
if isinstance(config[setting], Setting):
|
|
415
465
|
# proceed normally
|
|
416
466
|
value = config[setting].value
|
|
417
|
-
if config[setting].origin == 'default':
|
|
467
|
+
if config[setting].origin == 'default' or setting in _IGNORE_CHANGED:
|
|
418
468
|
color = 'green'
|
|
419
469
|
value = self.config.template_default(value, get_constants())
|
|
420
470
|
elif config[setting].origin == 'REQUIRED':
|
|
@@ -431,6 +481,8 @@ class ConfigCLI(CLI):
|
|
|
431
481
|
else:
|
|
432
482
|
entry = {}
|
|
433
483
|
for key in config[setting]._fields:
|
|
484
|
+
if key == 'type':
|
|
485
|
+
continue
|
|
434
486
|
entry[key] = getattr(config[setting], key)
|
|
435
487
|
|
|
436
488
|
if not context.CLIARGS['only_changed'] or changed:
|
|
@@ -439,7 +491,10 @@ class ConfigCLI(CLI):
|
|
|
439
491
|
return entries
|
|
440
492
|
|
|
441
493
|
def _get_global_configs(self):
|
|
442
|
-
|
|
494
|
+
|
|
495
|
+
# Add base
|
|
496
|
+
config = self.config.get_configuration_definitions(ignore_private=True)
|
|
497
|
+
# convert to settings
|
|
443
498
|
for setting in config.keys():
|
|
444
499
|
v, o = C.config.get_config_value_and_origin(setting, cfile=self.config_file, variables=get_constants())
|
|
445
500
|
config[setting] = Setting(setting, v, o, None)
|
|
@@ -451,7 +506,7 @@ class ConfigCLI(CLI):
|
|
|
451
506
|
# prep loading
|
|
452
507
|
loader = getattr(plugin_loader, '%s_loader' % ptype)
|
|
453
508
|
|
|
454
|
-
#
|
|
509
|
+
# accumulators
|
|
455
510
|
output = []
|
|
456
511
|
config_entries = {}
|
|
457
512
|
|
|
@@ -468,7 +523,7 @@ class ConfigCLI(CLI):
|
|
|
468
523
|
plugin_cs = loader.all(class_only=True)
|
|
469
524
|
|
|
470
525
|
for plugin in plugin_cs:
|
|
471
|
-
# in case of
|
|
526
|
+
# in case of deprecation they diverge
|
|
472
527
|
finalname = name = plugin._load_name
|
|
473
528
|
if name.startswith('_'):
|
|
474
529
|
if os.path.islink(plugin._original_path):
|
|
@@ -491,12 +546,9 @@ class ConfigCLI(CLI):
|
|
|
491
546
|
for setting in config_entries[finalname].keys():
|
|
492
547
|
try:
|
|
493
548
|
v, o = C.config.get_config_value_and_origin(setting, cfile=self.config_file, plugin_type=ptype, plugin_name=name, variables=get_constants())
|
|
494
|
-
except
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
o = 'REQUIRED'
|
|
498
|
-
else:
|
|
499
|
-
raise e
|
|
549
|
+
except AnsibleRequiredOptionError:
|
|
550
|
+
v = None
|
|
551
|
+
o = 'REQUIRED'
|
|
500
552
|
|
|
501
553
|
if v is None and o is None:
|
|
502
554
|
# not all cases will be error
|
|
@@ -516,17 +568,60 @@ class ConfigCLI(CLI):
|
|
|
516
568
|
|
|
517
569
|
return output
|
|
518
570
|
|
|
571
|
+
def _get_galaxy_server_configs(self):
|
|
572
|
+
|
|
573
|
+
output = []
|
|
574
|
+
# add galaxy servers
|
|
575
|
+
for server in self._galaxy_servers:
|
|
576
|
+
server_config = {}
|
|
577
|
+
s_config = self.config.get_configuration_definitions('galaxy_server', server)
|
|
578
|
+
for setting in s_config.keys():
|
|
579
|
+
try:
|
|
580
|
+
v, o = C.config.get_config_value_and_origin(setting, plugin_type='galaxy_server', plugin_name=server, cfile=self.config_file)
|
|
581
|
+
except AnsibleError as e:
|
|
582
|
+
if s_config[setting].get('required', False):
|
|
583
|
+
v = None
|
|
584
|
+
o = 'REQUIRED'
|
|
585
|
+
else:
|
|
586
|
+
raise e
|
|
587
|
+
if v is None and o is None:
|
|
588
|
+
# not all cases will be error
|
|
589
|
+
o = 'REQUIRED'
|
|
590
|
+
server_config[setting] = Setting(setting, v, o, None)
|
|
591
|
+
if context.CLIARGS['format'] == 'display':
|
|
592
|
+
if not context.CLIARGS['only_changed'] or server_config:
|
|
593
|
+
equals = '=' * len(server)
|
|
594
|
+
output.append(f'\n{server}\n{equals}')
|
|
595
|
+
output.extend(self._render_settings(server_config))
|
|
596
|
+
else:
|
|
597
|
+
output.append({server: server_config})
|
|
598
|
+
|
|
599
|
+
return output
|
|
600
|
+
|
|
519
601
|
def execute_dump(self):
|
|
520
602
|
'''
|
|
521
603
|
Shows the current settings, merges ansible.cfg if specified
|
|
522
604
|
'''
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
output = self._get_global_configs()
|
|
526
|
-
elif context.CLIARGS['type'] == 'all':
|
|
605
|
+
output = []
|
|
606
|
+
if context.CLIARGS['type'] in ('base', 'all'):
|
|
527
607
|
# deal with base
|
|
528
608
|
output = self._get_global_configs()
|
|
529
|
-
|
|
609
|
+
|
|
610
|
+
# add galaxy servers
|
|
611
|
+
server_config_list = self._get_galaxy_server_configs()
|
|
612
|
+
if context.CLIARGS['format'] == 'display':
|
|
613
|
+
output.append('\nGALAXY_SERVERS:\n')
|
|
614
|
+
output.extend(server_config_list)
|
|
615
|
+
else:
|
|
616
|
+
configs = {}
|
|
617
|
+
for server_config in server_config_list:
|
|
618
|
+
server = list(server_config.keys())[0]
|
|
619
|
+
server_reduced_config = server_config.pop(server)
|
|
620
|
+
configs[server] = server_reduced_config
|
|
621
|
+
output.append({'GALAXY_SERVERS': configs})
|
|
622
|
+
|
|
623
|
+
if context.CLIARGS['type'] == 'all':
|
|
624
|
+
# add all plugins
|
|
530
625
|
for ptype in C.CONFIGURABLE_PLUGINS:
|
|
531
626
|
plugin_list = self._get_plugin_configs(ptype, context.CLIARGS['args'])
|
|
532
627
|
if context.CLIARGS['format'] == 'display':
|
|
@@ -539,8 +634,9 @@ class ConfigCLI(CLI):
|
|
|
539
634
|
else:
|
|
540
635
|
pname = '%s_PLUGINS' % ptype.upper()
|
|
541
636
|
output.append({pname: plugin_list})
|
|
542
|
-
|
|
543
|
-
|
|
637
|
+
|
|
638
|
+
elif context.CLIARGS['type'] != 'base':
|
|
639
|
+
# deal with specific plugin
|
|
544
640
|
output = self._get_plugin_configs(context.CLIARGS['type'], context.CLIARGS['args'])
|
|
545
641
|
|
|
546
642
|
if context.CLIARGS['format'] == 'display':
|
|
@@ -552,6 +648,73 @@ class ConfigCLI(CLI):
|
|
|
552
648
|
|
|
553
649
|
self.pager(to_text(text, errors='surrogate_or_strict'))
|
|
554
650
|
|
|
651
|
+
def execute_validate(self):
|
|
652
|
+
|
|
653
|
+
found = False
|
|
654
|
+
config_entries = self._list_entries_from_args()
|
|
655
|
+
plugin_types = config_entries.pop('PLUGINS', None)
|
|
656
|
+
galaxy_servers = config_entries.pop('GALAXY_SERVERS', None)
|
|
657
|
+
|
|
658
|
+
if context.CLIARGS['format'] == 'ini':
|
|
659
|
+
if C.CONFIG_FILE is not None:
|
|
660
|
+
# validate ini config since it is found
|
|
661
|
+
|
|
662
|
+
sections = _get_ini_entries(config_entries)
|
|
663
|
+
# Also from plugins
|
|
664
|
+
if plugin_types:
|
|
665
|
+
for ptype in plugin_types:
|
|
666
|
+
for plugin in plugin_types[ptype].keys():
|
|
667
|
+
plugin_sections = _get_ini_entries(plugin_types[ptype][plugin])
|
|
668
|
+
for s in plugin_sections:
|
|
669
|
+
if s in sections:
|
|
670
|
+
sections[s].update(plugin_sections[s])
|
|
671
|
+
else:
|
|
672
|
+
sections[s] = plugin_sections[s]
|
|
673
|
+
if galaxy_servers:
|
|
674
|
+
for server in galaxy_servers:
|
|
675
|
+
server_sections = _get_ini_entries(galaxy_servers[server])
|
|
676
|
+
for s in server_sections:
|
|
677
|
+
if s in sections:
|
|
678
|
+
sections[s].update(server_sections[s])
|
|
679
|
+
else:
|
|
680
|
+
sections[s] = server_sections[s]
|
|
681
|
+
if sections:
|
|
682
|
+
p = C.config._parsers[C.CONFIG_FILE]
|
|
683
|
+
for s in p.sections():
|
|
684
|
+
# check for valid sections
|
|
685
|
+
if s not in sections:
|
|
686
|
+
display.error(f"Found unknown section '{s}' in '{C.CONFIG_FILE}.")
|
|
687
|
+
found = True
|
|
688
|
+
continue
|
|
689
|
+
|
|
690
|
+
# check keys in valid sections
|
|
691
|
+
for k in p.options(s):
|
|
692
|
+
if k not in sections[s]:
|
|
693
|
+
display.error(f"Found unknown key '{k}' in section '{s}' in '{C.CONFIG_FILE}.")
|
|
694
|
+
found = True
|
|
695
|
+
|
|
696
|
+
elif context.CLIARGS['format'] == 'env':
|
|
697
|
+
# validate any 'ANSIBLE_' env vars found
|
|
698
|
+
evars = [varname for varname in os.environ.keys() if _ansible_env_vars(varname)]
|
|
699
|
+
if evars:
|
|
700
|
+
data = _get_evar_list(config_entries)
|
|
701
|
+
if plugin_types:
|
|
702
|
+
for ptype in plugin_types:
|
|
703
|
+
for plugin in plugin_types[ptype].keys():
|
|
704
|
+
data.extend(_get_evar_list(plugin_types[ptype][plugin]))
|
|
705
|
+
|
|
706
|
+
for evar in evars:
|
|
707
|
+
if evar not in data:
|
|
708
|
+
display.error(f"Found unknown environment variable '{evar}'.")
|
|
709
|
+
found = True
|
|
710
|
+
|
|
711
|
+
# we found discrepancies!
|
|
712
|
+
if found:
|
|
713
|
+
sys.exit(1)
|
|
714
|
+
|
|
715
|
+
# allsgood
|
|
716
|
+
display.display("All configurations seem valid!")
|
|
717
|
+
|
|
555
718
|
|
|
556
719
|
def main(args=None):
|
|
557
720
|
ConfigCLI.cli_executor(args)
|
ansible/cli/console.py
CHANGED
|
@@ -545,7 +545,7 @@ class ConsoleCLI(CLI, cmd.Cmd):
|
|
|
545
545
|
if path:
|
|
546
546
|
module_loader.add_directory(path)
|
|
547
547
|
|
|
548
|
-
# dynamically add '
|
|
548
|
+
# dynamically add 'canonical' modules as commands, aliases could be used and dynamically loaded
|
|
549
549
|
self.modules = self.list_modules()
|
|
550
550
|
for module in self.modules:
|
|
551
551
|
setattr(self, 'do_' + module, lambda arg, module=module: self.default(module + ' ' + arg))
|
ansible/cli/doc.py
CHANGED
|
@@ -50,7 +50,7 @@ PB_OBJECTS = ['Play', 'Role', 'Block', 'Task', 'Handler']
|
|
|
50
50
|
PB_LOADED = {}
|
|
51
51
|
SNIPPETS = ['inventory', 'lookup', 'module']
|
|
52
52
|
|
|
53
|
-
#
|
|
53
|
+
# hardcoded from ascii values
|
|
54
54
|
STYLE = {
|
|
55
55
|
'BLINK': '\033[5m',
|
|
56
56
|
'BOLD': '\033[1m',
|
|
@@ -71,8 +71,14 @@ NOCOLOR = {
|
|
|
71
71
|
'PLUGIN': r'[%s]',
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
ref_style = {
|
|
75
|
+
'MODULE': C.COLOR_DOC_MODULE,
|
|
76
|
+
'REF': C.COLOR_DOC_REFERENCE,
|
|
77
|
+
'LINK': C.COLOR_DOC_LINK,
|
|
78
|
+
'DEP': C.COLOR_DOC_DEPRECATED,
|
|
79
|
+
'CONSTANT': C.COLOR_DOC_CONSTANT,
|
|
80
|
+
'PLUGIN': C.COLOR_DOC_PLUGIN,
|
|
81
|
+
}
|
|
76
82
|
|
|
77
83
|
|
|
78
84
|
def jdump(text):
|
|
@@ -381,6 +387,12 @@ class RoleMixin(object):
|
|
|
381
387
|
|
|
382
388
|
for role, collection, role_path in (roles | collroles):
|
|
383
389
|
argspec = self._load_argspec(role, role_path, collection)
|
|
390
|
+
if 'error' in argspec:
|
|
391
|
+
if fail_on_errors:
|
|
392
|
+
raise argspec['exception']
|
|
393
|
+
else:
|
|
394
|
+
display.warning('Skipping role (%s) due to: %s' % (role, argspec['error']), True)
|
|
395
|
+
continue
|
|
384
396
|
fqcn, doc = self._build_doc(role, role_path, collection, argspec, entry_point)
|
|
385
397
|
if doc:
|
|
386
398
|
result[fqcn] = doc
|
|
@@ -881,6 +893,7 @@ class DocCLI(CLI, RoleMixin):
|
|
|
881
893
|
plugin_type = context.CLIARGS['type'].lower()
|
|
882
894
|
do_json = context.CLIARGS['json_format'] or context.CLIARGS['dump']
|
|
883
895
|
listing = context.CLIARGS['list_files'] or context.CLIARGS['list_dir']
|
|
896
|
+
no_fail = bool(not context.CLIARGS['no_fail_on_errors'])
|
|
884
897
|
|
|
885
898
|
if context.CLIARGS['list_files']:
|
|
886
899
|
content = 'files'
|
|
@@ -903,7 +916,6 @@ class DocCLI(CLI, RoleMixin):
|
|
|
903
916
|
docs['all'] = {}
|
|
904
917
|
for ptype in ptypes:
|
|
905
918
|
|
|
906
|
-
no_fail = bool(not context.CLIARGS['no_fail_on_errors'])
|
|
907
919
|
if ptype == 'role':
|
|
908
920
|
roles = self._create_role_list(fail_on_errors=no_fail)
|
|
909
921
|
docs['all'][ptype] = self._create_role_doc(roles.keys(), context.CLIARGS['entry_point'], fail_on_errors=no_fail)
|
|
@@ -929,7 +941,7 @@ class DocCLI(CLI, RoleMixin):
|
|
|
929
941
|
if plugin_type == 'keyword':
|
|
930
942
|
docs = DocCLI._get_keywords_docs(context.CLIARGS['args'])
|
|
931
943
|
elif plugin_type == 'role':
|
|
932
|
-
docs = self._create_role_doc(context.CLIARGS['args'], context.CLIARGS['entry_point'])
|
|
944
|
+
docs = self._create_role_doc(context.CLIARGS['args'], context.CLIARGS['entry_point'], fail_on_errors=no_fail)
|
|
933
945
|
else:
|
|
934
946
|
# display specific plugin docs
|
|
935
947
|
docs = self._get_plugins_docs(plugin_type, context.CLIARGS['args'])
|
|
@@ -1083,7 +1095,7 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1083
1095
|
text = DocCLI.get_man_text(doc, collection_name, plugin_type)
|
|
1084
1096
|
except Exception as e:
|
|
1085
1097
|
display.vvv(traceback.format_exc())
|
|
1086
|
-
raise AnsibleError("Unable to retrieve documentation from '%s'
|
|
1098
|
+
raise AnsibleError("Unable to retrieve documentation from '%s'" % (plugin), orig_exc=e)
|
|
1087
1099
|
|
|
1088
1100
|
return text
|
|
1089
1101
|
|
|
@@ -1189,7 +1201,7 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1189
1201
|
opt_leadin = "-"
|
|
1190
1202
|
key = "%s%s %s" % (base_indent, opt_leadin, _format(o, 'yellow'))
|
|
1191
1203
|
|
|
1192
|
-
# description is specifically
|
|
1204
|
+
# description is specifically formatted and can either be string or list of strings
|
|
1193
1205
|
if 'description' not in opt:
|
|
1194
1206
|
raise AnsibleError("All (sub-)options and return values must have a 'description' field")
|
|
1195
1207
|
text.append('')
|
|
@@ -1339,6 +1351,17 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1339
1351
|
# use empty indent since this affects the start of the yaml doc, not it's keys
|
|
1340
1352
|
text.append(DocCLI._indent_lines(DocCLI._dump_yaml({k.upper(): doc[k]}), ''))
|
|
1341
1353
|
|
|
1354
|
+
if doc.get('examples', False):
|
|
1355
|
+
text.append('')
|
|
1356
|
+
text.append(_format("EXAMPLES:", 'bold'))
|
|
1357
|
+
if isinstance(doc['examples'], string_types):
|
|
1358
|
+
text.append(doc.pop('examples').strip())
|
|
1359
|
+
else:
|
|
1360
|
+
try:
|
|
1361
|
+
text.append(yaml_dump(doc.pop('examples'), indent=2, default_flow_style=False))
|
|
1362
|
+
except Exception as e:
|
|
1363
|
+
raise AnsibleParserError("Unable to parse examples section", orig_exc=e)
|
|
1364
|
+
|
|
1342
1365
|
return text
|
|
1343
1366
|
|
|
1344
1367
|
@staticmethod
|
|
@@ -1370,16 +1393,15 @@ class DocCLI(CLI, RoleMixin):
|
|
|
1370
1393
|
if doc.get('deprecated', False):
|
|
1371
1394
|
text.append(_format("DEPRECATED: ", 'bold', 'DEP'))
|
|
1372
1395
|
if isinstance(doc['deprecated'], dict):
|
|
1373
|
-
if 'removed_at_date' in doc['deprecated']:
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
)
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
doc['deprecated']['removed_in'] = doc['deprecated']['version']
|
|
1380
|
-
text.append("\tReason: %(why)s\n\tWill be removed in: Ansible %(removed_in)s\n\tAlternatives: %(alternative)s" % doc.pop('deprecated'))
|
|
1396
|
+
if 'removed_at_date' not in doc['deprecated'] and 'version' in doc['deprecated'] and 'removed_in' not in doc['deprecated']:
|
|
1397
|
+
doc['deprecated']['removed_in'] = doc['deprecated']['version']
|
|
1398
|
+
try:
|
|
1399
|
+
text.append('\t' + C.config.get_deprecated_msg_from_config(doc['deprecated'], True))
|
|
1400
|
+
except KeyError as e:
|
|
1401
|
+
raise AnsibleError("Invalid deprecation documentation structure", orig_exc=e)
|
|
1381
1402
|
else:
|
|
1382
|
-
text.append("%s" % doc
|
|
1403
|
+
text.append("%s" % doc['deprecated'])
|
|
1404
|
+
del doc['deprecated']
|
|
1383
1405
|
|
|
1384
1406
|
if doc.pop('has_action', False):
|
|
1385
1407
|
text.append("")
|