ansible-core 2.19.3rc1__py3-none-any.whl → 2.20.0b2__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 +70 -68
- 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/collections/list.py +4 -2
- 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 +4 -17
- ansible/galaxy/dependency_resolution/dataclasses.py +0 -10
- ansible/galaxy/dependency_resolution/providers.py +24 -118
- 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 +19 -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/mod_args.py +3 -0
- ansible/parsing/vault/__init__.py +1 -2
- ansible/playbook/base.py +8 -56
- ansible/playbook/block.py +1 -63
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/handler.py +1 -7
- ansible/playbook/helpers.py +15 -20
- ansible/playbook/included_file.py +1 -1
- ansible/playbook/play.py +105 -49
- 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 +51 -55
- 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 +6 -3
- 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.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/METADATA +3 -3
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/RECORD +199 -200
- 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/sanity.changelog.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- 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/validate_modules.py +1 -5
- ansible_test/_internal/commands/units/__init__.py +1 -13
- 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/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/unwanted.py +40 -27
- 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.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.3rc1.dist-info → ansible_core-2.20.0b2.dist-info}/top_level.txt +0 -0
ansible/playbook/block.py
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
import ansible.constants as C
|
|
21
20
|
from ansible.errors import AnsibleParserError
|
|
22
21
|
from ansible.module_utils.common.sentinel import Sentinel
|
|
23
22
|
from ansible.playbook.attribute import NonInheritableFieldAttribute
|
|
@@ -27,7 +26,6 @@ from ansible.playbook.collectionsearch import CollectionSearch
|
|
|
27
26
|
from ansible.playbook.delegatable import Delegatable
|
|
28
27
|
from ansible.playbook.helpers import load_list_of_tasks
|
|
29
28
|
from ansible.playbook.notifiable import Notifiable
|
|
30
|
-
from ansible.playbook.role import Role
|
|
31
29
|
from ansible.playbook.taggable import Taggable
|
|
32
30
|
|
|
33
31
|
|
|
@@ -220,65 +218,6 @@ class Block(Base, Conditional, CollectionSearch, Taggable, Notifiable, Delegatab
|
|
|
220
218
|
new_me.validate()
|
|
221
219
|
return new_me
|
|
222
220
|
|
|
223
|
-
def serialize(self):
|
|
224
|
-
"""
|
|
225
|
-
Override of the default serialize method, since when we're serializing
|
|
226
|
-
a task we don't want to include the attribute list of tasks.
|
|
227
|
-
"""
|
|
228
|
-
|
|
229
|
-
data = dict()
|
|
230
|
-
for attr in self.fattributes:
|
|
231
|
-
if attr not in ('block', 'rescue', 'always'):
|
|
232
|
-
data[attr] = getattr(self, attr)
|
|
233
|
-
|
|
234
|
-
data['dep_chain'] = self.get_dep_chain()
|
|
235
|
-
|
|
236
|
-
if self._role is not None:
|
|
237
|
-
data['role'] = self._role.serialize()
|
|
238
|
-
if self._parent is not None:
|
|
239
|
-
data['parent'] = self._parent.copy(exclude_tasks=True).serialize()
|
|
240
|
-
data['parent_type'] = self._parent.__class__.__name__
|
|
241
|
-
|
|
242
|
-
return data
|
|
243
|
-
|
|
244
|
-
def deserialize(self, data):
|
|
245
|
-
"""
|
|
246
|
-
Override of the default deserialize method, to match the above overridden
|
|
247
|
-
serialize method
|
|
248
|
-
"""
|
|
249
|
-
|
|
250
|
-
# import is here to avoid import loops
|
|
251
|
-
from ansible.playbook.task_include import TaskInclude
|
|
252
|
-
from ansible.playbook.handler_task_include import HandlerTaskInclude
|
|
253
|
-
|
|
254
|
-
# we don't want the full set of attributes (the task lists), as that
|
|
255
|
-
# would lead to a serialize/deserialize loop
|
|
256
|
-
for attr in self.fattributes:
|
|
257
|
-
if attr in data and attr not in ('block', 'rescue', 'always'):
|
|
258
|
-
setattr(self, attr, data.get(attr))
|
|
259
|
-
|
|
260
|
-
self._dep_chain = data.get('dep_chain', None)
|
|
261
|
-
|
|
262
|
-
# if there was a serialized role, unpack it too
|
|
263
|
-
role_data = data.get('role')
|
|
264
|
-
if role_data:
|
|
265
|
-
r = Role()
|
|
266
|
-
r.deserialize(role_data)
|
|
267
|
-
self._role = r
|
|
268
|
-
|
|
269
|
-
parent_data = data.get('parent')
|
|
270
|
-
if parent_data:
|
|
271
|
-
parent_type = data.get('parent_type')
|
|
272
|
-
if parent_type == 'Block':
|
|
273
|
-
p = Block()
|
|
274
|
-
elif parent_type == 'TaskInclude':
|
|
275
|
-
p = TaskInclude()
|
|
276
|
-
elif parent_type == 'HandlerTaskInclude':
|
|
277
|
-
p = HandlerTaskInclude()
|
|
278
|
-
p.deserialize(parent_data)
|
|
279
|
-
self._parent = p
|
|
280
|
-
self._dep_chain = self._parent.get_dep_chain()
|
|
281
|
-
|
|
282
221
|
def set_loader(self, loader):
|
|
283
222
|
self._loader = loader
|
|
284
223
|
if self._parent:
|
|
@@ -376,8 +315,7 @@ class Block(Base, Conditional, CollectionSearch, Taggable, Notifiable, Delegatab
|
|
|
376
315
|
filtered_block = evaluate_block(task)
|
|
377
316
|
if filtered_block.has_tasks():
|
|
378
317
|
tmp_list.append(filtered_block)
|
|
379
|
-
elif
|
|
380
|
-
task.evaluate_tags(self._play.only_tags, self._play.skip_tags, all_vars=all_vars)):
|
|
318
|
+
elif task.evaluate_tags(self._play.only_tags, self._play.skip_tags, all_vars=all_vars):
|
|
381
319
|
tmp_list.append(task)
|
|
382
320
|
return tmp_list
|
|
383
321
|
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
from ansible.module_utils.six import string_types
|
|
7
6
|
from ansible.playbook.attribute import FieldAttribute
|
|
8
7
|
from ansible.utils.collection_loader import AnsibleCollectionConfig
|
|
9
8
|
from ansible.utils.display import Display
|
|
@@ -32,7 +31,7 @@ def _ensure_default_collection(collection_list=None):
|
|
|
32
31
|
class CollectionSearch:
|
|
33
32
|
|
|
34
33
|
# this needs to be populated before we can resolve tasks/roles/etc
|
|
35
|
-
collections = FieldAttribute(isa='list', listof=
|
|
34
|
+
collections = FieldAttribute(isa='list', listof=(str,), priority=100, default=_ensure_default_collection, always_post_validate=True, static=True)
|
|
36
35
|
|
|
37
36
|
def _load_collections(self, attr, ds):
|
|
38
37
|
# We are always a mixin with Base, so we can validate this untemplated
|
ansible/playbook/handler.py
CHANGED
|
@@ -20,12 +20,11 @@ from __future__ import annotations
|
|
|
20
20
|
from ansible.errors import AnsibleAssertionError
|
|
21
21
|
from ansible.playbook.attribute import NonInheritableFieldAttribute
|
|
22
22
|
from ansible.playbook.task import Task
|
|
23
|
-
from ansible.module_utils.six import string_types
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
class Handler(Task):
|
|
27
26
|
|
|
28
|
-
listen = NonInheritableFieldAttribute(isa='list', default=list, listof=
|
|
27
|
+
listen = NonInheritableFieldAttribute(isa='list', default=list, listof=(str,), static=True)
|
|
29
28
|
|
|
30
29
|
def __init__(self, block=None, role=None, task_include=None):
|
|
31
30
|
self.notified_hosts = []
|
|
@@ -72,8 +71,3 @@ class Handler(Task):
|
|
|
72
71
|
|
|
73
72
|
def is_host_notified(self, host):
|
|
74
73
|
return host in self.notified_hosts
|
|
75
|
-
|
|
76
|
-
def serialize(self):
|
|
77
|
-
result = super(Handler, self).serialize()
|
|
78
|
-
result['is_handler'] = True
|
|
79
|
-
return result
|
ansible/playbook/helpers.py
CHANGED
|
@@ -165,17 +165,29 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
|
|
|
165
165
|
subdir = 'tasks'
|
|
166
166
|
if use_handlers:
|
|
167
167
|
subdir = 'handlers'
|
|
168
|
+
try:
|
|
169
|
+
include_target = templar.template(task.args['_raw_params'])
|
|
170
|
+
except AnsibleUndefinedVariable as ex:
|
|
171
|
+
raise AnsibleParserError(
|
|
172
|
+
message=f"Error when evaluating variable in import path {task.args['_raw_params']!r}.",
|
|
173
|
+
help_text="When using static imports, ensure that any variables used in their names are defined in vars/vars_files\n"
|
|
174
|
+
"or extra-vars passed in from the command line. Static imports cannot use variables from facts or inventory\n"
|
|
175
|
+
"sources like group or host vars.",
|
|
176
|
+
obj=task_ds,
|
|
177
|
+
) from ex
|
|
178
|
+
# FIXME this appears to be (almost?) duplicate code as in IncludedFile for include_tasks
|
|
168
179
|
while parent_include is not None:
|
|
169
180
|
if not isinstance(parent_include, TaskInclude):
|
|
170
181
|
parent_include = parent_include._parent
|
|
171
182
|
continue
|
|
172
|
-
parent_include
|
|
173
|
-
|
|
183
|
+
if isinstance(parent_include, IncludeRole):
|
|
184
|
+
parent_include_dir = parent_include._role_path
|
|
185
|
+
else:
|
|
186
|
+
parent_include_dir = os.path.dirname(templar.template(parent_include.args.get('_raw_params')))
|
|
174
187
|
if cumulative_path is None:
|
|
175
188
|
cumulative_path = parent_include_dir
|
|
176
189
|
elif not os.path.isabs(cumulative_path):
|
|
177
190
|
cumulative_path = os.path.join(parent_include_dir, cumulative_path)
|
|
178
|
-
include_target = templar.template(task.args['_raw_params'])
|
|
179
191
|
if task._role:
|
|
180
192
|
new_basedir = os.path.join(task._role._role_path, subdir, cumulative_path)
|
|
181
193
|
include_file = loader.path_dwim_relative(new_basedir, subdir, include_target)
|
|
@@ -189,16 +201,6 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
|
|
|
189
201
|
parent_include = parent_include._parent
|
|
190
202
|
|
|
191
203
|
if not found:
|
|
192
|
-
try:
|
|
193
|
-
include_target = templar.template(task.args['_raw_params'])
|
|
194
|
-
except AnsibleUndefinedVariable as ex:
|
|
195
|
-
raise AnsibleParserError(
|
|
196
|
-
message=f"Error when evaluating variable in import path {task.args['_raw_params']!r}.",
|
|
197
|
-
help_text="When using static imports, ensure that any variables used in their names are defined in vars/vars_files\n"
|
|
198
|
-
"or extra-vars passed in from the command line. Static imports cannot use variables from facts or inventory\n"
|
|
199
|
-
"sources like group or host vars.",
|
|
200
|
-
obj=task_ds,
|
|
201
|
-
) from ex
|
|
202
204
|
if task._role:
|
|
203
205
|
include_file = loader.path_dwim_relative(task._role._role_path, subdir, include_target)
|
|
204
206
|
else:
|
|
@@ -230,13 +232,6 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
|
|
|
230
232
|
variable_manager=variable_manager,
|
|
231
233
|
)
|
|
232
234
|
|
|
233
|
-
tags = ti_copy.tags[:]
|
|
234
|
-
|
|
235
|
-
# now we extend the tags on each of the included blocks
|
|
236
|
-
for b in included_blocks:
|
|
237
|
-
b.tags = list(set(b.tags).union(tags))
|
|
238
|
-
# FIXME - END
|
|
239
|
-
|
|
240
235
|
# FIXME: handlers shouldn't need this special handling, but do
|
|
241
236
|
# right now because they don't iterate blocks correctly
|
|
242
237
|
if use_handlers:
|
|
@@ -203,7 +203,7 @@ class IncludedFile:
|
|
|
203
203
|
for from_arg in new_task.FROM_ARGS:
|
|
204
204
|
if from_arg in include_args:
|
|
205
205
|
from_key = from_arg.removesuffix('_from')
|
|
206
|
-
new_task._from_files[from_key] = include_args.
|
|
206
|
+
new_task._from_files[from_key] = include_args.get(from_arg)
|
|
207
207
|
|
|
208
208
|
inc_file = IncludedFile(role_name, include_args, special_vars, new_task, is_role=True)
|
|
209
209
|
|
ansible/playbook/play.py
CHANGED
|
@@ -17,12 +17,15 @@
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import functools as _functools
|
|
21
|
+
import pathlib as _pathlib
|
|
22
|
+
|
|
20
23
|
from ansible import constants as C
|
|
21
24
|
from ansible import context
|
|
22
25
|
from ansible.errors import AnsibleError
|
|
23
|
-
from ansible.errors import AnsibleParserError, AnsibleAssertionError
|
|
26
|
+
from ansible.errors import AnsibleParserError, AnsibleAssertionError, AnsibleValueOmittedError
|
|
24
27
|
from ansible.module_utils.common.collections import is_sequence
|
|
25
|
-
from ansible.module_utils.
|
|
28
|
+
from ansible.module_utils.common.yaml import yaml_dump
|
|
26
29
|
from ansible.playbook.attribute import NonInheritableFieldAttribute
|
|
27
30
|
from ansible.playbook.base import Base
|
|
28
31
|
from ansible.playbook.block import Block
|
|
@@ -34,6 +37,8 @@ from ansible.playbook.taggable import Taggable
|
|
|
34
37
|
from ansible.parsing.vault import EncryptedString
|
|
35
38
|
from ansible.utils.display import Display
|
|
36
39
|
|
|
40
|
+
from ansible._internal._templating._engine import TemplateEngine as _TE
|
|
41
|
+
|
|
37
42
|
display = Display()
|
|
38
43
|
|
|
39
44
|
|
|
@@ -53,11 +58,11 @@ class Play(Base, Taggable, CollectionSearch):
|
|
|
53
58
|
"""
|
|
54
59
|
|
|
55
60
|
# =================================================================================
|
|
56
|
-
hosts = NonInheritableFieldAttribute(isa='list', required=True, listof=
|
|
61
|
+
hosts = NonInheritableFieldAttribute(isa='list', required=True, listof=(str,), always_post_validate=True, priority=-2)
|
|
57
62
|
|
|
58
63
|
# Facts
|
|
59
64
|
gather_facts = NonInheritableFieldAttribute(isa='bool', default=None, always_post_validate=True)
|
|
60
|
-
gather_subset = NonInheritableFieldAttribute(isa='list', default=None, listof=
|
|
65
|
+
gather_subset = NonInheritableFieldAttribute(isa='list', default=None, listof=(str,), always_post_validate=True)
|
|
61
66
|
gather_timeout = NonInheritableFieldAttribute(isa='int', default=None, always_post_validate=True)
|
|
62
67
|
fact_path = NonInheritableFieldAttribute(isa='string', default=None)
|
|
63
68
|
|
|
@@ -65,6 +70,8 @@ class Play(Base, Taggable, CollectionSearch):
|
|
|
65
70
|
vars_files = NonInheritableFieldAttribute(isa='list', default=list, priority=99)
|
|
66
71
|
vars_prompt = NonInheritableFieldAttribute(isa='list', default=list, always_post_validate=False)
|
|
67
72
|
|
|
73
|
+
validate_argspec = NonInheritableFieldAttribute(isa='string', always_post_validate=True)
|
|
74
|
+
|
|
68
75
|
# Role Attributes
|
|
69
76
|
roles = NonInheritableFieldAttribute(isa='list', default=list, priority=90)
|
|
70
77
|
|
|
@@ -120,10 +127,10 @@ class Play(Base, Taggable, CollectionSearch):
|
|
|
120
127
|
for entry in value:
|
|
121
128
|
if entry is None:
|
|
122
129
|
raise AnsibleParserError("Hosts list cannot contain values of 'None'. Please check your playbook")
|
|
123
|
-
elif not isinstance(entry, (
|
|
130
|
+
elif not isinstance(entry, (bytes, str)):
|
|
124
131
|
raise AnsibleParserError("Hosts list contains an invalid host value: '{host!s}'".format(host=entry))
|
|
125
132
|
|
|
126
|
-
elif not isinstance(value, (
|
|
133
|
+
elif not isinstance(value, (bytes, str, EncryptedString)):
|
|
127
134
|
raise AnsibleParserError("Hosts list must be a sequence or string. Please check your playbook.")
|
|
128
135
|
|
|
129
136
|
def get_name(self):
|
|
@@ -303,23 +310,13 @@ class Play(Base, Taggable, CollectionSearch):
|
|
|
303
310
|
|
|
304
311
|
t = Task(block=flush_block)
|
|
305
312
|
t.action = 'meta'
|
|
306
|
-
t.
|
|
313
|
+
t._resolved_action = 'ansible.builtin.meta'
|
|
307
314
|
t.args['_raw_params'] = 'flush_handlers'
|
|
308
315
|
t.implicit = True
|
|
309
316
|
t.set_loader(self._loader)
|
|
317
|
+
t.tags = ['always']
|
|
310
318
|
|
|
311
|
-
|
|
312
|
-
# Avoid calling flush_handlers in case the whole play is skipped on tags,
|
|
313
|
-
# this could be performance improvement since calling flush_handlers on
|
|
314
|
-
# large inventories could be expensive even if no hosts are notified
|
|
315
|
-
# since we call flush_handlers per host.
|
|
316
|
-
# Block.filter_tagged_tasks ignores evaluating tags on implicit meta
|
|
317
|
-
# tasks so we need to explicitly call Task.evaluate_tags here.
|
|
318
|
-
t.tags = self.tags
|
|
319
|
-
if t.evaluate_tags(self.only_tags, self.skip_tags, all_vars=self.vars):
|
|
320
|
-
flush_block.block = [t]
|
|
321
|
-
else:
|
|
322
|
-
flush_block.block = [t]
|
|
319
|
+
flush_block.block = [t]
|
|
323
320
|
|
|
324
321
|
# NOTE keep flush_handlers tasks even if a section has no regular tasks,
|
|
325
322
|
# there may be notified handlers from the previous section
|
|
@@ -400,36 +397,6 @@ class Play(Base, Taggable, CollectionSearch):
|
|
|
400
397
|
tasklist.append(task)
|
|
401
398
|
return tasklist
|
|
402
399
|
|
|
403
|
-
def serialize(self):
|
|
404
|
-
data = super(Play, self).serialize()
|
|
405
|
-
|
|
406
|
-
roles = []
|
|
407
|
-
for role in self.get_roles():
|
|
408
|
-
roles.append(role.serialize())
|
|
409
|
-
data['roles'] = roles
|
|
410
|
-
data['included_path'] = self._included_path
|
|
411
|
-
data['action_groups'] = self._action_groups
|
|
412
|
-
data['group_actions'] = self._group_actions
|
|
413
|
-
|
|
414
|
-
return data
|
|
415
|
-
|
|
416
|
-
def deserialize(self, data):
|
|
417
|
-
super(Play, self).deserialize(data)
|
|
418
|
-
|
|
419
|
-
self._included_path = data.get('included_path', None)
|
|
420
|
-
self._action_groups = data.get('action_groups', {})
|
|
421
|
-
self._group_actions = data.get('group_actions', {})
|
|
422
|
-
if 'roles' in data:
|
|
423
|
-
role_data = data.get('roles', [])
|
|
424
|
-
roles = []
|
|
425
|
-
for role in role_data:
|
|
426
|
-
r = Role()
|
|
427
|
-
r.deserialize(role)
|
|
428
|
-
roles.append(r)
|
|
429
|
-
|
|
430
|
-
setattr(self, 'roles', roles)
|
|
431
|
-
del data['roles']
|
|
432
|
-
|
|
433
400
|
def copy(self):
|
|
434
401
|
new_me = super(Play, self).copy()
|
|
435
402
|
new_me.role_cache = self.role_cache.copy()
|
|
@@ -438,3 +405,92 @@ class Play(Base, Taggable, CollectionSearch):
|
|
|
438
405
|
new_me._action_groups = self._action_groups
|
|
439
406
|
new_me._group_actions = self._group_actions
|
|
440
407
|
return new_me
|
|
408
|
+
|
|
409
|
+
def _post_validate_validate_argspec(self, attr: NonInheritableFieldAttribute, value: object, templar: _TE) -> str | None:
|
|
410
|
+
"""Validate user input is a bool or string, and return the corresponding argument spec name."""
|
|
411
|
+
|
|
412
|
+
# Ensure the configuration is valid
|
|
413
|
+
if isinstance(value, str):
|
|
414
|
+
try:
|
|
415
|
+
value = templar.template(value)
|
|
416
|
+
except AnsibleValueOmittedError:
|
|
417
|
+
value = False
|
|
418
|
+
|
|
419
|
+
if not isinstance(value, (str, bool)):
|
|
420
|
+
raise AnsibleParserError(f"validate_argspec must be a boolean or string, not {type(value)}", obj=value)
|
|
421
|
+
|
|
422
|
+
# Short-circuit if configuration is turned off or inapplicable
|
|
423
|
+
if not value or self._origin is None:
|
|
424
|
+
return None
|
|
425
|
+
|
|
426
|
+
# Use the requested argument spec or fall back to the play name
|
|
427
|
+
argspec_name = None
|
|
428
|
+
if isinstance(value, str):
|
|
429
|
+
argspec_name = value
|
|
430
|
+
elif self._ds.get("name"):
|
|
431
|
+
argspec_name = self.name
|
|
432
|
+
|
|
433
|
+
metadata_err = argspec_err = ""
|
|
434
|
+
if not argspec_name:
|
|
435
|
+
argspec_err = (
|
|
436
|
+
"A play name is required when validate_argspec is True. "
|
|
437
|
+
"Alternatively, set validate_argspec to the name of an argument spec."
|
|
438
|
+
)
|
|
439
|
+
if self._metadata_path is None:
|
|
440
|
+
metadata_err = "A playbook meta file is required. Considered:\n - "
|
|
441
|
+
metadata_err += "\n - ".join([path.as_posix() for path in self._metadata_candidate_paths])
|
|
442
|
+
|
|
443
|
+
if metadata_err or argspec_err:
|
|
444
|
+
error = f"{argspec_err + (' ' if argspec_err else '')}{metadata_err}"
|
|
445
|
+
raise AnsibleParserError(error, obj=self._origin)
|
|
446
|
+
|
|
447
|
+
metadata = self._loader.load_from_file(self._metadata_path)
|
|
448
|
+
|
|
449
|
+
try:
|
|
450
|
+
metadata = metadata['argument_specs']
|
|
451
|
+
metadata = metadata[argspec_name]
|
|
452
|
+
options = metadata['options']
|
|
453
|
+
except (TypeError, KeyError):
|
|
454
|
+
options = None
|
|
455
|
+
|
|
456
|
+
if not isinstance(options, dict):
|
|
457
|
+
raise AnsibleParserError(
|
|
458
|
+
f"No argument spec named '{argspec_name}' in {self._metadata_path}. Minimally expected:\n"
|
|
459
|
+
+ yaml_dump({"argument_specs": {f"{argspec_name!s}": {"options": {}}}}),
|
|
460
|
+
obj=metadata,
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
return argspec_name
|
|
464
|
+
|
|
465
|
+
@property
|
|
466
|
+
def _metadata_candidate_paths(self) -> list[_pathlib.Path]:
|
|
467
|
+
"""A list of possible playbook.meta paths in configured order."""
|
|
468
|
+
extensions = C.config.get_config_value("YAML_FILENAME_EXTENSIONS")
|
|
469
|
+
if self._origin.path.endswith(tuple(extensions)):
|
|
470
|
+
playbook_without_ext = self._origin.path.rsplit('.', 1)[0]
|
|
471
|
+
else:
|
|
472
|
+
playbook_without_ext = self._origin.path
|
|
473
|
+
|
|
474
|
+
return [_pathlib.Path(playbook_without_ext + ".meta" + ext) for ext in extensions + ['']]
|
|
475
|
+
|
|
476
|
+
@_functools.cached_property
|
|
477
|
+
def _metadata_path(self) -> str | None:
|
|
478
|
+
"""Locate playbook meta path:
|
|
479
|
+
|
|
480
|
+
playbook{ext?} -> playbook.meta{ext?}
|
|
481
|
+
"""
|
|
482
|
+
if self._origin is None:
|
|
483
|
+
# adhoc, ansible-console don't have an associated playbook
|
|
484
|
+
return None
|
|
485
|
+
for candidate in self._metadata_candidate_paths:
|
|
486
|
+
if candidate.is_file():
|
|
487
|
+
return candidate.as_posix()
|
|
488
|
+
return None
|
|
489
|
+
|
|
490
|
+
@property
|
|
491
|
+
def argument_spec(self) -> dict:
|
|
492
|
+
"""Retrieve the argument spec if one is configured."""
|
|
493
|
+
if not self.validate_argspec:
|
|
494
|
+
return {}
|
|
495
|
+
|
|
496
|
+
return self._loader.load_from_file(self._metadata_path)['argument_specs'][self.validate_argspec]['options']
|
ansible/playbook/play_context.py
CHANGED
|
@@ -325,3 +325,7 @@ class PlayContext(Base):
|
|
|
325
325
|
variables[var_opt] = var_val
|
|
326
326
|
except AttributeError:
|
|
327
327
|
continue
|
|
328
|
+
|
|
329
|
+
def deserialize(self, data):
|
|
330
|
+
"""Do not use this method. Backward compatibility for network connections plugins that rely on it."""
|
|
331
|
+
self.from_attrs(data)
|
|
@@ -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
|
|