ansible-core 2.17.5rc1__py3-none-any.whl → 2.18.0rc1__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 +3 -49
- 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 +34 -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 +10 -5
- 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 +8 -8
- 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 +2 -2
- 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/facts/timeout.py +1 -1
- 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 +25 -22
- ansible/modules/debug.py +1 -1
- ansible/modules/dnf.py +79 -164
- ansible/modules/dnf5.py +54 -29
- 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 +148 -13
- 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/plugins/__init__.py +2 -0
- ansible/plugins/action/__init__.py +7 -9
- ansible/plugins/action/dnf.py +7 -5
- ansible/plugins/action/package.py +5 -4
- 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/filter/unique.yml +28 -0
- 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 +18 -7
- ansible/plugins/strategy/linear.py +1 -13
- 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/galaxy.py +1 -1
- 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.0rc1.dist-info/Apache-License.txt +202 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/METADATA +36 -23
- ansible_core-2.18.0rc1.dist-info/MIT-license.txt +14 -0
- ansible_core-2.18.0rc1.dist-info/PSF-license.txt +48 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/RECORD +321 -316
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/entry_points.txt +1 -1
- ansible_core-2.18.0rc1.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 +6 -8
- 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 +10 -2
- ansible_test/_internal/encoding.py +4 -4
- 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 +56 -8
- 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/ansible-test-target.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +5 -0
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +6 -0
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +6 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -19
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +3 -4
- 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 +18 -24
- ansible_test/config/config.yml +1 -1
- ansible_core-2.17.5rc1.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.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/COPYING +0 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/WHEEL +0 -0
- {ansible_core-2.17.5rc1.dist-info → ansible_core-2.18.0rc1.dist-info}/top_level.txt +0 -0
ansible/playbook/base.py
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
+
import decimal
|
|
7
8
|
import itertools
|
|
8
9
|
import operator
|
|
9
10
|
import os
|
|
@@ -386,13 +387,13 @@ class FieldAttributeBase:
|
|
|
386
387
|
return fq_group_name, resolved_actions
|
|
387
388
|
|
|
388
389
|
def _resolve_action(self, action_name, mandatory=True):
|
|
389
|
-
context = module_loader.find_plugin_with_context(action_name)
|
|
390
|
+
context = module_loader.find_plugin_with_context(action_name, ignore_deprecated=(not mandatory))
|
|
390
391
|
if context.resolved and not context.action_plugin:
|
|
391
|
-
prefer = action_loader.find_plugin_with_context(action_name)
|
|
392
|
+
prefer = action_loader.find_plugin_with_context(action_name, ignore_deprecated=(not mandatory))
|
|
392
393
|
if prefer.resolved:
|
|
393
394
|
context = prefer
|
|
394
395
|
elif not context.resolved:
|
|
395
|
-
context = action_loader.find_plugin_with_context(action_name)
|
|
396
|
+
context = action_loader.find_plugin_with_context(action_name, ignore_deprecated=(not mandatory))
|
|
396
397
|
|
|
397
398
|
if context.resolved:
|
|
398
399
|
return context.resolved_fqcn
|
|
@@ -440,7 +441,13 @@ class FieldAttributeBase:
|
|
|
440
441
|
if attribute.isa == 'string':
|
|
441
442
|
value = to_text(value)
|
|
442
443
|
elif attribute.isa == 'int':
|
|
443
|
-
|
|
444
|
+
if not isinstance(value, int):
|
|
445
|
+
try:
|
|
446
|
+
if (decimal_value := decimal.Decimal(value)) != (int_value := int(decimal_value)):
|
|
447
|
+
raise decimal.DecimalException(f'Floating-point value {value!r} would be truncated.')
|
|
448
|
+
value = int_value
|
|
449
|
+
except decimal.DecimalException as e:
|
|
450
|
+
raise ValueError from e
|
|
444
451
|
elif attribute.isa == 'float':
|
|
445
452
|
value = float(value)
|
|
446
453
|
elif attribute.isa == 'bool':
|
|
@@ -574,9 +581,7 @@ class FieldAttributeBase:
|
|
|
574
581
|
|
|
575
582
|
def _load_vars(self, attr, ds):
|
|
576
583
|
'''
|
|
577
|
-
Vars in a play
|
|
578
|
-
as a list of dictionaries. If the later, this method will turn the
|
|
579
|
-
list into a single dictionary.
|
|
584
|
+
Vars in a play must be specified as a dictionary.
|
|
580
585
|
'''
|
|
581
586
|
|
|
582
587
|
def _validate_variable_keys(ds):
|
|
@@ -588,22 +593,6 @@ class FieldAttributeBase:
|
|
|
588
593
|
if isinstance(ds, dict):
|
|
589
594
|
_validate_variable_keys(ds)
|
|
590
595
|
return combine_vars(self.vars, ds)
|
|
591
|
-
elif isinstance(ds, list):
|
|
592
|
-
line_file = getattr(ds, 'ansible_pos', ("unknown", 0))
|
|
593
|
-
display.deprecated(
|
|
594
|
-
(
|
|
595
|
-
'Specifying a list of dictionaries for vars is deprecated in favor of '
|
|
596
|
-
'specifying a dictionary. Error occurred in the file: %s, line: %d' % (line_file[0], line_file[1])
|
|
597
|
-
),
|
|
598
|
-
version='2.18'
|
|
599
|
-
)
|
|
600
|
-
all_vars = self.vars
|
|
601
|
-
for item in ds:
|
|
602
|
-
if not isinstance(item, dict):
|
|
603
|
-
raise ValueError
|
|
604
|
-
_validate_variable_keys(item)
|
|
605
|
-
all_vars = combine_vars(all_vars, item)
|
|
606
|
-
return all_vars
|
|
607
596
|
elif ds is None:
|
|
608
597
|
return {}
|
|
609
598
|
else:
|
ansible/playbook/helpers.py
CHANGED
|
@@ -293,8 +293,12 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
|
|
|
293
293
|
else:
|
|
294
294
|
if use_handlers:
|
|
295
295
|
t = Handler.load(task_ds, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader)
|
|
296
|
+
if t.action in C._ACTION_META and t.args.get('_raw_params') == "end_role":
|
|
297
|
+
raise AnsibleParserError("Cannot execute 'end_role' from a handler")
|
|
296
298
|
else:
|
|
297
299
|
t = Task.load(task_ds, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader)
|
|
300
|
+
if t.action in C._ACTION_META and t.args.get('_raw_params') == "end_role" and role is None:
|
|
301
|
+
raise AnsibleParserError("Cannot execute 'end_role' from outside of a role")
|
|
298
302
|
|
|
299
303
|
task_list.append(t)
|
|
300
304
|
|
ansible/playbook/loop_control.py
CHANGED
|
@@ -29,6 +29,7 @@ class LoopControl(FieldAttributeBase):
|
|
|
29
29
|
pause = NonInheritableFieldAttribute(isa='float', default=0, always_post_validate=True)
|
|
30
30
|
extended = NonInheritableFieldAttribute(isa='bool', always_post_validate=True)
|
|
31
31
|
extended_allitems = NonInheritableFieldAttribute(isa='bool', default=True, always_post_validate=True)
|
|
32
|
+
break_when = NonInheritableFieldAttribute(isa='list', default=list)
|
|
32
33
|
|
|
33
34
|
def __init__(self):
|
|
34
35
|
super(LoopControl, self).__init__()
|
|
@@ -37,3 +38,10 @@ class LoopControl(FieldAttributeBase):
|
|
|
37
38
|
def load(data, variable_manager=None, loader=None):
|
|
38
39
|
t = LoopControl()
|
|
39
40
|
return t.load_data(data, variable_manager=variable_manager, loader=loader)
|
|
41
|
+
|
|
42
|
+
def _post_validate_break_when(self, attr, value, templar):
|
|
43
|
+
'''
|
|
44
|
+
break_when is evaluated after the execution of the loop is complete,
|
|
45
|
+
and should not be templated during the regular post_validate step.
|
|
46
|
+
'''
|
|
47
|
+
return value
|
ansible/playbook/play.py
CHANGED
|
@@ -28,7 +28,7 @@ from ansible.playbook.base import Base
|
|
|
28
28
|
from ansible.playbook.block import Block
|
|
29
29
|
from ansible.playbook.collectionsearch import CollectionSearch
|
|
30
30
|
from ansible.playbook.helpers import load_list_of_blocks, load_list_of_roles
|
|
31
|
-
from ansible.playbook.role import Role
|
|
31
|
+
from ansible.playbook.role import Role
|
|
32
32
|
from ansible.playbook.task import Task
|
|
33
33
|
from ansible.playbook.taggable import Taggable
|
|
34
34
|
from ansible.vars.manager import preprocess_vars
|
|
@@ -57,11 +57,9 @@ class Play(Base, Taggable, CollectionSearch):
|
|
|
57
57
|
|
|
58
58
|
# Facts
|
|
59
59
|
gather_facts = NonInheritableFieldAttribute(isa='bool', default=None, always_post_validate=True)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
gather_timeout = NonInheritableFieldAttribute(isa='int', default=C.DEFAULT_GATHER_TIMEOUT, always_post_validate=True)
|
|
64
|
-
fact_path = NonInheritableFieldAttribute(isa='string', default=C.DEFAULT_FACT_PATH)
|
|
60
|
+
gather_subset = NonInheritableFieldAttribute(isa='list', default=None, listof=string_types, always_post_validate=True)
|
|
61
|
+
gather_timeout = NonInheritableFieldAttribute(isa='int', default=None, always_post_validate=True)
|
|
62
|
+
fact_path = NonInheritableFieldAttribute(isa='string', default=None)
|
|
65
63
|
|
|
66
64
|
# Variable Attributes
|
|
67
65
|
vars_files = NonInheritableFieldAttribute(isa='list', default=list, priority=99)
|
|
@@ -102,22 +100,6 @@ class Play(Base, Taggable, CollectionSearch):
|
|
|
102
100
|
def __repr__(self):
|
|
103
101
|
return self.get_name()
|
|
104
102
|
|
|
105
|
-
@property
|
|
106
|
-
def ROLE_CACHE(self):
|
|
107
|
-
"""Backwards compat for custom strategies using ``play.ROLE_CACHE``
|
|
108
|
-
"""
|
|
109
|
-
display.deprecated(
|
|
110
|
-
'Play.ROLE_CACHE is deprecated in favor of Play.role_cache, or StrategyBase._get_cached_role',
|
|
111
|
-
version='2.18',
|
|
112
|
-
)
|
|
113
|
-
cache = {}
|
|
114
|
-
for path, roles in self.role_cache.items():
|
|
115
|
-
for role in roles:
|
|
116
|
-
name = role.get_name()
|
|
117
|
-
hashed_params = hash_params(role._get_hash_dict())
|
|
118
|
-
cache.setdefault(name, {})[hashed_params] = role
|
|
119
|
-
return cache
|
|
120
|
-
|
|
121
103
|
def _validate_hosts(self, attribute, name, value):
|
|
122
104
|
# Only validate 'hosts' if a value was passed in to original data set.
|
|
123
105
|
if 'hosts' in self._ds:
|
ansible/playbook/play_context.py
CHANGED
|
@@ -113,22 +113,6 @@ class PlayContext(Base):
|
|
|
113
113
|
# "PlayContext.force_handlers should not be used, the calling code should be using play itself instead"
|
|
114
114
|
force_handlers = FieldAttribute(isa='bool', default=False)
|
|
115
115
|
|
|
116
|
-
@property
|
|
117
|
-
def verbosity(self):
|
|
118
|
-
display.deprecated(
|
|
119
|
-
"PlayContext.verbosity is deprecated, use ansible.utils.display.Display.verbosity instead.",
|
|
120
|
-
version="2.18"
|
|
121
|
-
)
|
|
122
|
-
return self._internal_verbosity
|
|
123
|
-
|
|
124
|
-
@verbosity.setter
|
|
125
|
-
def verbosity(self, value):
|
|
126
|
-
display.deprecated(
|
|
127
|
-
"PlayContext.verbosity is deprecated, use ansible.utils.display.Display.verbosity instead.",
|
|
128
|
-
version="2.18"
|
|
129
|
-
)
|
|
130
|
-
self._internal_verbosity = value
|
|
131
|
-
|
|
132
116
|
def __init__(self, play=None, passwords=None, connection_lockfd=None):
|
|
133
117
|
# Note: play is really not optional. The only time it could be omitted is when we create
|
|
134
118
|
# a PlayContext just so we can invoke its deserialize method to load it from a serialized
|
|
@@ -90,7 +90,7 @@ class PlaybookInclude(Base, Conditional, Taggable):
|
|
|
90
90
|
# it is a collection playbook, setup default collections
|
|
91
91
|
AnsibleCollectionConfig.default_collection = playbook_collection
|
|
92
92
|
else:
|
|
93
|
-
# it is NOT a collection playbook, setup
|
|
93
|
+
# it is NOT a collection playbook, setup adjacent paths
|
|
94
94
|
AnsibleCollectionConfig.playbook_paths.append(os.path.dirname(os.path.abspath(to_bytes(playbook, errors='surrogate_or_strict'))))
|
|
95
95
|
|
|
96
96
|
pb._load_playbook_data(file_name=playbook, variable_manager=variable_manager, vars=self.vars.copy())
|
|
@@ -123,7 +123,7 @@ class PlaybookInclude(Base, Conditional, Taggable):
|
|
|
123
123
|
|
|
124
124
|
def preprocess_data(self, ds):
|
|
125
125
|
'''
|
|
126
|
-
|
|
126
|
+
Reorganizes the data for a PlaybookInclude datastructure to line
|
|
127
127
|
up with what we expect the proper attributes to be
|
|
128
128
|
'''
|
|
129
129
|
|
|
@@ -107,7 +107,7 @@ class Role(Base, Conditional, Taggable, CollectionSearch, Delegatable):
|
|
|
107
107
|
self.static = static
|
|
108
108
|
|
|
109
109
|
# includes (static=false) default to private, while imports (static=true) default to public
|
|
110
|
-
# but both can be
|
|
110
|
+
# but both can be overridden by global config if set
|
|
111
111
|
if public is None:
|
|
112
112
|
global_private, origin = C.config.get_config_value_and_origin('DEFAULT_PRIVATE_ROLE_VARS')
|
|
113
113
|
if origin == 'default':
|
|
@@ -508,7 +508,7 @@ class Role(Base, Conditional, Taggable, CollectionSearch, Delegatable):
|
|
|
508
508
|
# get exported variables from meta/dependencies
|
|
509
509
|
seen = []
|
|
510
510
|
for dep in self.get_all_dependencies():
|
|
511
|
-
# Avoid
|
|
511
|
+
# Avoid rerunning dupe deps since they can have vars from previous invocations and they accumulate in deps
|
|
512
512
|
# TODO: re-examine dep loading to see if we are somehow improperly adding the same dep too many times
|
|
513
513
|
if dep not in seen:
|
|
514
514
|
# only take 'exportable' vars from deps
|
ansible/plugins/__init__.py
CHANGED
|
@@ -99,6 +99,7 @@ class AnsiblePlugin(ABC):
|
|
|
99
99
|
|
|
100
100
|
def set_option(self, option, value):
|
|
101
101
|
self._options[option] = C.config.get_config_value(option, plugin_type=self.plugin_type, plugin_name=self._load_name, direct={option: value})
|
|
102
|
+
C.handle_config_noise(display)
|
|
102
103
|
|
|
103
104
|
def set_options(self, task_keys=None, var_options=None, direct=None):
|
|
104
105
|
'''
|
|
@@ -115,6 +116,7 @@ class AnsiblePlugin(ABC):
|
|
|
115
116
|
if self.allow_extras and var_options and '_extras' in var_options:
|
|
116
117
|
# these are largely unvalidated passthroughs, either plugin or underlying API will validate
|
|
117
118
|
self._options['_extras'] = var_options['_extras']
|
|
119
|
+
C.handle_config_noise(display)
|
|
118
120
|
|
|
119
121
|
def has_option(self, option):
|
|
120
122
|
if not self._options:
|
|
@@ -8,8 +8,8 @@ from __future__ import annotations
|
|
|
8
8
|
import base64
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
11
|
-
import random
|
|
12
11
|
import re
|
|
12
|
+
import secrets
|
|
13
13
|
import shlex
|
|
14
14
|
import stat
|
|
15
15
|
import tempfile
|
|
@@ -146,7 +146,7 @@ class ActionBase(ABC):
|
|
|
146
146
|
Be cautious when directly passing ``new_module_args`` directly to a
|
|
147
147
|
module invocation, as it will contain the defaults, and not only
|
|
148
148
|
the args supplied from the task. If you do this, the module
|
|
149
|
-
should not define ``
|
|
149
|
+
should not define ``mutually_exclusive`` or similar.
|
|
150
150
|
|
|
151
151
|
This code is roughly copied from the ``validate_argument_spec``
|
|
152
152
|
action plugin for use by other action plugins.
|
|
@@ -1114,7 +1114,7 @@ class ActionBase(ABC):
|
|
|
1114
1114
|
remote_files.append(remote_async_module_path)
|
|
1115
1115
|
|
|
1116
1116
|
async_limit = self._task.async_val
|
|
1117
|
-
async_jid = f'j{
|
|
1117
|
+
async_jid = f'j{secrets.randbelow(999999999999)}'
|
|
1118
1118
|
|
|
1119
1119
|
# call the interpreter for async_wrapper directly
|
|
1120
1120
|
# this permits use of a script for an interpreter on non-Linux platforms
|
|
@@ -1226,15 +1226,13 @@ class ActionBase(ABC):
|
|
|
1226
1226
|
try:
|
|
1227
1227
|
_validate_utf8_json(data)
|
|
1228
1228
|
except UnicodeEncodeError:
|
|
1229
|
-
|
|
1230
|
-
display.deprecated(
|
|
1229
|
+
raise ValueError(
|
|
1231
1230
|
f'Module "{self._task.resolved_action or self._task.action}" returned non UTF-8 data in '
|
|
1232
|
-
'the JSON response.
|
|
1233
|
-
version='2.18',
|
|
1231
|
+
'the JSON response.',
|
|
1234
1232
|
)
|
|
1235
1233
|
|
|
1236
1234
|
data['_ansible_parsed'] = True
|
|
1237
|
-
except ValueError:
|
|
1235
|
+
except ValueError as e:
|
|
1238
1236
|
# not valid json, lets try to capture error
|
|
1239
1237
|
data = dict(failed=True, _ansible_parsed=False)
|
|
1240
1238
|
data['module_stdout'] = res.get('stdout', u'')
|
|
@@ -1248,7 +1246,7 @@ class ActionBase(ABC):
|
|
|
1248
1246
|
data['exception'] = data['module_stdout']
|
|
1249
1247
|
|
|
1250
1248
|
# The default
|
|
1251
|
-
data['msg'] = "MODULE FAILURE"
|
|
1249
|
+
data['msg'] = f"MODULE FAILURE: {e}"
|
|
1252
1250
|
|
|
1253
1251
|
# try to figure out if we are missing interpreter
|
|
1254
1252
|
if self._used_interpreter is not None:
|
ansible/plugins/action/dnf.py
CHANGED
|
@@ -41,6 +41,13 @@ class ActionModule(ActionBase):
|
|
|
41
41
|
facts = self._execute_module(
|
|
42
42
|
module_name="ansible.legacy.setup", module_args=dict(filter="ansible_pkg_mgr", gather_subset="!all"),
|
|
43
43
|
task_vars=task_vars)
|
|
44
|
+
|
|
45
|
+
if facts.get("failed", False):
|
|
46
|
+
raise AnsibleActionFail(
|
|
47
|
+
f"Failed to fetch ansible_pkg_mgr to determine the dnf action backend: {facts.get('msg')}",
|
|
48
|
+
result=facts,
|
|
49
|
+
)
|
|
50
|
+
|
|
44
51
|
display.debug("Facts %s" % facts)
|
|
45
52
|
module = facts.get("ansible_facts", {}).get("ansible_pkg_mgr", "auto")
|
|
46
53
|
if (not self._task.delegate_to or self._task.delegate_facts) and module != 'auto':
|
|
@@ -75,9 +82,4 @@ class ActionModule(ActionBase):
|
|
|
75
82
|
result.update(self._execute_module(
|
|
76
83
|
module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task.async_val))
|
|
77
84
|
|
|
78
|
-
# Cleanup
|
|
79
|
-
if not self._task.async_val:
|
|
80
|
-
# remove a temporary path we created
|
|
81
|
-
self._remove_tmp_path(self._connection._shell.tmpdir)
|
|
82
|
-
|
|
83
85
|
return result
|
|
@@ -68,6 +68,11 @@ class ActionModule(ActionBase):
|
|
|
68
68
|
module_args=dict(filter='ansible_pkg_mgr', gather_subset='!all'),
|
|
69
69
|
task_vars=task_vars,
|
|
70
70
|
)
|
|
71
|
+
if facts.get("failed", False):
|
|
72
|
+
raise AnsibleActionFail(
|
|
73
|
+
f"Failed to fetch ansible_pkg_mgr to determine the package action backend: {facts.get('msg')}",
|
|
74
|
+
result=facts,
|
|
75
|
+
)
|
|
71
76
|
pmgr = 'ansible_pkg_mgr'
|
|
72
77
|
|
|
73
78
|
try:
|
|
@@ -103,9 +108,5 @@ class ActionModule(ActionBase):
|
|
|
103
108
|
|
|
104
109
|
except AnsibleAction as e:
|
|
105
110
|
result.update(e.result)
|
|
106
|
-
finally:
|
|
107
|
-
if not self._task.async_val:
|
|
108
|
-
# remove a temporary path we created
|
|
109
|
-
self._remove_tmp_path(self._connection._shell.tmpdir)
|
|
110
111
|
|
|
111
112
|
return result
|
ansible/plugins/action/reboot.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import secrets
|
|
8
8
|
import time
|
|
9
9
|
|
|
10
10
|
from datetime import datetime, timedelta, timezone
|
|
@@ -304,7 +304,7 @@ class ActionModule(ActionBase):
|
|
|
304
304
|
except AnsibleConnectionFailure:
|
|
305
305
|
pass
|
|
306
306
|
# Use exponential backoff with a max timeout, plus a little bit of randomness
|
|
307
|
-
random_int =
|
|
307
|
+
random_int = secrets.randbelow(1000) / 1000
|
|
308
308
|
fail_sleep = 2 ** fail_count + random_int
|
|
309
309
|
if fail_sleep > max_fail_sleep:
|
|
310
310
|
|
|
@@ -22,6 +22,7 @@ import json
|
|
|
22
22
|
import re
|
|
23
23
|
import sys
|
|
24
24
|
import textwrap
|
|
25
|
+
from typing import TYPE_CHECKING
|
|
25
26
|
|
|
26
27
|
from collections import OrderedDict
|
|
27
28
|
from collections.abc import MutableMapping
|
|
@@ -41,6 +42,9 @@ from ansible.vars.clean import strip_internal_keys, module_response_deepcopy
|
|
|
41
42
|
|
|
42
43
|
import yaml
|
|
43
44
|
|
|
45
|
+
if TYPE_CHECKING:
|
|
46
|
+
from ansible.executor.task_result import TaskResult
|
|
47
|
+
|
|
44
48
|
global_display = Display()
|
|
45
49
|
|
|
46
50
|
|
|
@@ -503,15 +507,52 @@ class CallbackBase(AnsiblePlugin):
|
|
|
503
507
|
def v2_on_any(self, *args, **kwargs):
|
|
504
508
|
self.on_any(args, kwargs)
|
|
505
509
|
|
|
506
|
-
def v2_runner_on_failed(self, result, ignore_errors=False):
|
|
510
|
+
def v2_runner_on_failed(self, result: TaskResult, ignore_errors: bool = False) -> None:
|
|
511
|
+
"""Get details about a failed task and whether or not Ansible should continue
|
|
512
|
+
running tasks on the host where the failure occurred, then process the details
|
|
513
|
+
as required by the callback (output, profiling, logging, notifications, etc.)
|
|
514
|
+
|
|
515
|
+
Note: The 'ignore_errors' directive only works when the task can run and returns
|
|
516
|
+
a value of 'failed'. It does not make Ansible ignore undefined variable errors,
|
|
517
|
+
connection failures, execution issues (for example, missing packages), or syntax errors.
|
|
518
|
+
|
|
519
|
+
Customization note: For more information about the attributes and methods of the
|
|
520
|
+
TaskResult class, see lib/ansible/executor/task_result.py.
|
|
521
|
+
|
|
522
|
+
:param TaskResult result: An object that contains details about the task
|
|
523
|
+
:param bool ignore_errors: Whether or not Ansible should continue running tasks on the host
|
|
524
|
+
where the failure occurred
|
|
525
|
+
|
|
526
|
+
:return: None
|
|
527
|
+
"""
|
|
507
528
|
host = result._host.get_name()
|
|
508
529
|
self.runner_on_failed(host, result._result, ignore_errors)
|
|
509
530
|
|
|
510
|
-
def v2_runner_on_ok(self, result):
|
|
531
|
+
def v2_runner_on_ok(self, result: TaskResult) -> None:
|
|
532
|
+
"""Get details about a successful task and process them as required by the callback
|
|
533
|
+
(output, profiling, logging, notifications, etc.)
|
|
534
|
+
|
|
535
|
+
Customization note: For more information about the attributes and methods of the
|
|
536
|
+
TaskResult class, see lib/ansible/executor/task_result.py.
|
|
537
|
+
|
|
538
|
+
:param TaskResult result: An object that contains details about the task
|
|
539
|
+
|
|
540
|
+
:return: None
|
|
541
|
+
"""
|
|
511
542
|
host = result._host.get_name()
|
|
512
543
|
self.runner_on_ok(host, result._result)
|
|
513
544
|
|
|
514
|
-
def v2_runner_on_skipped(self, result):
|
|
545
|
+
def v2_runner_on_skipped(self, result: TaskResult) -> None:
|
|
546
|
+
"""Get details about a skipped task and process them as required by the callback
|
|
547
|
+
(output, profiling, logging, notifications, etc.)
|
|
548
|
+
|
|
549
|
+
Customization note: For more information about the attributes and methods of the
|
|
550
|
+
TaskResult class, see lib/ansible/executor/task_result.py.
|
|
551
|
+
|
|
552
|
+
:param TaskResult result: An object that contains details about the task
|
|
553
|
+
|
|
554
|
+
:return: None
|
|
555
|
+
"""
|
|
515
556
|
if C.DISPLAY_SKIPPED_HOSTS:
|
|
516
557
|
host = result._host.get_name()
|
|
517
558
|
self.runner_on_skipped(host, self._get_item_label(getattr(result._result, 'results', {})))
|
|
@@ -293,7 +293,7 @@ class CallbackModule(CallbackBase):
|
|
|
293
293
|
label = self._get_item_label(included_file._vars)
|
|
294
294
|
if label:
|
|
295
295
|
msg += " => (item=%s)" % label
|
|
296
|
-
self._display.display(msg, color=C.
|
|
296
|
+
self._display.display(msg, color=C.COLOR_INCLUDED)
|
|
297
297
|
|
|
298
298
|
def v2_playbook_on_stats(self, stats):
|
|
299
299
|
self._display.banner("PLAY RECAP")
|
|
@@ -263,7 +263,7 @@ class CliconfBase(AnsiblePlugin):
|
|
|
263
263
|
'supports_commit_comment': <bool>, # identify if adding comment to commit is supported of not
|
|
264
264
|
'supports_onbox_diff': <bool>, # identify if on box diff capability is supported or not
|
|
265
265
|
'supports_generate_diff': <bool>, # identify if diff capability is supported within plugin
|
|
266
|
-
'supports_multiline_delimiter': <bool>, # identify if multiline
|
|
266
|
+
'supports_multiline_delimiter': <bool>, # identify if multiline delimiter is supported within config
|
|
267
267
|
'supports_diff_match': <bool>, # identify if match is supported
|
|
268
268
|
'supports_diff_ignore_lines': <bool>, # identify if ignore line in diff is supported
|
|
269
269
|
'supports_config_replace': <bool>, # identify if running config replace with candidate config is supported
|
|
@@ -111,8 +111,7 @@ DOCUMENTATION = """
|
|
|
111
111
|
proxy_command:
|
|
112
112
|
default: ''
|
|
113
113
|
description:
|
|
114
|
-
- Proxy information for running the connection via a jumphost
|
|
115
|
-
- Also this plugin will scan 'ssh_args', 'ssh_extra_args' and 'ssh_common_args' from the 'ssh' plugin settings for proxy information if set.
|
|
114
|
+
- Proxy information for running the connection via a jumphost.
|
|
116
115
|
type: string
|
|
117
116
|
env: [{name: ANSIBLE_PARAMIKO_PROXY_COMMAND}]
|
|
118
117
|
ini:
|
|
@@ -120,60 +119,6 @@ DOCUMENTATION = """
|
|
|
120
119
|
vars:
|
|
121
120
|
- name: ansible_paramiko_proxy_command
|
|
122
121
|
version_added: '2.15'
|
|
123
|
-
ssh_args:
|
|
124
|
-
description: Only used in parsing ProxyCommand for use in this plugin.
|
|
125
|
-
default: ''
|
|
126
|
-
type: string
|
|
127
|
-
ini:
|
|
128
|
-
- section: 'ssh_connection'
|
|
129
|
-
key: 'ssh_args'
|
|
130
|
-
env:
|
|
131
|
-
- name: ANSIBLE_SSH_ARGS
|
|
132
|
-
vars:
|
|
133
|
-
- name: ansible_ssh_args
|
|
134
|
-
version_added: '2.7'
|
|
135
|
-
deprecated:
|
|
136
|
-
why: In favor of the "proxy_command" option.
|
|
137
|
-
version: "2.18"
|
|
138
|
-
alternatives: proxy_command
|
|
139
|
-
ssh_common_args:
|
|
140
|
-
description: Only used in parsing ProxyCommand for use in this plugin.
|
|
141
|
-
type: string
|
|
142
|
-
ini:
|
|
143
|
-
- section: 'ssh_connection'
|
|
144
|
-
key: 'ssh_common_args'
|
|
145
|
-
version_added: '2.7'
|
|
146
|
-
env:
|
|
147
|
-
- name: ANSIBLE_SSH_COMMON_ARGS
|
|
148
|
-
version_added: '2.7'
|
|
149
|
-
vars:
|
|
150
|
-
- name: ansible_ssh_common_args
|
|
151
|
-
cli:
|
|
152
|
-
- name: ssh_common_args
|
|
153
|
-
default: ''
|
|
154
|
-
deprecated:
|
|
155
|
-
why: In favor of the "proxy_command" option.
|
|
156
|
-
version: "2.18"
|
|
157
|
-
alternatives: proxy_command
|
|
158
|
-
ssh_extra_args:
|
|
159
|
-
description: Only used in parsing ProxyCommand for use in this plugin.
|
|
160
|
-
type: string
|
|
161
|
-
vars:
|
|
162
|
-
- name: ansible_ssh_extra_args
|
|
163
|
-
env:
|
|
164
|
-
- name: ANSIBLE_SSH_EXTRA_ARGS
|
|
165
|
-
version_added: '2.7'
|
|
166
|
-
ini:
|
|
167
|
-
- key: ssh_extra_args
|
|
168
|
-
section: ssh_connection
|
|
169
|
-
version_added: '2.7'
|
|
170
|
-
cli:
|
|
171
|
-
- name: ssh_extra_args
|
|
172
|
-
default: ''
|
|
173
|
-
deprecated:
|
|
174
|
-
why: In favor of the "proxy_command" option.
|
|
175
|
-
version: "2.18"
|
|
176
|
-
alternatives: proxy_command
|
|
177
122
|
pty:
|
|
178
123
|
default: True
|
|
179
124
|
description: 'SUDO usually requires a PTY, True to give a PTY and False to not give a PTY.'
|
|
@@ -399,30 +344,7 @@ class Connection(ConnectionBase):
|
|
|
399
344
|
self._log_channel = name
|
|
400
345
|
|
|
401
346
|
def _parse_proxy_command(self, port: int = 22) -> dict[str, t.Any]:
|
|
402
|
-
proxy_command = None
|
|
403
|
-
# Parse ansible_ssh_common_args, specifically looking for ProxyCommand
|
|
404
|
-
ssh_args = [
|
|
405
|
-
self.get_option('ssh_extra_args'),
|
|
406
|
-
self.get_option('ssh_common_args'),
|
|
407
|
-
self.get_option('ssh_args', ''),
|
|
408
|
-
]
|
|
409
|
-
|
|
410
|
-
args = self._split_ssh_args(' '.join(ssh_args))
|
|
411
|
-
for i, arg in enumerate(args):
|
|
412
|
-
if arg.lower() == 'proxycommand':
|
|
413
|
-
# _split_ssh_args split ProxyCommand from the command itself
|
|
414
|
-
proxy_command = args[i + 1]
|
|
415
|
-
else:
|
|
416
|
-
# ProxyCommand and the command itself are a single string
|
|
417
|
-
match = SETTINGS_REGEX.match(arg)
|
|
418
|
-
if match:
|
|
419
|
-
if match.group(1).lower() == 'proxycommand':
|
|
420
|
-
proxy_command = match.group(2)
|
|
421
|
-
|
|
422
|
-
if proxy_command:
|
|
423
|
-
break
|
|
424
|
-
|
|
425
|
-
proxy_command = self.get_option('proxy_command') or proxy_command
|
|
347
|
+
proxy_command = self.get_option('proxy_command') or None
|
|
426
348
|
|
|
427
349
|
sock_kwarg = {}
|
|
428
350
|
if proxy_command:
|