ansible-core 2.19.0b5__py3-none-any.whl → 2.19.0b7__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.
- ansible/_internal/_ansiballz/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/{_ansiballz.py → _ansiballz/_wrapper.py} +11 -11
- ansible/_internal/_templating/_jinja_bits.py +22 -4
- ansible/_internal/_templating/_jinja_common.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +5 -2
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +6 -0
- ansible/_internal/_yaml/_constructor.py +4 -4
- ansible/_internal/_yaml/_dumper.py +26 -18
- ansible/cli/__init__.py +9 -14
- ansible/cli/adhoc.py +6 -3
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/console.py +2 -2
- ansible/cli/doc.py +4 -4
- ansible/cli/inventory.py +5 -7
- ansible/config/base.yml +33 -6
- ansible/errors/__init__.py +2 -1
- ansible/executor/module_common.py +75 -44
- ansible/executor/powershell/psrp_put_file.ps1 +1 -1
- ansible/executor/process/worker.py +2 -2
- ansible/executor/task_executor.py +2 -2
- ansible/executor/task_queue_manager.py +34 -70
- ansible/executor/task_result.py +1 -1
- ansible/galaxy/api.py +3 -6
- ansible/galaxy/collection/__init__.py +1 -6
- ansible/galaxy/collection/concrete_artifact_manager.py +4 -10
- ansible/galaxy/dependency_resolution/providers.py +3 -3
- ansible/galaxy/role.py +2 -2
- ansible/inventory/group.py +6 -1
- ansible/inventory/host.py +6 -1
- ansible/module_utils/_internal/__init__.py +7 -4
- ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
- ansible/module_utils/_internal/{_ansiballz.py → _ansiballz/_loader.py} +10 -38
- ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
- ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
- ansible/module_utils/_internal/_datatag/__init__.py +23 -1
- ansible/module_utils/_internal/_deprecator.py +39 -34
- ansible/module_utils/_internal/_json/_profiles/__init__.py +1 -0
- ansible/module_utils/_internal/_messages.py +26 -2
- ansible/module_utils/_internal/_plugin_info.py +14 -1
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +58 -70
- ansible/module_utils/common/respawn.py +4 -41
- ansible/module_utils/common/yaml.py +1 -1
- ansible/module_utils/connection.py +8 -11
- ansible/module_utils/csharp/Ansible.Basic.cs +1 -1
- ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
- ansible/module_utils/facts/hardware/base.py +1 -1
- ansible/module_utils/facts/hardware/linux.py +1 -1
- ansible/module_utils/facts/other/facter.py +1 -1
- ansible/module_utils/facts/sysctl.py +4 -6
- ansible/module_utils/facts/system/caps.py +2 -2
- ansible/module_utils/facts/system/distribution.py +2 -2
- ansible/module_utils/facts/system/local.py +1 -1
- ansible/module_utils/facts/virtual/linux.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/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
- ansible/module_utils/service.py +1 -1
- ansible/module_utils/urls.py +5 -5
- ansible/modules/apt.py +9 -3
- ansible/modules/apt_repository.py +10 -10
- ansible/modules/assemble.py +7 -5
- ansible/modules/async_wrapper.py +7 -17
- ansible/modules/command.py +3 -3
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +1 -1
- ansible/modules/expect.py +5 -5
- ansible/modules/file.py +16 -17
- ansible/modules/find.py +3 -3
- ansible/modules/get_url.py +17 -0
- ansible/modules/git.py +9 -7
- ansible/modules/hostname.py +2 -2
- ansible/modules/known_hosts.py +12 -14
- ansible/modules/package.py +6 -0
- ansible/modules/pip.py +9 -11
- ansible/modules/raw.py +2 -2
- ansible/modules/replace.py +2 -2
- ansible/modules/slurp.py +10 -13
- ansible/modules/stat.py +6 -8
- ansible/modules/unarchive.py +6 -6
- ansible/modules/user.py +1 -1
- ansible/modules/wait_for.py +38 -33
- ansible/modules/yum_repository.py +4 -3
- ansible/parsing/dataloader.py +2 -2
- ansible/parsing/mod_args.py +38 -20
- ansible/parsing/vault/__init__.py +9 -13
- ansible/playbook/base.py +7 -4
- ansible/playbook/helpers.py +1 -1
- ansible/playbook/included_file.py +3 -1
- ansible/playbook/play_context.py +2 -0
- ansible/playbook/playbook_include.py +23 -56
- ansible/playbook/role/__init__.py +38 -21
- ansible/playbook/taggable.py +19 -5
- ansible/playbook/task.py +2 -0
- ansible/plugins/action/__init__.py +2 -2
- ansible/plugins/action/assemble.py +2 -1
- ansible/plugins/action/assert.py +2 -2
- ansible/plugins/action/fetch.py +3 -3
- ansible/plugins/action/script.py +5 -4
- ansible/plugins/action/template.py +9 -3
- ansible/plugins/cache/__init__.py +17 -19
- ansible/plugins/callback/__init__.py +77 -87
- ansible/plugins/callback/default.py +0 -3
- ansible/plugins/callback/junit.py +0 -6
- ansible/plugins/callback/tree.py +5 -5
- ansible/plugins/connection/local.py +4 -4
- ansible/plugins/connection/paramiko_ssh.py +5 -5
- ansible/plugins/connection/ssh.py +9 -7
- ansible/plugins/connection/winrm.py +1 -1
- ansible/plugins/filter/core.py +19 -21
- ansible/plugins/filter/encryption.py +10 -2
- ansible/plugins/filter/pow.yml +1 -1
- ansible/plugins/filter/root.yml +1 -1
- ansible/plugins/filter/strftime.yml +3 -3
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +5 -4
- ansible/plugins/loader.py +5 -0
- ansible/plugins/lookup/password.py +4 -6
- ansible/plugins/lookup/template.py +9 -4
- ansible/plugins/shell/powershell.py +3 -2
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +3 -3
- ansible/plugins/test/core.py +2 -2
- ansible/release.py +1 -1
- ansible/template/__init__.py +9 -53
- ansible/utils/collection_loader/_collection_finder.py +3 -3
- ansible/utils/display.py +38 -37
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +6 -7
- ansible/utils/path.py +6 -8
- ansible/utils/py3compat.py +2 -1
- ansible/utils/ssh_functions.py +3 -2
- ansible/utils/vars.py +4 -1
- ansible/vars/manager.py +6 -3
- ansible/vars/plugins.py +3 -3
- ansible/vars/reserved.py +6 -4
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/RECORD +184 -173
- ansible_test/_internal/__init__.py +5 -0
- ansible_test/_internal/ansible_util.py +1 -1
- ansible_test/_internal/classification/python.py +6 -0
- ansible_test/_internal/cli/commands/__init__.py +0 -5
- ansible_test/_internal/cli/environments.py +51 -5
- ansible_test/_internal/commands/coverage/__init__.py +1 -1
- ansible_test/_internal/commands/integration/__init__.py +18 -5
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +7 -2
- ansible_test/_internal/commands/sanity/__init__.py +3 -1
- ansible_test/_internal/commands/sanity/integration_aliases.py +11 -0
- ansible_test/_internal/commands/shell/__init__.py +43 -4
- ansible_test/_internal/commands/units/__init__.py +4 -1
- ansible_test/_internal/config.py +21 -13
- ansible_test/_internal/debugging.py +166 -0
- ansible_test/_internal/delegation.py +21 -13
- ansible_test/_internal/host_profiles.py +259 -16
- ansible_test/_internal/inventory.py +4 -0
- ansible_test/_internal/metadata.py +94 -4
- ansible_test/_internal/processes.py +80 -0
- ansible_test/_internal/provisioning.py +10 -4
- ansible_test/_internal/python_requirements.py +27 -0
- ansible_test/_internal/ssh.py +1 -5
- ansible_test/_internal/target.py +8 -0
- ansible_test/_internal/thread.py +2 -1
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +20 -12
- ansible_test/_internal/util_common.py +13 -3
- ansible_test/_util/target/injector/python.py +8 -0
- ansible_test/_util/target/setup/requirements.py +3 -9
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/top_level.txt +0 -0
@@ -19,12 +19,7 @@ from __future__ import annotations
|
|
19
19
|
|
20
20
|
import os
|
21
21
|
|
22
|
-
import ansible.constants as C
|
23
|
-
from ansible.errors import AnsibleParserError, AnsibleAssertionError
|
24
22
|
from ansible.module_utils.common.text.converters import to_bytes
|
25
|
-
from ansible.module_utils._internal._datatag import AnsibleTagHelper
|
26
|
-
from ansible.module_utils.six import string_types
|
27
|
-
from ansible.parsing.splitter import split_args
|
28
23
|
from ansible.playbook.attribute import NonInheritableFieldAttribute
|
29
24
|
from ansible.playbook.base import Base
|
30
25
|
from ansible.playbook.conditional import Conditional
|
@@ -32,16 +27,29 @@ from ansible.playbook.taggable import Taggable
|
|
32
27
|
from ansible.utils.collection_loader import AnsibleCollectionConfig
|
33
28
|
from ansible.utils.collection_loader._collection_finder import _get_collection_name_from_path, _get_collection_playbook_path
|
34
29
|
from ansible._internal._templating._engine import TemplateEngine
|
35
|
-
from ansible.
|
36
|
-
|
37
|
-
display = Display()
|
30
|
+
from ansible.errors import AnsibleError
|
31
|
+
from ansible import constants as C
|
38
32
|
|
39
33
|
|
40
34
|
class PlaybookInclude(Base, Conditional, Taggable):
|
41
35
|
|
42
|
-
import_playbook = NonInheritableFieldAttribute(isa='string')
|
36
|
+
import_playbook = NonInheritableFieldAttribute(isa='string', required=True)
|
43
37
|
vars_val = NonInheritableFieldAttribute(isa='dict', default=dict, alias='vars')
|
44
38
|
|
39
|
+
_post_validate_object = True # manually post_validate to get free arg validation/coercion
|
40
|
+
|
41
|
+
def preprocess_data(self, ds):
|
42
|
+
keys = {action for action in C._ACTION_IMPORT_PLAYBOOK if action in ds}
|
43
|
+
|
44
|
+
if len(keys) != 1:
|
45
|
+
raise AnsibleError(f'Found conflicting import_playbook actions: {", ".join(sorted(keys))}')
|
46
|
+
|
47
|
+
key = next(iter(keys))
|
48
|
+
|
49
|
+
ds['import_playbook'] = ds.pop(key)
|
50
|
+
|
51
|
+
return ds
|
52
|
+
|
45
53
|
@staticmethod
|
46
54
|
def load(data, basedir, variable_manager=None, loader=None):
|
47
55
|
return PlaybookInclude().load_data(ds=data, basedir=basedir, variable_manager=variable_manager, loader=loader)
|
@@ -62,18 +70,22 @@ class PlaybookInclude(Base, Conditional, Taggable):
|
|
62
70
|
new_obj = super(PlaybookInclude, self).load_data(ds, variable_manager, loader)
|
63
71
|
|
64
72
|
all_vars = self.vars.copy()
|
73
|
+
|
65
74
|
if variable_manager:
|
66
75
|
all_vars |= variable_manager.get_vars()
|
67
76
|
|
68
77
|
templar = TemplateEngine(loader=loader, variables=all_vars)
|
69
78
|
|
79
|
+
new_obj.post_validate(templar)
|
80
|
+
|
70
81
|
# then we use the object to load a Playbook
|
71
82
|
pb = Playbook(loader=loader)
|
72
83
|
|
73
|
-
file_name =
|
84
|
+
file_name = new_obj.import_playbook
|
74
85
|
|
75
86
|
# check for FQCN
|
76
87
|
resource = _get_collection_playbook_path(file_name)
|
88
|
+
|
77
89
|
if resource is not None:
|
78
90
|
playbook = resource[1]
|
79
91
|
playbook_collection = resource[2]
|
@@ -92,6 +104,7 @@ class PlaybookInclude(Base, Conditional, Taggable):
|
|
92
104
|
else:
|
93
105
|
# it is NOT a collection playbook, setup adjacent paths
|
94
106
|
AnsibleCollectionConfig.playbook_paths.append(os.path.dirname(os.path.abspath(to_bytes(playbook, errors='surrogate_or_strict'))))
|
107
|
+
# broken, see: https://github.com/ansible/ansible/issues/85357
|
95
108
|
|
96
109
|
pb._load_playbook_data(file_name=playbook, variable_manager=variable_manager, vars=self.vars.copy())
|
97
110
|
|
@@ -120,49 +133,3 @@ class PlaybookInclude(Base, Conditional, Taggable):
|
|
120
133
|
task_block._when = new_obj.when[:] + task_block.when[:]
|
121
134
|
|
122
135
|
return pb
|
123
|
-
|
124
|
-
def preprocess_data(self, ds):
|
125
|
-
"""
|
126
|
-
Reorganizes the data for a PlaybookInclude datastructure to line
|
127
|
-
up with what we expect the proper attributes to be
|
128
|
-
"""
|
129
|
-
|
130
|
-
if not isinstance(ds, dict):
|
131
|
-
raise AnsibleAssertionError('ds (%s) should be a dict but was a %s' % (ds, type(ds)))
|
132
|
-
|
133
|
-
# the new, cleaned datastructure, which will have legacy items reduced to a standard structure suitable for the
|
134
|
-
# attributes of the task class; copy any tagged data to preserve things like origin
|
135
|
-
new_ds = AnsibleTagHelper.tag_copy(ds, {})
|
136
|
-
|
137
|
-
for (k, v) in ds.items():
|
138
|
-
if k in C._ACTION_IMPORT_PLAYBOOK:
|
139
|
-
self._preprocess_import(ds, new_ds, k, v)
|
140
|
-
else:
|
141
|
-
# some basic error checking, to make sure vars are properly
|
142
|
-
# formatted and do not conflict with k=v parameters
|
143
|
-
if k == 'vars':
|
144
|
-
if 'vars' in new_ds:
|
145
|
-
raise AnsibleParserError("import_playbook parameters cannot be mixed with 'vars' entries for import statements", obj=ds)
|
146
|
-
elif not isinstance(v, dict):
|
147
|
-
raise AnsibleParserError("vars for import_playbook statements must be specified as a dictionary", obj=ds)
|
148
|
-
new_ds[k] = v
|
149
|
-
|
150
|
-
return super(PlaybookInclude, self).preprocess_data(new_ds)
|
151
|
-
|
152
|
-
def _preprocess_import(self, ds, new_ds, k, v):
|
153
|
-
"""
|
154
|
-
Splits the playbook import line up into filename and parameters
|
155
|
-
"""
|
156
|
-
if v is None:
|
157
|
-
raise AnsibleParserError("playbook import parameter is missing", obj=ds)
|
158
|
-
elif not isinstance(v, string_types):
|
159
|
-
raise AnsibleParserError("playbook import parameter must be a string indicating a file path, got %s instead" % type(v), obj=ds)
|
160
|
-
|
161
|
-
# The import_playbook line must include at least one item, which is the filename
|
162
|
-
# to import. Anything after that should be regarded as a parameter to the import
|
163
|
-
items = split_args(v)
|
164
|
-
if len(items) == 0:
|
165
|
-
raise AnsibleParserError("import_playbook statements must specify the file name to import", obj=ds)
|
166
|
-
|
167
|
-
# DTFIX3: investigate this as a possible "problematic strip"
|
168
|
-
new_ds['import_playbook'] = AnsibleTagHelper.tag_copy(v, items[0].strip())
|
@@ -18,6 +18,7 @@
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
20
|
import os
|
21
|
+
import typing as _t
|
21
22
|
|
22
23
|
from collections.abc import Container, Mapping, Set, Sequence
|
23
24
|
from types import MappingProxyType
|
@@ -39,6 +40,16 @@ from ansible.utils.collection_loader import AnsibleCollectionConfig
|
|
39
40
|
from ansible.utils.path import is_subpath
|
40
41
|
from ansible.utils.vars import combine_vars
|
41
42
|
|
43
|
+
# NOTE: This import is only needed for the type-checking in __init__. While there's an alternative
|
44
|
+
# available by using forward references this seems not to work well with commonly used IDEs.
|
45
|
+
# Therefore the TYPE_CHECKING hack seems to be a more universal approach, even if not being very elegant.
|
46
|
+
# References:
|
47
|
+
# * https://stackoverflow.com/q/39740632/199513
|
48
|
+
# * https://peps.python.org/pep-0484/#forward-references
|
49
|
+
if _t.TYPE_CHECKING:
|
50
|
+
from ansible.playbook.block import Block
|
51
|
+
from ansible.playbook.play import Play
|
52
|
+
|
42
53
|
__all__ = ['Role', 'hash_params']
|
43
54
|
|
44
55
|
# TODO: this should be a utility function, but can't be a member of
|
@@ -97,13 +108,19 @@ def hash_params(params):
|
|
97
108
|
|
98
109
|
class Role(Base, Conditional, Taggable, CollectionSearch, Delegatable):
|
99
110
|
|
100
|
-
def __init__(self,
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
111
|
+
def __init__(self,
|
112
|
+
play: Play = None,
|
113
|
+
from_files: dict[str, list[str]] = None,
|
114
|
+
from_include: bool = False,
|
115
|
+
validate: bool = True,
|
116
|
+
public: bool = None,
|
117
|
+
static: bool = True) -> None:
|
118
|
+
self._role_name: str = None
|
119
|
+
self._role_path: str = None
|
120
|
+
self._role_collection: str = None
|
121
|
+
self._role_params: dict[str, dict[str, str]] = dict()
|
105
122
|
self._loader = None
|
106
|
-
self.static = static
|
123
|
+
self.static: bool = static
|
107
124
|
|
108
125
|
# includes (static=false) default to private, while imports (static=true) default to public
|
109
126
|
# but both can be overridden by global config if set
|
@@ -116,26 +133,26 @@ class Role(Base, Conditional, Taggable, CollectionSearch, Delegatable):
|
|
116
133
|
else:
|
117
134
|
self.public = public
|
118
135
|
|
119
|
-
self._metadata = RoleMetadata()
|
120
|
-
self._play = play
|
121
|
-
self._parents = []
|
122
|
-
self._dependencies = []
|
123
|
-
self._all_dependencies = None
|
124
|
-
self._task_blocks = []
|
125
|
-
self._handler_blocks = []
|
126
|
-
self._compiled_handler_blocks = None
|
127
|
-
self._default_vars = dict()
|
128
|
-
self._role_vars = dict()
|
129
|
-
self._had_task_run = dict()
|
130
|
-
self._completed = dict()
|
131
|
-
self._should_validate = validate
|
136
|
+
self._metadata: RoleMetadata = RoleMetadata()
|
137
|
+
self._play: Play = play
|
138
|
+
self._parents: list[Role] = []
|
139
|
+
self._dependencies: list[Role] = []
|
140
|
+
self._all_dependencies: list[Role] | None = None
|
141
|
+
self._task_blocks: list[Block] = []
|
142
|
+
self._handler_blocks: list[Block] = []
|
143
|
+
self._compiled_handler_blocks: list[Block] | None = None
|
144
|
+
self._default_vars: dict[str, str] | None = dict()
|
145
|
+
self._role_vars: dict[str, str] | None = dict()
|
146
|
+
self._had_task_run: dict[str, bool] = dict()
|
147
|
+
self._completed: dict[str, bool] = dict()
|
148
|
+
self._should_validate: bool = validate
|
132
149
|
|
133
150
|
if from_files is None:
|
134
151
|
from_files = {}
|
135
|
-
self._from_files = from_files
|
152
|
+
self._from_files: dict[str, list[str]] = from_files
|
136
153
|
|
137
154
|
# Indicates whether this role was included via include/import_role
|
138
|
-
self.from_include = from_include
|
155
|
+
self.from_include: bool = from_include
|
139
156
|
|
140
157
|
self._hash = None
|
141
158
|
|
ansible/playbook/taggable.py
CHANGED
@@ -17,6 +17,8 @@
|
|
17
17
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
|
+
import typing as t
|
21
|
+
|
20
22
|
from ansible.errors import AnsibleError
|
21
23
|
from ansible.module_utils.six import string_types
|
22
24
|
from ansible.module_utils.common.sentinel import Sentinel
|
@@ -25,7 +27,7 @@ from ansible.playbook.attribute import FieldAttribute
|
|
25
27
|
from ansible._internal._templating._engine import TemplateEngine
|
26
28
|
|
27
29
|
|
28
|
-
def _flatten_tags(tags: list) -> list:
|
30
|
+
def _flatten_tags(tags: list[str | int]) -> list[str | int]:
|
29
31
|
rv = set()
|
30
32
|
for tag in tags:
|
31
33
|
if isinstance(tag, list):
|
@@ -49,16 +51,28 @@ class Taggable:
|
|
49
51
|
|
50
52
|
raise AnsibleError('tags must be specified as a list', obj=ds)
|
51
53
|
|
54
|
+
def _get_all_taggable_objects(self) -> t.Iterable[Taggable]:
|
55
|
+
obj = self
|
56
|
+
while obj is not None:
|
57
|
+
yield obj
|
58
|
+
|
59
|
+
if (role := getattr(obj, "_role", Sentinel)) is not Sentinel:
|
60
|
+
yield role # type: ignore[misc]
|
61
|
+
|
62
|
+
obj = obj._parent
|
63
|
+
|
64
|
+
yield self.get_play()
|
65
|
+
|
52
66
|
def evaluate_tags(self, only_tags, skip_tags, all_vars):
|
53
|
-
"""
|
67
|
+
"""Check if the current item should be executed depending on the specified tags.
|
54
68
|
|
69
|
+
NOTE this method is assumed to be called only on Task objects.
|
70
|
+
"""
|
55
71
|
if self.tags:
|
56
72
|
templar = TemplateEngine(loader=self._loader, variables=all_vars)
|
57
|
-
obj
|
58
|
-
while obj is not None:
|
73
|
+
for obj in self._get_all_taggable_objects():
|
59
74
|
if (_tags := getattr(obj, "_tags", Sentinel)) is not Sentinel:
|
60
75
|
obj._tags = _flatten_tags(templar.template(_tags))
|
61
|
-
obj = obj._parent
|
62
76
|
tags = set(self.tags)
|
63
77
|
else:
|
64
78
|
# this makes isdisjoint work for untagged
|
ansible/playbook/task.py
CHANGED
@@ -65,6 +65,8 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl
|
|
65
65
|
Task.something(...)
|
66
66
|
"""
|
67
67
|
|
68
|
+
_post_validate_object = True
|
69
|
+
|
68
70
|
# =================================================================================
|
69
71
|
# ATTRIBUTES
|
70
72
|
# load_<attribute_name> and
|
@@ -103,7 +103,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
103
103
|
self._display = display
|
104
104
|
|
105
105
|
@abstractmethod
|
106
|
-
def run(self, tmp=None, task_vars=None):
|
106
|
+
def run(self, tmp: str | None = None, task_vars: dict[str, t.Any] | None = None) -> dict[str, t.Any]:
|
107
107
|
""" Action Plugins should implement this method to perform their
|
108
108
|
tasks. Everything else in this base class is a helper method for the
|
109
109
|
action plugin to do that.
|
@@ -120,7 +120,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
120
120
|
* Module parameters. These are stored in self._task.args
|
121
121
|
"""
|
122
122
|
# does not default to {'changed': False, 'failed': False}, as it used to break async
|
123
|
-
result = {}
|
123
|
+
result: dict[str, t.Any] = {}
|
124
124
|
|
125
125
|
if tmp is not None:
|
126
126
|
display.warning('ActionModule.run() no longer honors the tmp parameter. Action'
|
@@ -81,9 +81,10 @@ class ActionModule(ActionBase):
|
|
81
81
|
|
82
82
|
def run(self, tmp=None, task_vars=None):
|
83
83
|
|
84
|
-
self._supports_check_mode =
|
84
|
+
self._supports_check_mode = True
|
85
85
|
|
86
86
|
super(ActionModule, self).run(tmp, task_vars)
|
87
|
+
|
87
88
|
del tmp # tmp no longer has any effect
|
88
89
|
|
89
90
|
if task_vars is None:
|
ansible/plugins/action/assert.py
CHANGED
@@ -72,12 +72,12 @@ class ActionModule(ActionBase):
|
|
72
72
|
fail_msg = new_module_args['fail_msg']
|
73
73
|
success_msg = new_module_args['success_msg']
|
74
74
|
quiet = new_module_args['quiet']
|
75
|
-
|
75
|
+
that_list = new_module_args['that']
|
76
76
|
|
77
77
|
if not quiet:
|
78
78
|
result['_ansible_verbose_always'] = True
|
79
79
|
|
80
|
-
for that in
|
80
|
+
for that in that_list:
|
81
81
|
test_result = self._templar.evaluate_conditional(conditional=that)
|
82
82
|
if not test_result:
|
83
83
|
result['failed'] = True
|
ansible/plugins/action/fetch.py
CHANGED
@@ -119,7 +119,7 @@ class ActionModule(ActionBase):
|
|
119
119
|
|
120
120
|
if 'not found' in slurpres.get('msg', ''):
|
121
121
|
result['msg'] = "the remote file does not exist, not transferring, ignored"
|
122
|
-
elif slurpres.get('msg', '').startswith('source is a directory'):
|
122
|
+
elif slurpres.get('msg', '').lower().startswith('source is a directory'):
|
123
123
|
result['msg'] = "remote file is a directory, fetch cannot work on directories"
|
124
124
|
|
125
125
|
return result
|
@@ -180,8 +180,8 @@ class ActionModule(ActionBase):
|
|
180
180
|
try:
|
181
181
|
with open(to_bytes(dest, errors='surrogate_or_strict'), 'wb') as f:
|
182
182
|
f.write(remote_data)
|
183
|
-
except
|
184
|
-
raise AnsibleActionFail("Failed to fetch the file
|
183
|
+
except OSError as ex:
|
184
|
+
raise AnsibleActionFail("Failed to fetch the file.") from ex
|
185
185
|
new_checksum = secure_hash(dest)
|
186
186
|
# For backwards compatibility. We'll return None on FIPS enabled systems
|
187
187
|
try:
|
ansible/plugins/action/script.py
CHANGED
@@ -20,6 +20,7 @@ import os
|
|
20
20
|
import pathlib
|
21
21
|
import re
|
22
22
|
import shlex
|
23
|
+
import typing as _t
|
23
24
|
|
24
25
|
from ansible.errors import AnsibleError, AnsibleActionFail, AnsibleActionSkip
|
25
26
|
from ansible.executor.powershell import module_manifest as ps_manifest
|
@@ -35,7 +36,7 @@ class ActionModule(ActionBase):
|
|
35
36
|
# after chopping off a potential drive letter.
|
36
37
|
windows_absolute_path_detection = re.compile(r'^(?:[a-zA-Z]\:)?(\\|\/)')
|
37
38
|
|
38
|
-
def run(self, tmp=None, task_vars=None):
|
39
|
+
def run(self, tmp: str | None = None, task_vars: dict[str, _t.Any] | None = None) -> dict[str, _t.Any]:
|
39
40
|
""" handler for file transfer operations """
|
40
41
|
if task_vars is None:
|
41
42
|
task_vars = dict()
|
@@ -130,7 +131,7 @@ class ActionModule(ActionBase):
|
|
130
131
|
self._fixup_perms2((self._connection._shell.tmpdir, tmp_src), execute=True)
|
131
132
|
|
132
133
|
# add preparation steps to one ssh roundtrip executing the script
|
133
|
-
env_dict =
|
134
|
+
env_dict: dict[str, _t.Any] = {}
|
134
135
|
env_string = self._compute_environment_string(env_dict)
|
135
136
|
|
136
137
|
if executable:
|
@@ -164,10 +165,10 @@ class ActionModule(ActionBase):
|
|
164
165
|
script_cmd = self._connection._shell.build_module_command(env_string='', shebang='#!powershell', cmd='')
|
165
166
|
|
166
167
|
# now we execute script, always assume changed.
|
167
|
-
result = dict(self._low_level_execute_command(cmd=script_cmd, in_data=exec_data, sudoable=True, chdir=chdir), changed=True)
|
168
|
+
result: dict[str, object] = dict(self._low_level_execute_command(cmd=script_cmd, in_data=exec_data, sudoable=True, chdir=chdir), changed=True)
|
168
169
|
|
169
170
|
if 'rc' in result and result['rc'] != 0:
|
170
|
-
|
171
|
+
result.update(msg='non-zero return code', failed=True)
|
171
172
|
|
172
173
|
return result
|
173
174
|
finally:
|
@@ -25,7 +25,8 @@ from ansible.module_utils.common.text.converters import to_bytes, to_text, to_na
|
|
25
25
|
from ansible.module_utils.parsing.convert_bool import boolean
|
26
26
|
from ansible.module_utils.six import string_types
|
27
27
|
from ansible.plugins.action import ActionBase
|
28
|
-
from ansible.template import
|
28
|
+
from ansible.template import trust_as_template
|
29
|
+
from ansible._internal._templating import _template_vars
|
29
30
|
|
30
31
|
|
31
32
|
class ActionModule(ActionBase):
|
@@ -43,7 +44,7 @@ class ActionModule(ActionBase):
|
|
43
44
|
del tmp # tmp no longer has any effect
|
44
45
|
|
45
46
|
# Options type validation
|
46
|
-
#
|
47
|
+
# strings
|
47
48
|
for s_type in ('src', 'dest', 'state', 'newline_sequence', 'variable_start_string', 'variable_end_string', 'block_start_string',
|
48
49
|
'block_end_string', 'comment_start_string', 'comment_end_string'):
|
49
50
|
if s_type in self._task.args:
|
@@ -115,7 +116,12 @@ class ActionModule(ActionBase):
|
|
115
116
|
|
116
117
|
# add ansible 'template' vars
|
117
118
|
temp_vars = task_vars.copy()
|
118
|
-
temp_vars.update(generate_ansible_template_vars(
|
119
|
+
temp_vars.update(_template_vars.generate_ansible_template_vars(
|
120
|
+
path=self._task.args.get('src', None),
|
121
|
+
fullpath=source,
|
122
|
+
dest_path=dest,
|
123
|
+
include_ansible_managed='ansible_managed' not in temp_vars, # do not clobber ansible_managed when set by the user
|
124
|
+
))
|
119
125
|
|
120
126
|
overrides = dict(
|
121
127
|
block_start_string=block_start_string,
|
@@ -18,7 +18,6 @@
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
20
|
import copy
|
21
|
-
import errno
|
22
21
|
import os
|
23
22
|
import tempfile
|
24
23
|
import time
|
@@ -108,8 +107,8 @@ class BaseFileCacheModule(BaseCacheModule):
|
|
108
107
|
if not os.path.exists(self._cache_dir):
|
109
108
|
try:
|
110
109
|
os.makedirs(self._cache_dir)
|
111
|
-
except
|
112
|
-
raise AnsibleError("
|
110
|
+
except OSError as ex:
|
111
|
+
raise AnsibleError(f"Error in {self.plugin_name!r} cache plugin while trying to create cache dir {self._cache_dir!r}.") from ex
|
113
112
|
else:
|
114
113
|
for x in (os.R_OK, os.W_OK, os.X_OK):
|
115
114
|
if not os.access(self._cache_dir, x):
|
@@ -160,13 +159,13 @@ class BaseFileCacheModule(BaseCacheModule):
|
|
160
159
|
try:
|
161
160
|
try:
|
162
161
|
self._dump(value, tmpfile_path)
|
163
|
-
except
|
164
|
-
display.
|
162
|
+
except OSError as ex:
|
163
|
+
display.error_as_warning(f"Error in {self.plugin_name!r} cache plugin while trying to write to {tmpfile_path!r}.", exception=ex)
|
165
164
|
try:
|
166
165
|
os.rename(tmpfile_path, cachefile)
|
167
166
|
os.chmod(cachefile, mode=S_IRWU_RG_RO)
|
168
|
-
except
|
169
|
-
display.
|
167
|
+
except OSError as ex:
|
168
|
+
display.error_as_warning(f"Error in {self.plugin_name!r} cache plugin while trying to move {tmpfile_path!r} to {cachefile!r}.", exception=ex)
|
170
169
|
finally:
|
171
170
|
try:
|
172
171
|
os.unlink(tmpfile_path)
|
@@ -181,12 +180,12 @@ class BaseFileCacheModule(BaseCacheModule):
|
|
181
180
|
cachefile = self._get_cache_file_name(key)
|
182
181
|
try:
|
183
182
|
st = os.stat(cachefile)
|
184
|
-
except
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
183
|
+
except FileNotFoundError:
|
184
|
+
return False
|
185
|
+
except OSError as ex:
|
186
|
+
display.error_as_warning(f"Error in {self.plugin_name!r} cache plugin while trying to stat {cachefile!r}.", exception=ex)
|
187
|
+
|
188
|
+
return False
|
190
189
|
|
191
190
|
if time.time() - st.st_mtime <= self._timeout:
|
192
191
|
return False
|
@@ -223,11 +222,10 @@ class BaseFileCacheModule(BaseCacheModule):
|
|
223
222
|
try:
|
224
223
|
os.stat(cachefile)
|
225
224
|
return True
|
226
|
-
except
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
display.warning("error in '%s' cache plugin while trying to stat %s : %s" % (self.plugin_name, cachefile, to_bytes(e)))
|
225
|
+
except FileNotFoundError:
|
226
|
+
return False
|
227
|
+
except OSError as ex:
|
228
|
+
display.error_as_warning(f"Error in {self.plugin_name!r} cache plugin while trying to stat {cachefile!r}.", exception=ex)
|
231
229
|
|
232
230
|
def delete(self, key):
|
233
231
|
try:
|
@@ -236,7 +234,7 @@ class BaseFileCacheModule(BaseCacheModule):
|
|
236
234
|
pass
|
237
235
|
try:
|
238
236
|
os.remove(self._get_cache_file_name(key))
|
239
|
-
except
|
237
|
+
except OSError:
|
240
238
|
pass # TODO: only pass on non existing?
|
241
239
|
|
242
240
|
def flush(self):
|