ansible-core 2.19.4rc1__py3-none-any.whl → 2.20.0__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/_internal/__init__.py +1 -4
- ansible/_internal/_ansiballz/_builder.py +1 -3
- ansible/_internal/_collection_proxy.py +7 -9
- ansible/_internal/_json/__init__.py +3 -4
- ansible/_internal/_templating/_engine.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +1 -2
- ansible/_internal/_wrapt.py +105 -301
- ansible/cli/__init__.py +11 -10
- ansible/cli/adhoc.py +1 -2
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/config.py +5 -6
- ansible/cli/doc.py +67 -67
- ansible/cli/galaxy.py +15 -24
- ansible/cli/inventory.py +0 -1
- ansible/cli/playbook.py +0 -1
- ansible/cli/pull.py +0 -1
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
- ansible/config/base.yml +1 -25
- ansible/config/manager.py +0 -2
- ansible/executor/play_iterator.py +42 -20
- ansible/executor/playbook_executor.py +0 -9
- ansible/executor/task_executor.py +26 -18
- ansible/executor/task_queue_manager.py +1 -3
- ansible/galaxy/api.py +33 -80
- ansible/galaxy/collection/__init__.py +11 -21
- ansible/galaxy/dependency_resolution/__init__.py +10 -9
- ansible/galaxy/dependency_resolution/dataclasses.py +86 -70
- ansible/galaxy/dependency_resolution/providers.py +54 -134
- ansible/galaxy/dependency_resolution/versioning.py +2 -4
- ansible/galaxy/role.py +1 -33
- ansible/inventory/manager.py +2 -3
- ansible/keyword_desc.yml +0 -3
- ansible/module_utils/_internal/_datatag/__init__.py +2 -10
- ansible/module_utils/_internal/_no_six.py +86 -0
- ansible/module_utils/_text.py +28 -8
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/basic.py +26 -23
- ansible/module_utils/common/_collections_compat.py +11 -2
- ansible/module_utils/common/collections.py +8 -3
- ansible/module_utils/common/dict_transformations.py +1 -2
- ansible/module_utils/common/network.py +4 -2
- ansible/module_utils/common/parameters.py +32 -41
- ansible/module_utils/common/text/converters.py +109 -23
- ansible/module_utils/common/text/formatters.py +6 -2
- ansible/module_utils/common/validation.py +11 -9
- ansible/module_utils/connection.py +8 -3
- ansible/module_utils/facts/hardware/linux.py +23 -7
- ansible/module_utils/facts/hardware/netbsd.py +1 -1
- ansible/module_utils/facts/hardware/sunos.py +2 -1
- ansible/module_utils/facts/packages.py +6 -2
- ansible/module_utils/facts/system/distribution.py +2 -1
- ansible/module_utils/facts/system/env.py +6 -3
- ansible/module_utils/facts/system/local.py +3 -1
- ansible/module_utils/parsing/convert_bool.py +6 -2
- ansible/module_utils/service.py +2 -3
- ansible/module_utils/six/__init__.py +11 -6
- ansible/module_utils/yumdnf.py +0 -5
- ansible/modules/apt.py +18 -13
- ansible/modules/apt_repository.py +1 -1
- ansible/modules/assemble.py +5 -9
- ansible/modules/blockinfile.py +39 -23
- ansible/modules/cron.py +26 -35
- ansible/modules/deb822_repository.py +83 -12
- ansible/modules/dnf.py +3 -7
- ansible/modules/dnf5.py +4 -6
- ansible/modules/expect.py +0 -3
- ansible/modules/find.py +1 -2
- ansible/modules/get_url.py +1 -1
- ansible/modules/git.py +4 -5
- ansible/modules/include_vars.py +1 -1
- ansible/modules/known_hosts.py +7 -1
- ansible/modules/lineinfile.py +71 -63
- ansible/modules/package_facts.py +1 -1
- ansible/modules/pip.py +8 -2
- ansible/modules/replace.py +6 -6
- ansible/modules/service.py +3 -4
- ansible/modules/stat.py +20 -0
- ansible/modules/uri.py +9 -10
- ansible/modules/user.py +1 -2
- ansible/modules/wait_for.py +2 -2
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +1 -16
- ansible/parsing/dataloader.py +24 -31
- ansible/parsing/vault/__init__.py +1 -2
- ansible/playbook/base.py +8 -56
- ansible/playbook/block.py +0 -60
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/handler.py +1 -7
- ansible/playbook/helpers.py +0 -7
- ansible/playbook/included_file.py +1 -1
- ansible/playbook/play.py +102 -36
- ansible/playbook/play_context.py +4 -0
- ansible/playbook/role/__init__.py +10 -65
- ansible/playbook/role/definition.py +3 -4
- ansible/playbook/role/include.py +2 -3
- ansible/playbook/role/metadata.py +1 -12
- ansible/playbook/role/requirement.py +1 -2
- ansible/playbook/role_include.py +1 -2
- ansible/playbook/taggable.py +16 -5
- ansible/playbook/task.py +11 -50
- ansible/plugins/action/__init__.py +20 -19
- ansible/plugins/action/add_host.py +1 -2
- ansible/plugins/action/fetch.py +3 -5
- ansible/plugins/action/group_by.py +1 -2
- ansible/plugins/action/include_vars.py +20 -22
- ansible/plugins/action/script.py +1 -3
- ansible/plugins/action/template.py +1 -2
- ansible/plugins/action/uri.py +4 -2
- ansible/plugins/cache/__init__.py +1 -0
- ansible/plugins/callback/__init__.py +13 -6
- ansible/plugins/connection/__init__.py +3 -7
- ansible/plugins/connection/local.py +2 -3
- ansible/plugins/connection/psrp.py +0 -2
- ansible/plugins/connection/ssh.py +2 -7
- ansible/plugins/connection/winrm.py +0 -2
- ansible/plugins/doc_fragments/result_format_callback.py +15 -0
- ansible/plugins/filter/core.py +4 -5
- ansible/plugins/filter/encryption.py +3 -27
- ansible/plugins/filter/mathstuff.py +1 -2
- ansible/plugins/filter/to_nice_yaml.yml +31 -3
- ansible/plugins/filter/to_yaml.yml +29 -12
- ansible/plugins/inventory/__init__.py +1 -2
- ansible/plugins/inventory/toml.py +3 -6
- ansible/plugins/inventory/yaml.py +1 -2
- ansible/plugins/loader.py +3 -4
- ansible/plugins/lookup/password.py +1 -2
- ansible/plugins/lookup/subelements.py +2 -3
- ansible/plugins/lookup/url.py +1 -1
- ansible/plugins/lookup/varnames.py +1 -2
- ansible/plugins/shell/__init__.py +9 -4
- ansible/plugins/shell/powershell.py +8 -24
- ansible/plugins/strategy/__init__.py +5 -2
- ansible/plugins/test/core.py +4 -1
- ansible/plugins/test/falsy.yml +1 -1
- ansible/plugins/test/regex.yml +18 -6
- ansible/plugins/test/truthy.yml +1 -1
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -7
- ansible/utils/collection_loader/_collection_config.py +5 -0
- ansible/utils/collection_loader/_collection_finder.py +11 -14
- ansible/utils/context_objects.py +7 -4
- ansible/utils/display.py +7 -6
- ansible/utils/encrypt.py +0 -5
- ansible/utils/helpers.py +6 -2
- ansible/utils/jsonrpc.py +7 -3
- ansible/utils/plugin_docs.py +49 -38
- ansible/utils/ssh_functions.py +0 -19
- ansible/utils/unsafe_proxy.py +7 -7
- ansible/vars/clean.py +2 -3
- ansible/vars/manager.py +28 -22
- ansible/vars/plugins.py +1 -31
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/METADATA +4 -4
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/RECORD +213 -214
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/network.txt +0 -1
- ansible_test/_data/completion/remote.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -1
- ansible_test/_data/requirements/ansible.txt +1 -1
- ansible_test/_data/requirements/sanity.ansible-doc.txt +2 -2
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- 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 -6
- ansible_test/_data/requirements/sanity.runtime-metadata.txt +1 -1
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/cache.py +2 -5
- ansible_test/_internal/cli/compat.py +1 -1
- ansible_test/_internal/commands/coverage/combine.py +1 -3
- ansible_test/_internal/commands/integration/__init__.py +3 -7
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +1 -3
- ansible_test/_internal/commands/integration/filters.py +5 -10
- ansible_test/_internal/commands/sanity/pylint.py +11 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
- ansible_test/_internal/commands/units/__init__.py +1 -13
- ansible_test/_internal/compat/packaging.py +2 -2
- ansible_test/_internal/compat/yaml.py +2 -2
- ansible_test/_internal/completion.py +2 -5
- ansible_test/_internal/config.py +2 -7
- ansible_test/_internal/coverage_util.py +1 -1
- ansible_test/_internal/delegation.py +2 -0
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/host_profiles.py +6 -11
- ansible_test/_internal/provider/__init__.py +2 -5
- ansible_test/_internal/provisioning.py +2 -5
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/python_requirements.py +1 -1
- ansible_test/_internal/target.py +2 -6
- ansible_test/_internal/thread.py +1 -4
- ansible_test/_internal/util.py +9 -14
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +48 -45
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +9 -7
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +51 -37
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/setup/bootstrap.sh +0 -6
- ansible/utils/py3compat.py +0 -27
- ansible_test/_data/pytest/config/legacy.ini +0 -4
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.4rc1.dist-info → ansible_core-2.20.0.dist-info}/top_level.txt +0 -0
|
@@ -27,7 +27,6 @@ from ansible import constants as C
|
|
|
27
27
|
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleAssertionError
|
|
28
28
|
from ansible.module_utils.common.sentinel import Sentinel
|
|
29
29
|
from ansible.module_utils.common.text.converters import to_text
|
|
30
|
-
from ansible.module_utils.six import binary_type, text_type
|
|
31
30
|
from ansible.playbook.base import Base
|
|
32
31
|
from ansible.playbook.collectionsearch import CollectionSearch
|
|
33
32
|
from ansible.playbook.conditional import Conditional
|
|
@@ -37,6 +36,7 @@ from ansible.playbook.role.metadata import RoleMetadata
|
|
|
37
36
|
from ansible.playbook.taggable import Taggable
|
|
38
37
|
from ansible.plugins.loader import add_all_plugin_dirs
|
|
39
38
|
from ansible.utils.collection_loader import AnsibleCollectionConfig
|
|
39
|
+
from ansible.utils.display import Display
|
|
40
40
|
from ansible.utils.path import is_subpath
|
|
41
41
|
from ansible.utils.vars import combine_vars
|
|
42
42
|
|
|
@@ -52,14 +52,12 @@ if _t.TYPE_CHECKING:
|
|
|
52
52
|
|
|
53
53
|
__all__ = ['Role', 'hash_params']
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
# the role due to the fact that it would require the use of self
|
|
57
|
-
# in a static method. This is also used in the base class for
|
|
58
|
-
# strategies (ansible/plugins/strategy/__init__.py)
|
|
55
|
+
_display = Display()
|
|
59
56
|
|
|
60
57
|
|
|
61
58
|
def hash_params(params):
|
|
62
59
|
"""
|
|
60
|
+
DEPRECATED
|
|
63
61
|
Construct a data structure of parameters that is hashable.
|
|
64
62
|
|
|
65
63
|
This requires changing any mutable data structures into immutable ones.
|
|
@@ -71,10 +69,16 @@ def hash_params(params):
|
|
|
71
69
|
1) There shouldn't be any unhashable scalars specified in the yaml
|
|
72
70
|
2) Our only choice would be to return an error anyway.
|
|
73
71
|
"""
|
|
72
|
+
|
|
73
|
+
_display.deprecated(
|
|
74
|
+
msg="The hash_params function is deprecated as its consumers have moved to internal alternatives",
|
|
75
|
+
version='2.24',
|
|
76
|
+
help_text='Contact the plugin author to update their code',
|
|
77
|
+
)
|
|
74
78
|
# Any container is unhashable if it contains unhashable items (for
|
|
75
79
|
# instance, tuple() is a Hashable subclass but if it contains a dict, it
|
|
76
80
|
# cannot be hashed)
|
|
77
|
-
if isinstance(params, Container) and not isinstance(params, (
|
|
81
|
+
if isinstance(params, Container) and not isinstance(params, (str, bytes)):
|
|
78
82
|
if isinstance(params, Mapping):
|
|
79
83
|
try:
|
|
80
84
|
# Optimistically hope the contents are all hashable
|
|
@@ -651,65 +655,6 @@ class Role(Base, Conditional, Taggable, CollectionSearch, Delegatable):
|
|
|
651
655
|
|
|
652
656
|
return block_list
|
|
653
657
|
|
|
654
|
-
def serialize(self, include_deps=True):
|
|
655
|
-
res = super(Role, self).serialize()
|
|
656
|
-
|
|
657
|
-
res['_role_name'] = self._role_name
|
|
658
|
-
res['_role_path'] = self._role_path
|
|
659
|
-
res['_role_vars'] = self._role_vars
|
|
660
|
-
res['_role_params'] = self._role_params
|
|
661
|
-
res['_default_vars'] = self._default_vars
|
|
662
|
-
res['_had_task_run'] = self._had_task_run.copy()
|
|
663
|
-
res['_completed'] = self._completed.copy()
|
|
664
|
-
|
|
665
|
-
res['_metadata'] = self._metadata.serialize()
|
|
666
|
-
|
|
667
|
-
if include_deps:
|
|
668
|
-
deps = []
|
|
669
|
-
for role in self.get_direct_dependencies():
|
|
670
|
-
deps.append(role.serialize())
|
|
671
|
-
res['_dependencies'] = deps
|
|
672
|
-
|
|
673
|
-
parents = []
|
|
674
|
-
for parent in self._parents:
|
|
675
|
-
parents.append(parent.serialize(include_deps=False))
|
|
676
|
-
res['_parents'] = parents
|
|
677
|
-
|
|
678
|
-
return res
|
|
679
|
-
|
|
680
|
-
def deserialize(self, data, include_deps=True):
|
|
681
|
-
self._role_name = data.get('_role_name', '')
|
|
682
|
-
self._role_path = data.get('_role_path', '')
|
|
683
|
-
self._role_vars = data.get('_role_vars', dict())
|
|
684
|
-
self._role_params = data.get('_role_params', dict())
|
|
685
|
-
self._default_vars = data.get('_default_vars', dict())
|
|
686
|
-
self._had_task_run = data.get('_had_task_run', dict())
|
|
687
|
-
self._completed = data.get('_completed', dict())
|
|
688
|
-
|
|
689
|
-
if include_deps:
|
|
690
|
-
deps = []
|
|
691
|
-
for dep in data.get('_dependencies', []):
|
|
692
|
-
r = Role()
|
|
693
|
-
r.deserialize(dep)
|
|
694
|
-
deps.append(r)
|
|
695
|
-
setattr(self, '_dependencies', deps)
|
|
696
|
-
|
|
697
|
-
parent_data = data.get('_parents', [])
|
|
698
|
-
parents = []
|
|
699
|
-
for parent in parent_data:
|
|
700
|
-
r = Role()
|
|
701
|
-
r.deserialize(parent, include_deps=False)
|
|
702
|
-
parents.append(r)
|
|
703
|
-
setattr(self, '_parents', parents)
|
|
704
|
-
|
|
705
|
-
metadata_data = data.get('_metadata')
|
|
706
|
-
if metadata_data:
|
|
707
|
-
m = RoleMetadata()
|
|
708
|
-
m.deserialize(metadata_data)
|
|
709
|
-
self._metadata = m
|
|
710
|
-
|
|
711
|
-
super(Role, self).deserialize(data)
|
|
712
|
-
|
|
713
658
|
def set_loader(self, loader):
|
|
714
659
|
self._loader = loader
|
|
715
660
|
for parent in self._parents:
|
|
@@ -22,7 +22,6 @@ import os
|
|
|
22
22
|
from ansible import constants as C
|
|
23
23
|
from ansible.errors import AnsibleError, AnsibleAssertionError
|
|
24
24
|
from ansible.module_utils._internal._datatag import AnsibleTagHelper
|
|
25
|
-
from ansible.module_utils.six import string_types
|
|
26
25
|
from ansible.playbook.attribute import NonInheritableFieldAttribute
|
|
27
26
|
from ansible.playbook.base import Base
|
|
28
27
|
from ansible.playbook.collectionsearch import CollectionSearch
|
|
@@ -70,7 +69,7 @@ class RoleDefinition(Base, Conditional, Taggable, CollectionSearch):
|
|
|
70
69
|
if isinstance(ds, int):
|
|
71
70
|
ds = "%s" % ds
|
|
72
71
|
|
|
73
|
-
if not isinstance(ds, dict) and not isinstance(ds,
|
|
72
|
+
if not isinstance(ds, dict) and not isinstance(ds, str):
|
|
74
73
|
raise AnsibleAssertionError()
|
|
75
74
|
|
|
76
75
|
if isinstance(ds, dict):
|
|
@@ -113,11 +112,11 @@ class RoleDefinition(Base, Conditional, Taggable, CollectionSearch):
|
|
|
113
112
|
string), just that string
|
|
114
113
|
"""
|
|
115
114
|
|
|
116
|
-
if isinstance(ds,
|
|
115
|
+
if isinstance(ds, str):
|
|
117
116
|
return ds
|
|
118
117
|
|
|
119
118
|
role_name = ds.get('role', ds.get('name'))
|
|
120
|
-
if not role_name or not isinstance(role_name,
|
|
119
|
+
if not role_name or not isinstance(role_name, str):
|
|
121
120
|
raise AnsibleError('role definitions must contain a role name', obj=ds)
|
|
122
121
|
|
|
123
122
|
# if we have the required datastructures, and if the role_name
|
ansible/playbook/role/include.py
CHANGED
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
from ansible.errors import AnsibleError, AnsibleParserError
|
|
21
|
-
from ansible.module_utils.six import string_types
|
|
22
21
|
from ansible.playbook.delegatable import Delegatable
|
|
23
22
|
from ansible.playbook.role.definition import RoleDefinition
|
|
24
23
|
|
|
@@ -40,10 +39,10 @@ class RoleInclude(RoleDefinition, Delegatable):
|
|
|
40
39
|
@staticmethod
|
|
41
40
|
def load(data, play, current_role_path=None, parent_role=None, variable_manager=None, loader=None, collection_list=None):
|
|
42
41
|
|
|
43
|
-
if not (isinstance(data,
|
|
42
|
+
if not (isinstance(data, str) or isinstance(data, dict)):
|
|
44
43
|
raise AnsibleParserError("Invalid role definition.", obj=data)
|
|
45
44
|
|
|
46
|
-
if isinstance(data,
|
|
45
|
+
if isinstance(data, str) and ',' in data:
|
|
47
46
|
raise AnsibleError("Invalid old style role requirement: %s" % data)
|
|
48
47
|
|
|
49
48
|
ri = RoleInclude(play=play, role_basedir=current_role_path, variable_manager=variable_manager, loader=loader, collection_list=collection_list)
|
|
@@ -20,7 +20,6 @@ from __future__ import annotations
|
|
|
20
20
|
import os
|
|
21
21
|
|
|
22
22
|
from ansible.errors import AnsibleParserError, AnsibleError
|
|
23
|
-
from ansible.module_utils.six import string_types
|
|
24
23
|
from ansible.playbook.attribute import NonInheritableFieldAttribute
|
|
25
24
|
from ansible.playbook.base import Base
|
|
26
25
|
from ansible.playbook.collectionsearch import CollectionSearch
|
|
@@ -70,7 +69,7 @@ class RoleMetadata(Base, CollectionSearch):
|
|
|
70
69
|
|
|
71
70
|
for role_def in ds:
|
|
72
71
|
# FIXME: consolidate with ansible-galaxy to keep this in sync
|
|
73
|
-
if isinstance(role_def,
|
|
72
|
+
if isinstance(role_def, str) or 'role' in role_def or 'name' in role_def:
|
|
74
73
|
roles.append(role_def)
|
|
75
74
|
continue
|
|
76
75
|
try:
|
|
@@ -106,13 +105,3 @@ class RoleMetadata(Base, CollectionSearch):
|
|
|
106
105
|
collection_search_list=collection_search_list)
|
|
107
106
|
except AssertionError as ex:
|
|
108
107
|
raise AnsibleParserError("A malformed list of role dependencies was encountered.", obj=self._ds) from ex
|
|
109
|
-
|
|
110
|
-
def serialize(self):
|
|
111
|
-
return dict(
|
|
112
|
-
allow_duplicates=self._allow_duplicates,
|
|
113
|
-
dependencies=self._dependencies
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
def deserialize(self, data):
|
|
117
|
-
setattr(self, 'allow_duplicates', data.get('allow_duplicates', False))
|
|
118
|
-
setattr(self, 'dependencies', data.get('dependencies', []))
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
from ansible.errors import AnsibleError
|
|
21
|
-
from ansible.module_utils.six import string_types
|
|
22
21
|
from ansible.playbook.role.definition import RoleDefinition
|
|
23
22
|
from ansible.utils.display import Display
|
|
24
23
|
from ansible.utils.galaxy import scm_archive_resource
|
|
@@ -65,7 +64,7 @@ class RoleRequirement(RoleDefinition):
|
|
|
65
64
|
@staticmethod
|
|
66
65
|
def role_yaml_parse(role):
|
|
67
66
|
|
|
68
|
-
if isinstance(role,
|
|
67
|
+
if isinstance(role, str):
|
|
69
68
|
name = None
|
|
70
69
|
scm = None
|
|
71
70
|
src = None
|
ansible/playbook/role_include.py
CHANGED
|
@@ -23,7 +23,6 @@ from ansible.playbook.task_include import TaskInclude
|
|
|
23
23
|
from ansible.playbook.role import Role
|
|
24
24
|
from ansible.playbook.role.include import RoleInclude
|
|
25
25
|
from ansible.utils.display import Display
|
|
26
|
-
from ansible.module_utils.six import string_types
|
|
27
26
|
from ansible._internal._templating._engine import TemplateEngine
|
|
28
27
|
|
|
29
28
|
__all__ = ['IncludeRole']
|
|
@@ -137,7 +136,7 @@ class IncludeRole(TaskInclude):
|
|
|
137
136
|
for key in my_arg_names.intersection(IncludeRole.FROM_ARGS):
|
|
138
137
|
from_key = key.removesuffix('_from')
|
|
139
138
|
args_value = ir.args.get(key)
|
|
140
|
-
if not isinstance(args_value,
|
|
139
|
+
if not isinstance(args_value, str):
|
|
141
140
|
raise AnsibleParserError('Expected a string for %s but got %s instead' % (key, type(args_value)))
|
|
142
141
|
ir._from_files[from_key] = args_value
|
|
143
142
|
|
ansible/playbook/taggable.py
CHANGED
|
@@ -19,11 +19,14 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import typing as t
|
|
21
21
|
|
|
22
|
+
from ansible._internal._templating._engine import TemplateEngine
|
|
22
23
|
from ansible.errors import AnsibleError
|
|
23
24
|
from ansible.module_utils.common.sentinel import Sentinel
|
|
24
25
|
from ansible.module_utils._internal._datatag import AnsibleTagHelper
|
|
25
26
|
from ansible.playbook.attribute import FieldAttribute
|
|
26
|
-
from ansible.
|
|
27
|
+
from ansible.utils.display import Display
|
|
28
|
+
|
|
29
|
+
_display = Display()
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
def _flatten_tags(tags: list[str | int]) -> list[str | int]:
|
|
@@ -38,17 +41,25 @@ def _flatten_tags(tags: list[str | int]) -> list[str | int]:
|
|
|
38
41
|
|
|
39
42
|
class Taggable:
|
|
40
43
|
|
|
44
|
+
_RESERVED = frozenset(['tagged', 'all', 'untagged'])
|
|
41
45
|
untagged = frozenset(['untagged'])
|
|
42
46
|
tags = FieldAttribute(isa='list', default=list, listof=(str, int), extend=True)
|
|
43
47
|
|
|
44
48
|
def _load_tags(self, attr, ds):
|
|
49
|
+
|
|
50
|
+
tags = None
|
|
45
51
|
if isinstance(ds, list):
|
|
46
|
-
|
|
52
|
+
tags = ds
|
|
53
|
+
elif isinstance(ds, str):
|
|
54
|
+
tags = [AnsibleTagHelper.tag_copy(ds, item.strip()) for item in ds.split(',')]
|
|
55
|
+
|
|
56
|
+
if tags is None:
|
|
57
|
+
raise AnsibleError('tags must be specified as a list', obj=ds)
|
|
47
58
|
|
|
48
|
-
if
|
|
49
|
-
|
|
59
|
+
if found := self._RESERVED.intersection(tags):
|
|
60
|
+
_display.warning(f"Found reserved tagnames in tags: {list(found)!r}, we do not recommend doing this as it might give unexpected results", obj=ds)
|
|
50
61
|
|
|
51
|
-
|
|
62
|
+
return tags
|
|
52
63
|
|
|
53
64
|
def _get_all_taggable_objects(self) -> t.Iterable[Taggable]:
|
|
54
65
|
obj = self
|
ansible/playbook/task.py
CHANGED
|
@@ -25,7 +25,6 @@ from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVar
|
|
|
25
25
|
from ansible.executor.module_common import _get_action_arg_defaults
|
|
26
26
|
from ansible.module_utils.common.text.converters import to_native
|
|
27
27
|
from ansible.module_utils._internal._datatag import AnsibleTagHelper
|
|
28
|
-
from ansible.module_utils.six import string_types
|
|
29
28
|
from ansible.parsing.mod_args import ModuleArgsParser, RAW_PARAM_MODULES
|
|
30
29
|
from ansible.plugins.action import ActionBase
|
|
31
30
|
from ansible.plugins.loader import action_loader, module_loader, lookup_loader
|
|
@@ -37,7 +36,6 @@ from ansible.playbook.conditional import Conditional
|
|
|
37
36
|
from ansible.playbook.delegatable import Delegatable
|
|
38
37
|
from ansible.playbook.loop_control import LoopControl
|
|
39
38
|
from ansible.playbook.notifiable import Notifiable
|
|
40
|
-
from ansible.playbook.role import Role
|
|
41
39
|
from ansible.playbook.taggable import Taggable
|
|
42
40
|
from ansible._internal import _task
|
|
43
41
|
from ansible._internal._templating import _marker_behaviors
|
|
@@ -161,7 +159,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl
|
|
|
161
159
|
def _merge_kv(self, ds):
|
|
162
160
|
if ds is None:
|
|
163
161
|
return ""
|
|
164
|
-
elif isinstance(ds,
|
|
162
|
+
elif isinstance(ds, str):
|
|
165
163
|
return ds
|
|
166
164
|
elif isinstance(ds, dict):
|
|
167
165
|
buf = ""
|
|
@@ -505,53 +503,6 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl
|
|
|
505
503
|
|
|
506
504
|
return new_me
|
|
507
505
|
|
|
508
|
-
def serialize(self):
|
|
509
|
-
data = super(Task, self).serialize()
|
|
510
|
-
|
|
511
|
-
if not self._squashed and not self._finalized:
|
|
512
|
-
if self._parent:
|
|
513
|
-
data['parent'] = self._parent.serialize()
|
|
514
|
-
data['parent_type'] = self._parent.__class__.__name__
|
|
515
|
-
|
|
516
|
-
if self._role:
|
|
517
|
-
data['role'] = self._role.serialize()
|
|
518
|
-
|
|
519
|
-
data['implicit'] = self.implicit
|
|
520
|
-
data['_resolved_action'] = self._resolved_action
|
|
521
|
-
|
|
522
|
-
return data
|
|
523
|
-
|
|
524
|
-
def deserialize(self, data):
|
|
525
|
-
|
|
526
|
-
# import is here to avoid import loops
|
|
527
|
-
from ansible.playbook.task_include import TaskInclude
|
|
528
|
-
from ansible.playbook.handler_task_include import HandlerTaskInclude
|
|
529
|
-
|
|
530
|
-
parent_data = data.get('parent', None)
|
|
531
|
-
if parent_data:
|
|
532
|
-
parent_type = data.get('parent_type')
|
|
533
|
-
if parent_type == 'Block':
|
|
534
|
-
p = Block()
|
|
535
|
-
elif parent_type == 'TaskInclude':
|
|
536
|
-
p = TaskInclude()
|
|
537
|
-
elif parent_type == 'HandlerTaskInclude':
|
|
538
|
-
p = HandlerTaskInclude()
|
|
539
|
-
p.deserialize(parent_data)
|
|
540
|
-
self._parent = p
|
|
541
|
-
del data['parent']
|
|
542
|
-
|
|
543
|
-
role_data = data.get('role')
|
|
544
|
-
if role_data:
|
|
545
|
-
r = Role()
|
|
546
|
-
r.deserialize(role_data)
|
|
547
|
-
self._role = r
|
|
548
|
-
del data['role']
|
|
549
|
-
|
|
550
|
-
self.implicit = data.get('implicit', False)
|
|
551
|
-
self._resolved_action = data.get('_resolved_action')
|
|
552
|
-
|
|
553
|
-
super(Task, self).deserialize(data)
|
|
554
|
-
|
|
555
506
|
def set_loader(self, loader):
|
|
556
507
|
"""
|
|
557
508
|
Sets the loader on this object and recursively on parent, child objects.
|
|
@@ -629,6 +580,16 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl
|
|
|
629
580
|
attrs.update(_resolved_action=self._resolved_action)
|
|
630
581
|
return attrs
|
|
631
582
|
|
|
583
|
+
def from_attrs(self, attrs):
|
|
584
|
+
super().from_attrs(attrs)
|
|
585
|
+
|
|
586
|
+
# from_attrs is only used to create a finalized task
|
|
587
|
+
# from attrs from the Worker/TaskExecutor
|
|
588
|
+
# Those attrs are finalized and squashed in the TE
|
|
589
|
+
# and controller side use needs to reflect that
|
|
590
|
+
self._finalized = True
|
|
591
|
+
self._squashed = True
|
|
592
|
+
|
|
632
593
|
def _resolve_conditional(
|
|
633
594
|
self,
|
|
634
595
|
conditional: list[str | bool],
|
|
@@ -29,7 +29,6 @@ from ansible.module_utils.common.arg_spec import ArgumentSpecValidator
|
|
|
29
29
|
from ansible.module_utils.errors import UnsupportedError
|
|
30
30
|
from ansible.module_utils.json_utils import _filter_non_json_lines
|
|
31
31
|
from ansible.module_utils.common.json import Direction, get_module_encoder, get_module_decoder
|
|
32
|
-
from ansible.module_utils.six import binary_type, string_types, text_type
|
|
33
32
|
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
|
34
33
|
from ansible.release import __version__
|
|
35
34
|
from ansible.utils.collection_loader import resource_from_fqcr
|
|
@@ -52,7 +51,7 @@ if t.TYPE_CHECKING:
|
|
|
52
51
|
|
|
53
52
|
|
|
54
53
|
def _validate_utf8_json(d):
|
|
55
|
-
if isinstance(d,
|
|
54
|
+
if isinstance(d, str):
|
|
56
55
|
# Purposefully not using to_bytes here for performance reasons
|
|
57
56
|
d.encode(encoding='utf-8', errors='strict')
|
|
58
57
|
elif isinstance(d, dict):
|
|
@@ -288,14 +287,6 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
|
288
287
|
elif leaf_module_name == 'async_status' and collection_name in rewrite_collection_names:
|
|
289
288
|
module_name = '%s.%s' % (win_collection, leaf_module_name)
|
|
290
289
|
|
|
291
|
-
# TODO: move this tweak down to the modules, not extensible here
|
|
292
|
-
# Remove extra quotes surrounding path parameters before sending to module.
|
|
293
|
-
if leaf_module_name in ['win_stat', 'win_file', 'win_copy', 'slurp'] and module_args and \
|
|
294
|
-
hasattr(self._connection._shell, '_unquote'):
|
|
295
|
-
for key in ('src', 'dest', 'path'):
|
|
296
|
-
if key in module_args:
|
|
297
|
-
module_args[key] = self._connection._shell._unquote(module_args[key])
|
|
298
|
-
|
|
299
290
|
result = self._shared_loader_obj.module_loader.find_plugin_with_context(module_name, mod_type, collection_list=self._task.collections)
|
|
300
291
|
|
|
301
292
|
if not result.resolved:
|
|
@@ -680,8 +671,18 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
|
680
671
|
become_user,
|
|
681
672
|
setfacl_mode)
|
|
682
673
|
|
|
683
|
-
|
|
684
|
-
|
|
674
|
+
match res.get('rc'):
|
|
675
|
+
case 0:
|
|
676
|
+
return remote_paths
|
|
677
|
+
case 2:
|
|
678
|
+
# invalid syntax (for example, missing user, missing colon)
|
|
679
|
+
self._display.debug(f"setfacl command failed with an invalid syntax. Trying chmod instead. Err: {res!r}")
|
|
680
|
+
case 127:
|
|
681
|
+
# setfacl binary does not exists or we don't have permission to use it.
|
|
682
|
+
self._display.debug(f"setfacl binary does not exist or does not have permission to use it. Trying chmod instead. Err: {res!r}")
|
|
683
|
+
case _:
|
|
684
|
+
# generic debug message
|
|
685
|
+
self._display.debug(f'Failed to set facl {setfacl_mode}, got:{res!r}')
|
|
685
686
|
|
|
686
687
|
# Step 3b: Set execute if we need to. We do this before anything else
|
|
687
688
|
# because some of the methods below might work but not let us set
|
|
@@ -874,7 +875,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
|
874
875
|
# happens sometimes when it is a dir and not on bsd
|
|
875
876
|
if 'checksum' not in mystat['stat']:
|
|
876
877
|
mystat['stat']['checksum'] = ''
|
|
877
|
-
elif not isinstance(mystat['stat']['checksum'],
|
|
878
|
+
elif not isinstance(mystat['stat']['checksum'], str):
|
|
878
879
|
raise AnsibleError("Invalid checksum returned by stat: expected a string type but got %s" % type(mystat['stat']['checksum']))
|
|
879
880
|
|
|
880
881
|
return mystat['stat']
|
|
@@ -1084,7 +1085,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
|
1084
1085
|
# the remote system, which can be read and parsed by the module
|
|
1085
1086
|
args_data = ""
|
|
1086
1087
|
for k, v in module_args.items():
|
|
1087
|
-
args_data += '%s=%s ' % (k, shlex.quote(
|
|
1088
|
+
args_data += '%s=%s ' % (k, shlex.quote(str(v)))
|
|
1088
1089
|
self._transfer_data(args_file_path, args_data)
|
|
1089
1090
|
elif module_style in ('non_native_want_json', 'binary'):
|
|
1090
1091
|
profile_encoder = get_module_encoder(module_bits.serialization_profile, Direction.CONTROLLER_TO_MODULE)
|
|
@@ -1169,7 +1170,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
|
1169
1170
|
self._cleanup_remote_tmp = False
|
|
1170
1171
|
|
|
1171
1172
|
# NOTE: dnf returns results .. but that made it 'compatible' with squashing, so we allow mappings, for now
|
|
1172
|
-
if 'results' in data and (not isinstance(data['results'], Sequence) or isinstance(data['results'],
|
|
1173
|
+
if 'results' in data and (not isinstance(data['results'], Sequence) or isinstance(data['results'], str)):
|
|
1173
1174
|
data['ansible_module_results'] = data['results']
|
|
1174
1175
|
del data['results']
|
|
1175
1176
|
display.warning("Found internal 'results' key in module return, renamed to 'ansible_module_results'.")
|
|
@@ -1322,16 +1323,16 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
|
1322
1323
|
|
|
1323
1324
|
# stdout and stderr may be either a file-like or a bytes object.
|
|
1324
1325
|
# Convert either one to a text type
|
|
1325
|
-
if isinstance(stdout,
|
|
1326
|
+
if isinstance(stdout, bytes):
|
|
1326
1327
|
out = to_text(stdout, errors=encoding_errors)
|
|
1327
|
-
elif not isinstance(stdout,
|
|
1328
|
+
elif not isinstance(stdout, str):
|
|
1328
1329
|
out = to_text(b''.join(stdout.readlines()), errors=encoding_errors)
|
|
1329
1330
|
else:
|
|
1330
1331
|
out = stdout
|
|
1331
1332
|
|
|
1332
|
-
if isinstance(stderr,
|
|
1333
|
+
if isinstance(stderr, bytes):
|
|
1333
1334
|
err = to_text(stderr, errors=encoding_errors)
|
|
1334
|
-
elif not isinstance(stderr,
|
|
1335
|
+
elif not isinstance(stderr, str):
|
|
1335
1336
|
err = to_text(b''.join(stderr.readlines()), errors=encoding_errors)
|
|
1336
1337
|
else:
|
|
1337
1338
|
err = stderr
|
|
@@ -21,7 +21,6 @@ from __future__ import annotations
|
|
|
21
21
|
from collections.abc import Mapping
|
|
22
22
|
|
|
23
23
|
from ansible.errors import AnsibleActionFail
|
|
24
|
-
from ansible.module_utils.six import string_types
|
|
25
24
|
from ansible.plugins.action import ActionBase
|
|
26
25
|
from ansible.parsing.utils.addresses import parse_address
|
|
27
26
|
from ansible.utils.display import Display
|
|
@@ -74,7 +73,7 @@ class ActionModule(ActionBase):
|
|
|
74
73
|
if groups:
|
|
75
74
|
if isinstance(groups, list):
|
|
76
75
|
group_list = groups
|
|
77
|
-
elif isinstance(groups,
|
|
76
|
+
elif isinstance(groups, str):
|
|
78
77
|
group_list = groups.split(",")
|
|
79
78
|
else:
|
|
80
79
|
raise AnsibleActionFail("Groups must be specified as a list.", obj=groups)
|
ansible/plugins/action/fetch.py
CHANGED
|
@@ -20,7 +20,6 @@ import os
|
|
|
20
20
|
import base64
|
|
21
21
|
from ansible.errors import AnsibleConnectionFailure, AnsibleError, AnsibleActionFail, AnsibleActionSkip
|
|
22
22
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
23
|
-
from ansible.module_utils.six import string_types
|
|
24
23
|
from ansible.module_utils.parsing.convert_bool import boolean
|
|
25
24
|
from ansible.plugins.action import ActionBase
|
|
26
25
|
from ansible.utils.display import Display
|
|
@@ -52,10 +51,10 @@ class ActionModule(ActionBase):
|
|
|
52
51
|
|
|
53
52
|
msg = ''
|
|
54
53
|
# FIXME: validate source and dest are strings; use basic.py and module specs
|
|
55
|
-
if not isinstance(source,
|
|
54
|
+
if not isinstance(source, str):
|
|
56
55
|
msg = "Invalid type supplied for source option, it must be a string"
|
|
57
56
|
|
|
58
|
-
if not isinstance(dest,
|
|
57
|
+
if not isinstance(dest, str):
|
|
59
58
|
msg = "Invalid type supplied for dest option, it must be a string"
|
|
60
59
|
|
|
61
60
|
if source is None or dest is None:
|
|
@@ -131,7 +130,6 @@ class ActionModule(ActionBase):
|
|
|
131
130
|
|
|
132
131
|
# calculate the destination name
|
|
133
132
|
if os.path.sep not in self._connection._shell.join_path('a', ''):
|
|
134
|
-
source = self._connection._shell._unquote(source)
|
|
135
133
|
source_local = source.replace('\\', '/')
|
|
136
134
|
else:
|
|
137
135
|
source_local = source
|
|
@@ -194,7 +192,7 @@ class ActionModule(ActionBase):
|
|
|
194
192
|
msg="checksum mismatch", file=source, dest=dest, remote_md5sum=None,
|
|
195
193
|
checksum=new_checksum, remote_checksum=remote_checksum))
|
|
196
194
|
else:
|
|
197
|
-
result.update({'changed': True, 'md5sum': new_md5, 'dest': dest,
|
|
195
|
+
result.update({'changed': True, 'md5sum': new_md5, 'file': source, 'dest': dest,
|
|
198
196
|
'remote_md5sum': None, 'checksum': new_checksum,
|
|
199
197
|
'remote_checksum': remote_checksum})
|
|
200
198
|
else:
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
from ansible.plugins.action import ActionBase
|
|
20
|
-
from ansible.module_utils.six import string_types
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
class ActionModule(ActionBase):
|
|
@@ -42,7 +41,7 @@ class ActionModule(ActionBase):
|
|
|
42
41
|
|
|
43
42
|
group_name = self._task.args.get('key')
|
|
44
43
|
parent_groups = self._task.args.get('parents', ['all'])
|
|
45
|
-
if isinstance(parent_groups,
|
|
44
|
+
if isinstance(parent_groups, str):
|
|
46
45
|
parent_groups = [parent_groups]
|
|
47
46
|
|
|
48
47
|
result['changed'] = False
|
|
@@ -10,7 +10,6 @@ import pathlib
|
|
|
10
10
|
import ansible.constants as C
|
|
11
11
|
from ansible.errors import AnsibleError
|
|
12
12
|
from ansible._internal._datatag._tags import SourceWasEncrypted
|
|
13
|
-
from ansible.module_utils.six import string_types
|
|
14
13
|
from ansible.module_utils.common.text.converters import to_native
|
|
15
14
|
from ansible.plugins.action import ActionBase
|
|
16
15
|
from ansible.utils.vars import combine_vars
|
|
@@ -38,14 +37,17 @@ class ActionModule(ActionBase):
|
|
|
38
37
|
if not self.ignore_files:
|
|
39
38
|
self.ignore_files = list()
|
|
40
39
|
|
|
41
|
-
if isinstance(self.ignore_files,
|
|
40
|
+
if isinstance(self.ignore_files, str):
|
|
41
|
+
self._display.deprecated(
|
|
42
|
+
msg="Specifying 'ignore_files' as a string is deprecated.",
|
|
43
|
+
version="2.24",
|
|
44
|
+
help_text="Use a list of strings instead.",
|
|
45
|
+
obj=self.ignore_files,
|
|
46
|
+
)
|
|
42
47
|
self.ignore_files = self.ignore_files.split()
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
'failed': True,
|
|
47
|
-
'message': '{0} must be a list'.format(self.ignore_files)
|
|
48
|
-
}
|
|
49
|
+
if not isinstance(self.ignore_files, list):
|
|
50
|
+
raise AnsibleError("The 'ignore_files' option must be a list.", obj=self.ignore_files)
|
|
49
51
|
|
|
50
52
|
def _set_args(self):
|
|
51
53
|
""" Set instance variables based on the arguments that were passed """
|
|
@@ -65,11 +67,8 @@ class ActionModule(ActionBase):
|
|
|
65
67
|
self.ignore_files = self._task.args.get('ignore_files', None)
|
|
66
68
|
self.valid_extensions = self._task.args.get('extensions', self.VALID_FILE_EXTENSIONS)
|
|
67
69
|
|
|
68
|
-
# convert/validate extensions list
|
|
69
|
-
if isinstance(self.valid_extensions, string_types):
|
|
70
|
-
self.valid_extensions = list(self.valid_extensions)
|
|
71
70
|
if not isinstance(self.valid_extensions, list):
|
|
72
|
-
raise AnsibleError('
|
|
71
|
+
raise AnsibleError("The 'extensions' option must be a list.", obj=self.valid_extensions)
|
|
73
72
|
|
|
74
73
|
def run(self, tmp=None, task_vars=None):
|
|
75
74
|
""" Load yml files recursively from a directory.
|
|
@@ -93,10 +92,10 @@ class ActionModule(ActionBase):
|
|
|
93
92
|
elif arg in self.VALID_ALL:
|
|
94
93
|
pass
|
|
95
94
|
else:
|
|
96
|
-
raise AnsibleError('{
|
|
95
|
+
raise AnsibleError(f'{arg} is not a valid option in include_vars', obj=arg)
|
|
97
96
|
|
|
98
97
|
if dirs and files:
|
|
99
|
-
raise AnsibleError("You are mixing file only and dir only arguments, these are incompatible")
|
|
98
|
+
raise AnsibleError("You are mixing file only and dir only arguments, these are incompatible", obj=self._task.args)
|
|
100
99
|
|
|
101
100
|
# set internal vars from args
|
|
102
101
|
self._set_args()
|
|
@@ -108,13 +107,13 @@ class ActionModule(ActionBase):
|
|
|
108
107
|
self._set_root_dir()
|
|
109
108
|
if not path.exists(self.source_dir):
|
|
110
109
|
failed = True
|
|
111
|
-
err_msg =
|
|
110
|
+
err_msg = f"{self.source_dir} directory does not exist"
|
|
112
111
|
elif not path.isdir(self.source_dir):
|
|
113
112
|
failed = True
|
|
114
|
-
err_msg =
|
|
113
|
+
err_msg = f"{self.source_dir} is not a directory"
|
|
115
114
|
else:
|
|
116
115
|
for root_dir, filenames in self._traverse_dir_depth():
|
|
117
|
-
failed, err_msg, updated_results =
|
|
116
|
+
failed, err_msg, updated_results = self._load_files_in_dir(root_dir, filenames)
|
|
118
117
|
if failed:
|
|
119
118
|
break
|
|
120
119
|
results.update(updated_results)
|
|
@@ -175,7 +174,7 @@ class ActionModule(ActionBase):
|
|
|
175
174
|
self.source_dir = path.join(current_dir, self.source_dir)
|
|
176
175
|
|
|
177
176
|
def _log_walk(self, error):
|
|
178
|
-
self._display.vvv(
|
|
177
|
+
self._display.vvv(f"Issue with walking through {error.filename}: {error}")
|
|
179
178
|
|
|
180
179
|
def _traverse_dir_depth(self):
|
|
181
180
|
""" Recursively iterate over a directory and sort the files in
|
|
@@ -204,9 +203,8 @@ class ActionModule(ActionBase):
|
|
|
204
203
|
try:
|
|
205
204
|
if re.search(r'{0}$'.format(file_type), filename):
|
|
206
205
|
return True
|
|
207
|
-
except Exception:
|
|
208
|
-
|
|
209
|
-
raise AnsibleError(err_msg)
|
|
206
|
+
except Exception as ex:
|
|
207
|
+
raise AnsibleError(f'Invalid regular expression: {file_type!r}', obj=file_type) from ex
|
|
210
208
|
return False
|
|
211
209
|
|
|
212
210
|
def _is_valid_file_ext(self, source_file):
|
|
@@ -232,7 +230,7 @@ class ActionModule(ActionBase):
|
|
|
232
230
|
err_msg = ''
|
|
233
231
|
if validate_extensions and not self._is_valid_file_ext(filename):
|
|
234
232
|
failed = True
|
|
235
|
-
err_msg =
|
|
233
|
+
err_msg = f"{filename!r} does not have a valid extension: {', '.join(self.valid_extensions)}"
|
|
236
234
|
else:
|
|
237
235
|
data = self._loader.load_from_file(filename, cache='none', trusted_as_template=True)
|
|
238
236
|
|
|
@@ -243,7 +241,7 @@ class ActionModule(ActionBase):
|
|
|
243
241
|
|
|
244
242
|
if not isinstance(data, dict):
|
|
245
243
|
failed = True
|
|
246
|
-
err_msg =
|
|
244
|
+
err_msg = f"{filename!r} must be stored as a dictionary/hash"
|
|
247
245
|
else:
|
|
248
246
|
self.included_files.append(filename)
|
|
249
247
|
results.update(data)
|