ansible-core 2.19.2rc1__py3-none-any.whl → 2.20.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/_internal/__init__.py +1 -4
- ansible/_internal/_ansiballz/_builder.py +1 -3
- ansible/_internal/_collection_proxy.py +7 -9
- ansible/_internal/_display_utils.py +145 -0
- 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/powershell/async_watchdog.ps1 +24 -4
- ansible/executor/task_executor.py +32 -22
- 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 +1 -2
- 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 +27 -24
- 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/urls.py +6 -2
- 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/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 +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 +103 -37
- 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 +2 -4
- 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/script.py +2 -1
- ansible/plugins/inventory/toml.py +3 -6
- ansible/plugins/inventory/yaml.py +1 -2
- ansible/plugins/list.py +10 -3
- ansible/plugins/loader.py +6 -6
- 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/regex.yml +18 -6
- 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 +28 -167
- 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 +27 -20
- ansible/vars/plugins.py +1 -31
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/METADATA +3 -3
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/RECORD +200 -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 +30 -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.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.2rc1.dist-info → ansible_core-2.20.0b1.dist-info}/top_level.txt +0 -0
ansible/utils/plugin_docs.py
CHANGED
|
@@ -11,13 +11,14 @@ import yaml
|
|
|
11
11
|
from ansible import constants as C
|
|
12
12
|
from ansible.release import __version__ as ansible_version
|
|
13
13
|
from ansible.errors import AnsibleError, AnsibleParserError, AnsiblePluginNotFound
|
|
14
|
-
from ansible.module_utils.
|
|
14
|
+
from ansible.module_utils._internal import _no_six
|
|
15
15
|
from ansible.module_utils.common.text.converters import to_native
|
|
16
16
|
from ansible.parsing.plugin_docs import read_docstring
|
|
17
17
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
|
18
18
|
from ansible.utils.display import Display
|
|
19
19
|
from ansible._internal._datatag import _tags
|
|
20
20
|
|
|
21
|
+
_FRAGMENTABLE = ('DOCUMENTATION', 'RETURN')
|
|
21
22
|
display = Display()
|
|
22
23
|
|
|
23
24
|
|
|
@@ -125,23 +126,30 @@ def remove_current_collection_from_versions_and_dates(fragment, collection_name,
|
|
|
125
126
|
_process_versions_and_dates(fragment, is_module, return_docs, remove)
|
|
126
127
|
|
|
127
128
|
|
|
128
|
-
|
|
129
|
+
class AnsibleFragmentError(AnsibleError):
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def add_fragments(doc, filename, fragment_loader, is_module=False, section='DOCUMENTATION'):
|
|
134
|
+
|
|
135
|
+
if section not in _FRAGMENTABLE:
|
|
136
|
+
raise AnsibleError(f"Invalid fragment section ({section}) passed to render {filename}, it can only be one of {_FRAGMENTABLE!r}")
|
|
129
137
|
|
|
130
138
|
fragments = doc.pop('extends_documentation_fragment', [])
|
|
131
139
|
|
|
132
|
-
if isinstance(fragments,
|
|
140
|
+
if isinstance(fragments, str):
|
|
133
141
|
fragments = fragments.split(',')
|
|
134
142
|
|
|
135
143
|
unknown_fragments = []
|
|
136
144
|
|
|
137
|
-
# doc_fragments are allowed to specify a fragment var other than DOCUMENTATION
|
|
145
|
+
# doc_fragments are allowed to specify a fragment var other than DOCUMENTATION or RETURN
|
|
138
146
|
# with a . separator; this is complicated by collections-hosted doc_fragments that
|
|
139
147
|
# use the same separator. Assume it's collection-hosted normally first, try to load
|
|
140
148
|
# as-specified. If failure, assume the right-most component is a var, split it off,
|
|
141
149
|
# and retry the load.
|
|
142
150
|
for fragment_slug in fragments:
|
|
143
151
|
fragment_name = fragment_slug.strip()
|
|
144
|
-
fragment_var =
|
|
152
|
+
fragment_var = section
|
|
145
153
|
|
|
146
154
|
fragment_class = fragment_loader.get(fragment_name)
|
|
147
155
|
if fragment_class is None and '.' in fragment_slug:
|
|
@@ -157,7 +165,7 @@ def add_fragments(doc, filename, fragment_loader, is_module=False):
|
|
|
157
165
|
# trust-tagged source propagates to loaded values; expressions and templates in config require trust
|
|
158
166
|
fragment_yaml = _tags.TrustedAsTemplate().tag(getattr(fragment_class, fragment_var, None))
|
|
159
167
|
if fragment_yaml is None:
|
|
160
|
-
if fragment_var
|
|
168
|
+
if fragment_var not in _FRAGMENTABLE:
|
|
161
169
|
# if it's asking for something specific that's missing, that's an error
|
|
162
170
|
unknown_fragments.append(fragment_slug)
|
|
163
171
|
continue
|
|
@@ -168,44 +176,40 @@ def add_fragments(doc, filename, fragment_loader, is_module=False):
|
|
|
168
176
|
|
|
169
177
|
real_fragment_name = getattr(fragment_class, 'ansible_name')
|
|
170
178
|
real_collection_name = '.'.join(real_fragment_name.split('.')[0:2]) if '.' in real_fragment_name else ''
|
|
171
|
-
add_collection_to_versions_and_dates(fragment, real_collection_name, is_module=is_module)
|
|
172
|
-
|
|
173
|
-
if '
|
|
174
|
-
notes
|
|
175
|
-
|
|
176
|
-
if
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
except Exception as e:
|
|
197
|
-
raise AnsibleError("%s %s (%s) of unknown type: %s" % (to_native(e), doc_key, fragment_name, filename))
|
|
198
|
-
else:
|
|
199
|
-
doc[doc_key] = fragment.pop(doc_key)
|
|
179
|
+
add_collection_to_versions_and_dates(fragment, real_collection_name, is_module=is_module, return_docs=(section == 'RETURN'))
|
|
180
|
+
|
|
181
|
+
if section == 'DOCUMENTATION':
|
|
182
|
+
# notes, seealso, options and attributes entries are specificly merged, but only occur in documentation section
|
|
183
|
+
for doc_key in ['notes', 'seealso']:
|
|
184
|
+
if doc_key in fragment:
|
|
185
|
+
entries = fragment.pop(doc_key)
|
|
186
|
+
if entries:
|
|
187
|
+
if doc_key not in doc:
|
|
188
|
+
doc[doc_key] = []
|
|
189
|
+
doc[doc_key].extend(entries)
|
|
190
|
+
|
|
191
|
+
if 'options' not in fragment and 'attributes' not in fragment:
|
|
192
|
+
raise AnsibleFragmentError("missing options or attributes in fragment (%s), possibly misformatted?: %s" % (fragment_name, filename))
|
|
193
|
+
|
|
194
|
+
# ensure options themselves are directly merged
|
|
195
|
+
for doc_key in ['options', 'attributes']:
|
|
196
|
+
if doc_key in fragment:
|
|
197
|
+
if doc_key in doc:
|
|
198
|
+
try:
|
|
199
|
+
merge_fragment(doc[doc_key], fragment.pop(doc_key))
|
|
200
|
+
except Exception as e:
|
|
201
|
+
raise AnsibleFragmentError("%s %s (%s) of unknown type: %s" % (to_native(e), doc_key, fragment_name, filename))
|
|
202
|
+
else:
|
|
203
|
+
doc[doc_key] = fragment.pop(doc_key)
|
|
200
204
|
|
|
201
205
|
# merge rest of the sections
|
|
202
206
|
try:
|
|
203
207
|
merge_fragment(doc, fragment)
|
|
204
208
|
except Exception as e:
|
|
205
|
-
raise
|
|
209
|
+
raise AnsibleFragmentError("%s (%s) of unknown type: %s" % (to_native(e), fragment_name, filename))
|
|
206
210
|
|
|
207
211
|
if unknown_fragments:
|
|
208
|
-
raise
|
|
212
|
+
raise AnsibleFragmentError('unknown doc_fragment(s) in file {0}: {1}'.format(filename, to_native(', '.join(unknown_fragments))))
|
|
209
213
|
|
|
210
214
|
|
|
211
215
|
def get_docstring(filename, fragment_loader, verbose=False, ignore_errors=False, collection_name=None, is_module=None, plugin_type=None):
|
|
@@ -230,13 +234,16 @@ def get_docstring(filename, fragment_loader, verbose=False, ignore_errors=False,
|
|
|
230
234
|
add_collection_to_versions_and_dates(data['doc'], collection_name, is_module=is_module)
|
|
231
235
|
|
|
232
236
|
# add fragments to documentation
|
|
233
|
-
add_fragments(data['doc'], filename, fragment_loader=fragment_loader, is_module=is_module)
|
|
237
|
+
add_fragments(data['doc'], filename, fragment_loader=fragment_loader, is_module=is_module, section='DOCUMENTATION')
|
|
234
238
|
|
|
235
239
|
if data.get('returndocs', False):
|
|
236
240
|
# add collection name to versions and dates
|
|
237
241
|
if collection_name is not None:
|
|
238
242
|
add_collection_to_versions_and_dates(data['returndocs'], collection_name, is_module=is_module, return_docs=True)
|
|
239
243
|
|
|
244
|
+
# add fragments to return
|
|
245
|
+
add_fragments(data['returndocs'], filename, fragment_loader=fragment_loader, is_module=is_module, section='RETURN')
|
|
246
|
+
|
|
240
247
|
return data['doc'], data['plainexamples'], data['returndocs'], data['metadata']
|
|
241
248
|
|
|
242
249
|
|
|
@@ -352,3 +359,7 @@ def get_plugin_docs(plugin, plugin_type, loader, fragment_loader, verbose):
|
|
|
352
359
|
docs[0]['plugin_name'] = context.resolved_fqcn
|
|
353
360
|
|
|
354
361
|
return docs
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def __getattr__(importable_name):
|
|
365
|
+
return _no_six.deprecate(importable_name, __name__, "string_types")
|
ansible/utils/ssh_functions.py
CHANGED
|
@@ -20,9 +20,7 @@ from __future__ import annotations
|
|
|
20
20
|
|
|
21
21
|
import subprocess
|
|
22
22
|
|
|
23
|
-
from ansible import constants as C
|
|
24
23
|
from ansible.module_utils.common.text.converters import to_bytes
|
|
25
|
-
from ansible.module_utils.compat.paramiko import _paramiko as paramiko
|
|
26
24
|
from ansible.utils.display import Display
|
|
27
25
|
|
|
28
26
|
display = Display()
|
|
@@ -50,20 +48,3 @@ def check_for_controlpersist(ssh_executable):
|
|
|
50
48
|
|
|
51
49
|
_HAS_CONTROLPERSIST[ssh_executable] = has_cp
|
|
52
50
|
return has_cp
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def set_default_transport():
|
|
56
|
-
|
|
57
|
-
# deal with 'smart' connection .. one time ..
|
|
58
|
-
if C.DEFAULT_TRANSPORT == 'smart':
|
|
59
|
-
display.deprecated(
|
|
60
|
-
msg="The `smart` option for connections is deprecated.",
|
|
61
|
-
version="2.20",
|
|
62
|
-
help_text="Set the connection plugin directly instead.",
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
# see if SSH can support ControlPersist if not use paramiko
|
|
66
|
-
if not check_for_controlpersist('ssh') and paramiko is not None:
|
|
67
|
-
C.DEFAULT_TRANSPORT = "paramiko"
|
|
68
|
-
else:
|
|
69
|
-
C.DEFAULT_TRANSPORT = "ssh"
|
ansible/utils/unsafe_proxy.py
CHANGED
|
@@ -7,17 +7,13 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
from collections.abc import Mapping, Set
|
|
9
9
|
|
|
10
|
+
from ansible.module_utils._internal import _no_six
|
|
10
11
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
|
11
12
|
from ansible.module_utils.common.collections import is_sequence
|
|
12
13
|
from ansible._internal._datatag._tags import TrustedAsTemplate
|
|
13
|
-
from ansible.module_utils.six import binary_type, text_type
|
|
14
|
-
|
|
15
|
-
import typing as t
|
|
16
14
|
|
|
17
15
|
__all__ = ['AnsibleUnsafe', 'wrap_var']
|
|
18
16
|
|
|
19
|
-
T = t.TypeVar('T')
|
|
20
|
-
|
|
21
17
|
|
|
22
18
|
class AnsibleUnsafe:
|
|
23
19
|
def __new__(cls, value):
|
|
@@ -66,9 +62,9 @@ def wrap_var(v):
|
|
|
66
62
|
v = _wrap_set(v)
|
|
67
63
|
elif is_sequence(v):
|
|
68
64
|
v = _wrap_sequence(v)
|
|
69
|
-
elif isinstance(v,
|
|
65
|
+
elif isinstance(v, bytes):
|
|
70
66
|
v = AnsibleUnsafeBytes(v)
|
|
71
|
-
elif isinstance(v,
|
|
67
|
+
elif isinstance(v, str):
|
|
72
68
|
v = AnsibleUnsafeText(v)
|
|
73
69
|
|
|
74
70
|
return v
|
|
@@ -80,3 +76,7 @@ def to_unsafe_bytes(*args, **kwargs):
|
|
|
80
76
|
|
|
81
77
|
def to_unsafe_text(*args, **kwargs):
|
|
82
78
|
return wrap_var(to_text(*args, **kwargs))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def __getattr__(importable_name):
|
|
82
|
+
return _no_six.deprecate(importable_name, __name__, "binary_type", "text_type")
|
ansible/vars/clean.py
CHANGED
|
@@ -10,7 +10,6 @@ from collections.abc import MutableMapping, MutableSequence
|
|
|
10
10
|
|
|
11
11
|
from ansible import constants as C
|
|
12
12
|
from ansible.errors import AnsibleError
|
|
13
|
-
from ansible.module_utils import six
|
|
14
13
|
from ansible.plugins.loader import connection_loader
|
|
15
14
|
from ansible.utils.display import Display
|
|
16
15
|
|
|
@@ -48,7 +47,7 @@ def module_response_deepcopy(v):
|
|
|
48
47
|
"""
|
|
49
48
|
if isinstance(v, dict):
|
|
50
49
|
ret = v.copy()
|
|
51
|
-
items =
|
|
50
|
+
items = ret.items()
|
|
52
51
|
elif isinstance(v, list):
|
|
53
52
|
ret = v[:]
|
|
54
53
|
items = enumerate(ret)
|
|
@@ -80,7 +79,7 @@ def strip_internal_keys(dirty, exceptions=None):
|
|
|
80
79
|
|
|
81
80
|
# listify to avoid updating dict while iterating over it
|
|
82
81
|
for k in list(dirty.keys()):
|
|
83
|
-
if isinstance(k,
|
|
82
|
+
if isinstance(k, str):
|
|
84
83
|
if k.startswith('_ansible_') and k not in exceptions:
|
|
85
84
|
del dirty[k]
|
|
86
85
|
continue
|
ansible/vars/manager.py
CHANGED
|
@@ -33,7 +33,6 @@ from ansible.inventory.host import Host
|
|
|
33
33
|
from ansible.inventory.helpers import sort_groups, get_group_vars
|
|
34
34
|
from ansible.inventory.manager import InventoryManager
|
|
35
35
|
from ansible.module_utils.datatag import native_type_name
|
|
36
|
-
from ansible.module_utils.six import text_type
|
|
37
36
|
from ansible.parsing.dataloader import DataLoader
|
|
38
37
|
from ansible._internal._templating._engine import TemplateEngine
|
|
39
38
|
from ansible.plugins.loader import cache_loader
|
|
@@ -50,13 +49,18 @@ if t.TYPE_CHECKING:
|
|
|
50
49
|
|
|
51
50
|
display = Display()
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
_DEPRECATE_TOP_LEVEL_FACT_TAG = _tags.Deprecated(
|
|
53
|
+
msg='INJECT_FACTS_AS_VARS default to `True` is deprecated, top-level facts will not be auto injected after the change.',
|
|
54
|
+
version='2.24',
|
|
55
|
+
deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
|
|
56
|
+
help_text='Use `ansible_facts["fact_name"]` (no `ansible_` prefix) instead.',
|
|
57
|
+
)
|
|
58
|
+
_DEPRECATE_VARS = _tags.Deprecated(
|
|
59
|
+
msg='The internal "vars" dictionary is deprecated.',
|
|
60
|
+
version='2.24',
|
|
61
|
+
deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR,
|
|
62
|
+
help_text='Use the `vars` and `varnames` lookups instead.',
|
|
63
|
+
)
|
|
60
64
|
|
|
61
65
|
|
|
62
66
|
def _deprecate_top_level_fact(value: t.Any) -> t.Any:
|
|
@@ -65,9 +69,7 @@ def _deprecate_top_level_fact(value: t.Any) -> t.Any:
|
|
|
65
69
|
The inner values are shared to aid in message de-duplication across hosts/values, and reduce intra-process memory usage.
|
|
66
70
|
Unique tag instances are required to achieve the correct de-duplication within a top-level templating operation.
|
|
67
71
|
"""
|
|
68
|
-
|
|
69
|
-
# return _DEPRECATE_TOP_LEVEL_FACT_TAG.tag(value)
|
|
70
|
-
return value
|
|
72
|
+
return _DEPRECATE_TOP_LEVEL_FACT_TAG.tag(value)
|
|
71
73
|
|
|
72
74
|
|
|
73
75
|
def preprocess_vars(a):
|
|
@@ -285,8 +287,7 @@ class VariableManager:
|
|
|
285
287
|
all_vars = _combine_and_track(all_vars, _plugins_inventory([host]), "inventory host_vars for '%s'" % host)
|
|
286
288
|
all_vars = _combine_and_track(all_vars, _plugins_play([host]), "playbook host_vars for '%s'" % host)
|
|
287
289
|
|
|
288
|
-
# finally, the facts caches for this host, if
|
|
289
|
-
# TODO: cleaning of facts should eventually become part of taskresults instead of vars
|
|
290
|
+
# finally, the facts caches for this host, if they exist
|
|
290
291
|
try:
|
|
291
292
|
try:
|
|
292
293
|
facts = self._fact_cache.get(host.name)
|
|
@@ -295,12 +296,16 @@ class VariableManager:
|
|
|
295
296
|
|
|
296
297
|
all_vars |= namespace_facts(facts)
|
|
297
298
|
|
|
299
|
+
inject, origin = C.config.get_config_value_and_origin('INJECT_FACTS_AS_VARS')
|
|
298
300
|
# push facts to main namespace
|
|
299
|
-
if
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
if inject:
|
|
302
|
+
if origin == 'default':
|
|
303
|
+
clean_top = {k: _deprecate_top_level_fact(v) for k, v in clean_facts(facts).items()}
|
|
304
|
+
else:
|
|
305
|
+
clean_top = clean_facts(facts)
|
|
306
|
+
all_vars = _combine_and_track(all_vars, clean_top, "facts")
|
|
302
307
|
else:
|
|
303
|
-
# always 'promote' ansible_local
|
|
308
|
+
# always 'promote' ansible_local, even if empty
|
|
304
309
|
all_vars = _combine_and_track(all_vars, {'ansible_local': facts.get('ansible_local', {})}, "facts")
|
|
305
310
|
except KeyError:
|
|
306
311
|
pass
|
|
@@ -419,8 +424,10 @@ class VariableManager:
|
|
|
419
424
|
|
|
420
425
|
# 'vars' magic var
|
|
421
426
|
if task or play:
|
|
422
|
-
|
|
423
|
-
|
|
427
|
+
all_vars['vars'] = _DEPRECATE_VARS.tag({})
|
|
428
|
+
for k, v in all_vars.items():
|
|
429
|
+
# has to be copy, otherwise recursive ref
|
|
430
|
+
all_vars['vars'][k] = _DEPRECATE_VARS.tag(v)
|
|
424
431
|
|
|
425
432
|
display.debug("done with get_vars()")
|
|
426
433
|
return all_vars
|
|
@@ -467,7 +474,7 @@ class VariableManager:
|
|
|
467
474
|
if task._role:
|
|
468
475
|
variables['role_name'] = task._role.get_name(include_role_fqcn=False)
|
|
469
476
|
variables['role_path'] = task._role._role_path
|
|
470
|
-
variables['role_uuid'] =
|
|
477
|
+
variables['role_uuid'] = str(task._role._uuid)
|
|
471
478
|
variables['ansible_collection_name'] = task._role._role_collection
|
|
472
479
|
variables['ansible_role_name'] = task._role.get_name()
|
|
473
480
|
|
ansible/vars/plugins.py
CHANGED
|
@@ -8,8 +8,6 @@ import os
|
|
|
8
8
|
from functools import lru_cache
|
|
9
9
|
|
|
10
10
|
from ansible import constants as C
|
|
11
|
-
from ansible.errors import AnsibleError
|
|
12
|
-
from ansible.inventory.group import InventoryObjectType
|
|
13
11
|
from ansible.plugins.loader import vars_loader
|
|
14
12
|
from ansible.utils.display import Display
|
|
15
13
|
from ansible.utils.vars import combine_vars
|
|
@@ -26,34 +24,6 @@ def _prime_vars_loader():
|
|
|
26
24
|
vars_loader.get(plugin_name)
|
|
27
25
|
|
|
28
26
|
|
|
29
|
-
def get_plugin_vars(loader, plugin, path, entities):
|
|
30
|
-
|
|
31
|
-
data = {}
|
|
32
|
-
try:
|
|
33
|
-
data = plugin.get_vars(loader, path, entities)
|
|
34
|
-
except AttributeError:
|
|
35
|
-
if hasattr(plugin, 'get_host_vars') or hasattr(plugin, 'get_group_vars'):
|
|
36
|
-
display.deprecated(
|
|
37
|
-
msg=f"The vars plugin {plugin.ansible_name} from {plugin._original_path} is relying "
|
|
38
|
-
"on the deprecated entrypoints `get_host_vars` and `get_group_vars`.",
|
|
39
|
-
version="2.20",
|
|
40
|
-
help_text="This plugin should be updated to inherit from `BaseVarsPlugin` and define "
|
|
41
|
-
"a `get_vars` method as the main entrypoint instead.",
|
|
42
|
-
)
|
|
43
|
-
try:
|
|
44
|
-
for entity in entities:
|
|
45
|
-
if entity.base_type is InventoryObjectType.HOST:
|
|
46
|
-
data |= plugin.get_host_vars(entity.name)
|
|
47
|
-
else:
|
|
48
|
-
data |= plugin.get_group_vars(entity.name)
|
|
49
|
-
except AttributeError:
|
|
50
|
-
if hasattr(plugin, 'run'):
|
|
51
|
-
raise AnsibleError("Cannot use v1 type vars plugin %s from %s" % (plugin._load_name, plugin._original_path))
|
|
52
|
-
else:
|
|
53
|
-
raise AnsibleError("Invalid vars plugin %s from %s" % (plugin._load_name, plugin._original_path))
|
|
54
|
-
return data
|
|
55
|
-
|
|
56
|
-
|
|
57
27
|
# optimized for stateless plugins; non-stateless plugin instances will fall out quickly
|
|
58
28
|
@lru_cache(maxsize=10)
|
|
59
29
|
def _plugin_should_run(plugin, stage):
|
|
@@ -99,7 +69,7 @@ def get_vars_from_path(loader, path, entities, stage):
|
|
|
99
69
|
if not _plugin_should_run(plugin, stage):
|
|
100
70
|
continue
|
|
101
71
|
|
|
102
|
-
if (new_vars :=
|
|
72
|
+
if (new_vars := plugin.get_vars(loader, path, entities)) != {}:
|
|
103
73
|
data = combine_vars(data, new_vars)
|
|
104
74
|
|
|
105
75
|
return data
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ansible-core
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.20.0b1
|
|
4
4
|
Summary: Radically simple IT automation
|
|
5
5
|
Author: Ansible Project
|
|
6
6
|
Project-URL: Homepage, https://ansible.com/
|
|
@@ -18,14 +18,14 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (G
|
|
|
18
18
|
Classifier: Natural Language :: English
|
|
19
19
|
Classifier: Operating System :: POSIX
|
|
20
20
|
Classifier: Programming Language :: Python :: 3
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
24
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
25
|
Classifier: Topic :: System :: Installation/Setup
|
|
26
26
|
Classifier: Topic :: System :: Systems Administration
|
|
27
27
|
Classifier: Topic :: Utilities
|
|
28
|
-
Requires-Python: >=3.
|
|
28
|
+
Requires-Python: >=3.12
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: COPYING
|
|
31
31
|
License-File: licenses/Apache-License.txt
|