ansible-core 2.19.0b2__py3-none-any.whl → 2.19.0b4__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/__init__.py +1 -1
- ansible/_internal/_ansiballz.py +1 -4
- ansible/_internal/_json/__init__.py +1 -1
- ansible/_internal/_templating/_datatag.py +3 -4
- ansible/_internal/_templating/_engine.py +6 -1
- ansible/_internal/_templating/_jinja_plugins.py +2 -6
- ansible/_internal/_testing.py +26 -0
- ansible/cli/__init__.py +3 -2
- ansible/cli/arguments/option_helpers.py +10 -3
- ansible/cli/doc.py +0 -1
- ansible/config/base.yml +5 -23
- ansible/config/manager.py +144 -103
- ansible/constants.py +1 -63
- ansible/errors/__init__.py +6 -2
- ansible/executor/module_common.py +11 -7
- ansible/executor/task_executor.py +6 -8
- ansible/galaxy/api.py +1 -1
- ansible/galaxy/collection/__init__.py +3 -3
- ansible/inventory/manager.py +1 -0
- ansible/module_utils/_internal/_ansiballz.py +4 -30
- ansible/module_utils/_internal/_datatag/_tags.py +3 -25
- ansible/module_utils/_internal/_deprecator.py +134 -0
- ansible/module_utils/_internal/_plugin_info.py +25 -0
- ansible/module_utils/_internal/_validation.py +14 -0
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +64 -17
- ansible/module_utils/common/arg_spec.py +8 -3
- ansible/module_utils/common/messages.py +40 -23
- ansible/module_utils/common/process.py +0 -1
- ansible/module_utils/common/respawn.py +0 -7
- ansible/module_utils/common/warnings.py +13 -13
- ansible/module_utils/datatag.py +13 -13
- ansible/module_utils/facts/virtual/linux.py +1 -1
- ansible/module_utils/parsing/convert_bool.py +6 -0
- ansible/modules/assemble.py +4 -4
- ansible/modules/async_status.py +1 -1
- ansible/modules/cron.py +3 -5
- ansible/modules/dnf5.py +2 -1
- ansible/modules/get_url.py +1 -1
- ansible/modules/git.py +1 -6
- ansible/modules/pip.py +2 -4
- ansible/modules/sysvinit.py +3 -3
- ansible/playbook/task.py +0 -2
- ansible/plugins/__init__.py +18 -8
- ansible/plugins/action/__init__.py +7 -15
- ansible/plugins/action/gather_facts.py +2 -4
- ansible/plugins/action/template.py +3 -0
- ansible/plugins/callback/oneline.py +7 -1
- ansible/plugins/callback/tree.py +7 -1
- ansible/plugins/connection/local.py +1 -1
- ansible/plugins/connection/paramiko_ssh.py +9 -2
- ansible/plugins/doc_fragments/action_core.py +1 -1
- ansible/plugins/filter/core.py +4 -1
- ansible/plugins/inventory/__init__.py +2 -2
- ansible/plugins/loader.py +197 -132
- ansible/plugins/lookup/url.py +2 -2
- ansible/plugins/strategy/__init__.py +6 -6
- ansible/release.py +1 -1
- ansible/template/__init__.py +1 -1
- ansible/utils/collection_loader/__init__.py +2 -0
- ansible/utils/collection_loader/_collection_meta.py +5 -3
- ansible/utils/display.py +137 -71
- ansible/utils/plugin_docs.py +2 -1
- ansible/utils/py3compat.py +1 -7
- ansible/utils/ssh_functions.py +4 -1
- ansible/vars/manager.py +18 -10
- ansible/vars/plugins.py +4 -4
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/METADATA +3 -2
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/RECORD +82 -79
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/WHEEL +1 -1
- ansible_test/_internal/commands/sanity/pylint.py +1 -0
- ansible_test/_internal/docker_util.py +4 -3
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +486 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_comment.py +137 -0
- ansible/module_utils/_internal/_dataclass_annotation_patch.py +0 -64
- ansible/module_utils/_internal/_plugin_exec_context.py +0 -49
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +0 -399
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses}/COPYING +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/Apache-License.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/MIT-license.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/PSF-license.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info/licenses/licenses}/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b2.dist-info → ansible_core-2.19.0b4.dist-info}/top_level.txt +0 -0
@@ -4,15 +4,12 @@
|
|
4
4
|
|
5
5
|
from __future__ import annotations as _annotations
|
6
6
|
|
7
|
-
import datetime as _datetime
|
8
7
|
import typing as _t
|
9
8
|
|
10
|
-
from ansible.module_utils._internal import _traceback,
|
9
|
+
from ansible.module_utils._internal import _traceback, _deprecator
|
11
10
|
from ansible.module_utils.common import messages as _messages
|
12
11
|
from ansible.module_utils import _internal
|
13
12
|
|
14
|
-
_UNSET = _t.cast(_t.Any, object())
|
15
|
-
|
16
13
|
|
17
14
|
def warn(warning: str) -> None:
|
18
15
|
"""Record a warning to be returned with the module result."""
|
@@ -28,22 +25,23 @@ def warn(warning: str) -> None:
|
|
28
25
|
def deprecate(
|
29
26
|
msg: str,
|
30
27
|
version: str | None = None,
|
31
|
-
date: str |
|
32
|
-
collection_name: str | None =
|
28
|
+
date: str | None = None,
|
29
|
+
collection_name: str | None = None,
|
33
30
|
*,
|
31
|
+
deprecator: _messages.PluginInfo | None = None,
|
34
32
|
help_text: str | None = None,
|
35
33
|
obj: object | None = None,
|
36
34
|
) -> None:
|
37
35
|
"""
|
38
|
-
Record a deprecation warning
|
36
|
+
Record a deprecation warning.
|
39
37
|
The `obj` argument is only useful in a controller context; it is ignored for target-side callers.
|
38
|
+
Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
|
39
|
+
Specify `version` or `date`, but not both.
|
40
|
+
If `date` is a string, it must be in the form `YYYY-MM-DD`.
|
40
41
|
"""
|
41
|
-
|
42
|
-
date = str(date)
|
42
|
+
_skip_stackwalk = True
|
43
43
|
|
44
|
-
|
45
|
-
# if collection_name is not _UNSET:
|
46
|
-
# deprecate('The `collection_name` argument to `deprecate` is deprecated.', version='2.27')
|
44
|
+
deprecator = _deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name)
|
47
45
|
|
48
46
|
if _internal.is_controller:
|
49
47
|
_display = _internal.import_controller_module('ansible.utils.display').Display()
|
@@ -53,6 +51,8 @@ def deprecate(
|
|
53
51
|
date=date,
|
54
52
|
help_text=help_text,
|
55
53
|
obj=obj,
|
54
|
+
# skip passing collection_name; get_best_deprecator already accounted for it when present
|
55
|
+
deprecator=deprecator,
|
56
56
|
)
|
57
57
|
|
58
58
|
return
|
@@ -64,7 +64,7 @@ def deprecate(
|
|
64
64
|
formatted_traceback=_traceback.maybe_capture_traceback(_traceback.TracebackEvent.DEPRECATED),
|
65
65
|
version=version,
|
66
66
|
date=date,
|
67
|
-
|
67
|
+
deprecator=deprecator,
|
68
68
|
)] = None
|
69
69
|
|
70
70
|
|
ansible/module_utils/datatag.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
"""Public API for data tagging."""
|
2
2
|
from __future__ import annotations as _annotations
|
3
3
|
|
4
|
-
import datetime as _datetime
|
5
4
|
import typing as _t
|
6
5
|
|
7
|
-
from ._internal import
|
6
|
+
from ._internal import _datatag, _deprecator
|
8
7
|
from ._internal._datatag import _tags
|
8
|
+
from .common import messages as _messages
|
9
9
|
|
10
10
|
_T = _t.TypeVar('_T')
|
11
11
|
|
@@ -14,28 +14,28 @@ def deprecate_value(
|
|
14
14
|
value: _T,
|
15
15
|
msg: str,
|
16
16
|
*,
|
17
|
+
version: str | None = None,
|
18
|
+
date: str | None = None,
|
19
|
+
collection_name: str | None = None,
|
20
|
+
deprecator: _messages.PluginInfo | None = None,
|
17
21
|
help_text: str | None = None,
|
18
|
-
removal_date: str | _datetime.date | None = None,
|
19
|
-
removal_version: str | None = None,
|
20
22
|
) -> _T:
|
21
23
|
"""
|
22
24
|
Return `value` tagged with the given deprecation details.
|
23
25
|
The types `None` and `bool` cannot be deprecated and are returned unmodified.
|
24
26
|
Raises a `TypeError` if `value` is not a supported type.
|
25
|
-
|
26
|
-
|
27
|
+
Most callers do not need to provide `collection_name` or `deprecator` -- but provide only one if needed.
|
28
|
+
Specify `version` or `date`, but not both.
|
29
|
+
If `date` is provided, it should be in the form `YYYY-MM-DD`.
|
27
30
|
"""
|
28
|
-
|
29
|
-
# The `fromisoformat` method accepts other ISO 8601 formats than `YYYY-MM-DD` starting with Python 3.11.
|
30
|
-
# That should be considered undocumented behavior of `deprecate_value` rather than an intentional feature.
|
31
|
-
removal_date = _datetime.date.fromisoformat(removal_date)
|
31
|
+
_skip_stackwalk = True
|
32
32
|
|
33
33
|
deprecated = _tags.Deprecated(
|
34
34
|
msg=msg,
|
35
35
|
help_text=help_text,
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
date=date,
|
37
|
+
version=version,
|
38
|
+
deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
|
39
39
|
)
|
40
40
|
|
41
41
|
return deprecated.tag(value)
|
@@ -151,7 +151,7 @@ class LinuxVirtual(Virtual):
|
|
151
151
|
sys_vendor = get_file_content('/sys/devices/virtual/dmi/id/sys_vendor')
|
152
152
|
product_family = get_file_content('/sys/devices/virtual/dmi/id/product_family')
|
153
153
|
|
154
|
-
if product_name in ('KVM', 'KVM Server', 'Bochs', 'AHV'):
|
154
|
+
if product_name in ('KVM', 'KVM Server', 'Bochs', 'AHV', 'CloudStack KVM Hypervisor'):
|
155
155
|
guest_tech.add('kvm')
|
156
156
|
if not found_virt:
|
157
157
|
virtual_facts['virtualization_type'] = 'kvm'
|
@@ -3,6 +3,8 @@
|
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
+
import collections.abc as c
|
7
|
+
|
6
8
|
from ansible.module_utils.six import binary_type, text_type
|
7
9
|
from ansible.module_utils.common.text.converters import to_text
|
8
10
|
|
@@ -17,9 +19,13 @@ def boolean(value, strict=True):
|
|
17
19
|
return value
|
18
20
|
|
19
21
|
normalized_value = value
|
22
|
+
|
20
23
|
if isinstance(value, (text_type, binary_type)):
|
21
24
|
normalized_value = to_text(value, errors='surrogate_or_strict').lower().strip()
|
22
25
|
|
26
|
+
if not isinstance(value, c.Hashable):
|
27
|
+
normalized_value = None # prevent unhashable types from bombing, but keep the rest of the existing fallback/error behavior
|
28
|
+
|
23
29
|
if normalized_value in BOOLEANS_TRUE:
|
24
30
|
return True
|
25
31
|
elif normalized_value in BOOLEANS_FALSE or not strict:
|
ansible/modules/assemble.py
CHANGED
@@ -181,7 +181,7 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno
|
|
181
181
|
return temp_path
|
182
182
|
|
183
183
|
|
184
|
-
def cleanup(path, result=None):
|
184
|
+
def cleanup(module, path, result=None):
|
185
185
|
# cleanup just in case
|
186
186
|
if os.path.exists(path):
|
187
187
|
try:
|
@@ -189,7 +189,7 @@ def cleanup(path, result=None):
|
|
189
189
|
except (IOError, OSError) as e:
|
190
190
|
# don't error on possible race conditions, but keep warning
|
191
191
|
if result is not None:
|
192
|
-
|
192
|
+
module.warn('Unable to remove temp file (%s): %s' % (path, to_native(e)))
|
193
193
|
|
194
194
|
|
195
195
|
def main():
|
@@ -261,7 +261,7 @@ def main():
|
|
261
261
|
(rc, out, err) = module.run_command(validate % path)
|
262
262
|
result['validation'] = dict(rc=rc, stdout=out, stderr=err)
|
263
263
|
if rc != 0:
|
264
|
-
cleanup(path)
|
264
|
+
cleanup(module, path)
|
265
265
|
module.fail_json(msg="failed to validate: rc:%s error:%s" % (rc, err))
|
266
266
|
if backup and dest_hash is not None:
|
267
267
|
result['backup_file'] = module.backup_local(dest)
|
@@ -269,7 +269,7 @@ def main():
|
|
269
269
|
module.atomic_move(path, dest, unsafe_writes=module.params['unsafe_writes'])
|
270
270
|
changed = True
|
271
271
|
|
272
|
-
cleanup(path, result)
|
272
|
+
cleanup(module, path, result)
|
273
273
|
|
274
274
|
# handle file permissions
|
275
275
|
file_args = module.load_file_common_arguments(module.params)
|
ansible/modules/async_status.py
CHANGED
ansible/modules/cron.py
CHANGED
@@ -618,7 +618,6 @@ def main():
|
|
618
618
|
|
619
619
|
changed = False
|
620
620
|
res_args = dict()
|
621
|
-
warnings = list()
|
622
621
|
|
623
622
|
if cron_file:
|
624
623
|
|
@@ -627,8 +626,8 @@ def main():
|
|
627
626
|
|
628
627
|
cron_file_basename = os.path.basename(cron_file)
|
629
628
|
if not re.search(r'^[A-Z0-9_-]+$', cron_file_basename, re.I):
|
630
|
-
|
631
|
-
|
629
|
+
module.warn('Filename portion of cron_file ("%s") should consist' % cron_file_basename +
|
630
|
+
' solely of upper- and lower-case letters, digits, underscores, and hyphens')
|
632
631
|
|
633
632
|
# Ensure all files generated are only writable by the owning user. Primarily relevant for the cron_file option.
|
634
633
|
os.umask(int('022', 8))
|
@@ -693,7 +692,7 @@ def main():
|
|
693
692
|
if do_install:
|
694
693
|
for char in ['\r', '\n']:
|
695
694
|
if char in job.strip('\r\n'):
|
696
|
-
|
695
|
+
module.warn('Job should not contain line breaks')
|
697
696
|
break
|
698
697
|
|
699
698
|
job = crontab.get_cron_job(minute, hour, day, month, weekday, job, special_time, disabled)
|
@@ -734,7 +733,6 @@ def main():
|
|
734
733
|
res_args = dict(
|
735
734
|
jobs=crontab.get_jobnames(),
|
736
735
|
envs=crontab.get_envnames(),
|
737
|
-
warnings=warnings,
|
738
736
|
changed=changed
|
739
737
|
)
|
740
738
|
|
ansible/modules/dnf5.py
CHANGED
@@ -722,6 +722,7 @@ class Dnf5Module(YumDnf):
|
|
722
722
|
if self.security:
|
723
723
|
types.append("security")
|
724
724
|
advisory_query.filter_type(types)
|
725
|
+
conf.skip_unavailable = True # ignore packages that are of a different type, for backwards compat
|
725
726
|
settings.set_advisory_filter(advisory_query)
|
726
727
|
|
727
728
|
goal = libdnf5.base.Goal(base)
|
@@ -797,7 +798,7 @@ class Dnf5Module(YumDnf):
|
|
797
798
|
if self.module.check_mode:
|
798
799
|
if results:
|
799
800
|
msg = "Check mode: No changes made, but would have if not in check mode"
|
800
|
-
|
801
|
+
elif changed:
|
801
802
|
transaction.download()
|
802
803
|
if not self.download_only:
|
803
804
|
transaction.set_description("ansible dnf5 module")
|
ansible/modules/get_url.py
CHANGED
@@ -87,7 +87,7 @@ options:
|
|
87
87
|
- 'If a checksum is passed to this parameter, the digest of the
|
88
88
|
destination file will be calculated after it is downloaded to ensure
|
89
89
|
its integrity and verify that the transfer completed successfully.
|
90
|
-
Format: <algorithm>:<checksum|url>, for example C(checksum="sha256:D98291AC[...]B6DC7B97",
|
90
|
+
Format: <algorithm>:<checksum|url>, for example C(checksum="sha256:D98291AC[...]B6DC7B97"),
|
91
91
|
C(checksum="sha256:http://example.com/path/sha256sum.txt").'
|
92
92
|
- If you worry about portability, only the sha1 algorithm is available
|
93
93
|
on all platforms and python versions.
|
ansible/modules/git.py
CHANGED
@@ -317,11 +317,6 @@ remote_url_changed:
|
|
317
317
|
returned: success
|
318
318
|
type: bool
|
319
319
|
sample: True
|
320
|
-
warnings:
|
321
|
-
description: List of warnings if requested features were not available due to a too old git version.
|
322
|
-
returned: error
|
323
|
-
type: str
|
324
|
-
sample: git version is too old to fully support the depth argument. Falling back to full checkouts.
|
325
320
|
git_dir_now:
|
326
321
|
description: Contains the new path of .git directory if it is changed.
|
327
322
|
returned: success
|
@@ -1240,7 +1235,7 @@ def main():
|
|
1240
1235
|
archive_prefix = module.params['archive_prefix']
|
1241
1236
|
separate_git_dir = module.params['separate_git_dir']
|
1242
1237
|
|
1243
|
-
result = dict(changed=False
|
1238
|
+
result = dict(changed=False)
|
1244
1239
|
|
1245
1240
|
if module.params['accept_hostkey']:
|
1246
1241
|
if ssh_opts is not None:
|
ansible/modules/pip.py
CHANGED
@@ -814,10 +814,8 @@ def main():
|
|
814
814
|
elif requirements:
|
815
815
|
cmd.extend(['-r', requirements])
|
816
816
|
else:
|
817
|
-
module.
|
818
|
-
|
819
|
-
warnings=["No valid name or requirements file found."],
|
820
|
-
)
|
817
|
+
module.warn("No valid name or requirements file found.")
|
818
|
+
module.exit_json(changed=False)
|
821
819
|
|
822
820
|
if module.check_mode:
|
823
821
|
if extra_args or requirements or state == 'latest' or not name:
|
ansible/modules/sysvinit.py
CHANGED
@@ -88,9 +88,9 @@ EXAMPLES = """
|
|
88
88
|
|
89
89
|
- name: Sleep for 5 seconds between stop and start command of badly behaving service
|
90
90
|
ansible.builtin.sysvinit:
|
91
|
-
|
92
|
-
|
93
|
-
|
91
|
+
name: apache2
|
92
|
+
state: restarted
|
93
|
+
sleep: 5
|
94
94
|
|
95
95
|
- name: Make sure apache2 is started on runlevels 3 and 5
|
96
96
|
ansible.builtin.sysvinit:
|
ansible/playbook/task.py
CHANGED
@@ -227,8 +227,6 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl
|
|
227
227
|
raise AnsibleError("you must specify a value when using %s" % k, obj=ds)
|
228
228
|
new_ds['loop_with'] = loop_name
|
229
229
|
new_ds['loop'] = v
|
230
|
-
# display.deprecated("with_ type loops are being phased out, use the 'loop' keyword instead",
|
231
|
-
# version="2.10", collection_name='ansible.builtin')
|
232
230
|
|
233
231
|
def preprocess_data(self, ds):
|
234
232
|
"""
|
ansible/plugins/__init__.py
CHANGED
@@ -20,24 +20,26 @@
|
|
20
20
|
from __future__ import annotations
|
21
21
|
|
22
22
|
import abc
|
23
|
+
import functools
|
23
24
|
import types
|
24
25
|
import typing as t
|
25
26
|
|
26
27
|
from ansible import constants as C
|
27
28
|
from ansible.errors import AnsibleError
|
28
29
|
from ansible.utils.display import Display
|
30
|
+
from ansible.utils import display as _display
|
29
31
|
|
30
|
-
from ansible.module_utils._internal import
|
32
|
+
from ansible.module_utils._internal import _plugin_info
|
31
33
|
|
32
34
|
display = Display()
|
33
35
|
|
34
36
|
if t.TYPE_CHECKING:
|
35
|
-
from .
|
37
|
+
from . import loader as _t_loader
|
36
38
|
|
37
39
|
# Global so that all instances of a PluginLoader will share the caches
|
38
40
|
MODULE_CACHE = {} # type: dict[str, dict[str, types.ModuleType]]
|
39
|
-
PATH_CACHE = {} # type: dict[str, list[PluginPathContext] | None]
|
40
|
-
PLUGIN_PATH_CACHE = {} # type: dict[str, dict[str, dict[str, PluginPathContext]]]
|
41
|
+
PATH_CACHE = {} # type: dict[str, list[_t_loader.PluginPathContext] | None]
|
42
|
+
PLUGIN_PATH_CACHE = {} # type: dict[str, dict[str, dict[str, _t_loader.PluginPathContext]]]
|
41
43
|
|
42
44
|
|
43
45
|
def get_plugin_class(obj):
|
@@ -50,10 +52,10 @@ def get_plugin_class(obj):
|
|
50
52
|
class _ConfigurablePlugin(t.Protocol):
|
51
53
|
"""Protocol to provide type-safe access to config for plugin-related mixins."""
|
52
54
|
|
53
|
-
def get_option(self, option: str, hostvars: dict[str, object] | None = None) ->
|
55
|
+
def get_option(self, option: str, hostvars: dict[str, object] | None = None) -> t.Any: ...
|
54
56
|
|
55
57
|
|
56
|
-
class _AnsiblePluginInfoMixin(
|
58
|
+
class _AnsiblePluginInfoMixin(_plugin_info.HasPluginInfo):
|
57
59
|
"""Mixin to provide type annotations and default values for existing PluginLoader-set load-time attrs."""
|
58
60
|
_original_path: str | None = None
|
59
61
|
_load_name: str | None = None
|
@@ -102,6 +104,14 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|
102
104
|
raise KeyError(str(e))
|
103
105
|
return option_value, origin
|
104
106
|
|
107
|
+
@functools.cached_property
|
108
|
+
def __plugin_info(self):
|
109
|
+
"""
|
110
|
+
Internal cached property to retrieve `PluginInfo` for this plugin instance.
|
111
|
+
Only for use by the `AnsiblePlugin` base class.
|
112
|
+
"""
|
113
|
+
return _plugin_info.get_plugin_info(self)
|
114
|
+
|
105
115
|
def get_option(self, option, hostvars=None):
|
106
116
|
|
107
117
|
if option not in self._options:
|
@@ -117,7 +127,7 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|
117
127
|
|
118
128
|
def set_option(self, option, value):
|
119
129
|
self._options[option] = C.config.get_config_value(option, plugin_type=self.plugin_type, plugin_name=self._load_name, direct={option: value})
|
120
|
-
|
130
|
+
_display._report_config_warnings(self.__plugin_info)
|
121
131
|
|
122
132
|
def set_options(self, task_keys=None, var_options=None, direct=None):
|
123
133
|
"""
|
@@ -134,7 +144,7 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|
134
144
|
if self.allow_extras and var_options and '_extras' in var_options:
|
135
145
|
# these are largely unvalidated passthroughs, either plugin or underlying API will validate
|
136
146
|
self._options['_extras'] = var_options['_extras']
|
137
|
-
|
147
|
+
_display._report_config_warnings(self.__plugin_info)
|
138
148
|
|
139
149
|
def has_option(self, option):
|
140
150
|
if not self._options:
|
@@ -318,13 +318,6 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
318
318
|
final_environment: dict[str, t.Any] = {}
|
319
319
|
self._compute_environment_string(final_environment)
|
320
320
|
|
321
|
-
# `modify_module` adapts PluginInfo to allow target-side use of `PluginExecContext` since modules aren't plugins
|
322
|
-
plugin = PluginInfo(
|
323
|
-
requested_name=module_name,
|
324
|
-
resolved_name=result.resolved_fqcn,
|
325
|
-
type='module',
|
326
|
-
)
|
327
|
-
|
328
321
|
# modify_module will exit early if interpreter discovery is required; re-run after if necessary
|
329
322
|
for _dummy in (1, 2):
|
330
323
|
try:
|
@@ -338,7 +331,6 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
338
331
|
async_timeout=self._task.async_val,
|
339
332
|
environment=final_environment,
|
340
333
|
remote_is_local=bool(getattr(self._connection, '_remote_is_local', False)),
|
341
|
-
plugin=plugin,
|
342
334
|
become_plugin=self._connection.become,
|
343
335
|
)
|
344
336
|
|
@@ -649,12 +641,12 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
649
641
|
# done. Make the files +x if we're asked to, and return.
|
650
642
|
if not self._is_become_unprivileged():
|
651
643
|
if execute:
|
652
|
-
# Can't depend on the file being transferred with
|
644
|
+
# Can't depend on the file being transferred with required permissions.
|
653
645
|
# Only need user perms because no become was used here
|
654
|
-
res = self._remote_chmod(remote_paths, 'u+
|
646
|
+
res = self._remote_chmod(remote_paths, 'u+rwx')
|
655
647
|
if res['rc'] != 0:
|
656
648
|
raise AnsibleError(
|
657
|
-
'Failed to set
|
649
|
+
'Failed to set permissions on remote files '
|
658
650
|
'(rc: {0}, err: {1})'.format(
|
659
651
|
res['rc'],
|
660
652
|
to_native(res['stderr'])))
|
@@ -695,10 +687,10 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
695
687
|
return remote_paths
|
696
688
|
|
697
689
|
# Step 3b: Set execute if we need to. We do this before anything else
|
698
|
-
# because some of the methods below might work but not let us set
|
699
|
-
# as part of them.
|
690
|
+
# because some of the methods below might work but not let us set
|
691
|
+
# permissions as part of them.
|
700
692
|
if execute:
|
701
|
-
res = self._remote_chmod(remote_paths, 'u+
|
693
|
+
res = self._remote_chmod(remote_paths, 'u+rwx')
|
702
694
|
if res['rc'] != 0:
|
703
695
|
raise AnsibleError(
|
704
696
|
'Failed to set file mode or acl on remote temporary files '
|
@@ -1010,7 +1002,7 @@ class ActionBase(ABC, _AnsiblePluginInfoMixin):
|
|
1010
1002
|
# tells the module to ignore options that are not in its argspec.
|
1011
1003
|
module_args['_ansible_ignore_unknown_opts'] = ignore_unknown_opts
|
1012
1004
|
|
1013
|
-
# allow user to insert string to add context to remote
|
1005
|
+
# allow user to insert string to add context to remote logging
|
1014
1006
|
module_args['_ansible_target_log_info'] = C.config.get_config_value('TARGET_LOG_INFO', variables=task_vars)
|
1015
1007
|
|
1016
1008
|
module_args['_ansible_tracebacks_for'] = _traceback.traceback_for()
|
@@ -28,10 +28,8 @@ class ActionModule(ActionBase):
|
|
28
28
|
|
29
29
|
# TODO: remove in favor of controller side argspec detecting valid arguments
|
30
30
|
# network facts modules must support gather_subset
|
31
|
-
|
32
|
-
|
33
|
-
except AttributeError:
|
34
|
-
name = self._connection._load_name.split('.')[-1]
|
31
|
+
name = self._connection.ansible_name.removeprefix('ansible.netcommon.')
|
32
|
+
|
35
33
|
if name not in ('network_cli', 'httpapi', 'netconf'):
|
36
34
|
subset = mod_args.pop('gather_subset', None)
|
37
35
|
if subset not in ('all', ['all'], None):
|
@@ -132,6 +132,9 @@ class ActionModule(ActionBase):
|
|
132
132
|
data_templar = self._templar.copy_with_new_env(searchpath=searchpath, available_variables=temp_vars)
|
133
133
|
resultant = data_templar.template(template_data, escape_backslashes=False, overrides=overrides)
|
134
134
|
|
135
|
+
if resultant is None:
|
136
|
+
resultant = ''
|
137
|
+
|
135
138
|
new_task = self._task.copy()
|
136
139
|
# mode is either the mode from task.args or the mode of the source file if the task.args
|
137
140
|
# mode == 'preserve'
|
@@ -17,6 +17,7 @@ from ansible import constants as C
|
|
17
17
|
from ansible.plugins.callback import CallbackBase
|
18
18
|
from ansible.template import Templar
|
19
19
|
from ansible.executor.task_result import CallbackTaskResult
|
20
|
+
from ansible.module_utils._internal import _deprecator
|
20
21
|
|
21
22
|
|
22
23
|
class CallbackModule(CallbackBase):
|
@@ -32,7 +33,12 @@ class CallbackModule(CallbackBase):
|
|
32
33
|
|
33
34
|
def __init__(self, *args, **kwargs):
|
34
35
|
super().__init__(*args, **kwargs)
|
35
|
-
|
36
|
+
|
37
|
+
self._display.deprecated( # pylint: disable=ansible-deprecated-unnecessary-collection-name
|
38
|
+
msg='The oneline callback plugin is deprecated.',
|
39
|
+
version='2.23',
|
40
|
+
deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR, # entire plugin being removed; this improves the messaging
|
41
|
+
)
|
36
42
|
|
37
43
|
def _command_generic_msg(self, hostname, result, caption):
|
38
44
|
stdout = result.get('stdout', '').replace('\n', '\\n').replace('\r', '\\r')
|
ansible/plugins/callback/tree.py
CHANGED
@@ -34,6 +34,7 @@ from ansible.executor.task_result import CallbackTaskResult
|
|
34
34
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
35
35
|
from ansible.plugins.callback import CallbackBase
|
36
36
|
from ansible.utils.path import makedirs_safe, unfrackpath
|
37
|
+
from ansible.module_utils._internal import _deprecator
|
37
38
|
|
38
39
|
|
39
40
|
class CallbackModule(CallbackBase):
|
@@ -48,7 +49,12 @@ class CallbackModule(CallbackBase):
|
|
48
49
|
|
49
50
|
def __init__(self, *args, **kwargs):
|
50
51
|
super().__init__(*args, **kwargs)
|
51
|
-
|
52
|
+
|
53
|
+
self._display.deprecated( # pylint: disable=ansible-deprecated-unnecessary-collection-name
|
54
|
+
msg='The tree callback plugin is deprecated.',
|
55
|
+
version='2.23',
|
56
|
+
deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR, # entire plugin being removed; this improves the messaging
|
57
|
+
)
|
52
58
|
|
53
59
|
def set_options(self, task_keys=None, var_options=None, direct=None):
|
54
60
|
""" override to set self.tree """
|
@@ -252,7 +252,7 @@ class Connection(ConnectionBase):
|
|
252
252
|
def _become_success_timeout(self) -> int:
|
253
253
|
"""Timeout value for become success in seconds."""
|
254
254
|
if (timeout := self.get_option('become_success_timeout')) < 1:
|
255
|
-
timeout = C.config.
|
255
|
+
timeout = C.config.get_config_default('become_success_timeout', plugin_type='connection', plugin_name='local')
|
256
256
|
|
257
257
|
return timeout
|
258
258
|
|
@@ -248,11 +248,13 @@ from ansible.errors import (
|
|
248
248
|
AnsibleError,
|
249
249
|
AnsibleFileNotFound,
|
250
250
|
)
|
251
|
+
|
252
|
+
from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text
|
251
253
|
from ansible.module_utils.compat.paramiko import _PARAMIKO_IMPORT_ERR as PARAMIKO_IMPORT_ERR, _paramiko as paramiko
|
252
254
|
from ansible.plugins.connection import ConnectionBase
|
253
255
|
from ansible.utils.display import Display
|
254
256
|
from ansible.utils.path import makedirs_safe
|
255
|
-
from ansible.module_utils.
|
257
|
+
from ansible.module_utils._internal import _deprecator
|
256
258
|
|
257
259
|
display = Display()
|
258
260
|
|
@@ -327,7 +329,12 @@ class Connection(ConnectionBase):
|
|
327
329
|
_log_channel: str | None = None
|
328
330
|
|
329
331
|
def __init__(self, *args, **kwargs):
|
330
|
-
display.deprecated(
|
332
|
+
display.deprecated( # pylint: disable=ansible-deprecated-unnecessary-collection-name
|
333
|
+
msg='The paramiko connection plugin is deprecated.',
|
334
|
+
version='2.21',
|
335
|
+
deprecator=_deprecator.ANSIBLE_CORE_DEPRECATOR, # entire plugin being removed; this improves the messaging
|
336
|
+
)
|
337
|
+
|
331
338
|
super().__init__(*args, **kwargs)
|
332
339
|
|
333
340
|
def _cache_key(self) -> str:
|
@@ -29,7 +29,7 @@ attributes:
|
|
29
29
|
platforms: all
|
30
30
|
until:
|
31
31
|
description: Denotes if this action obeys until/retry/poll keywords
|
32
|
-
support:
|
32
|
+
support: none
|
33
33
|
tags:
|
34
34
|
description: Allows for the 'tags' keyword to control the selection of this action for execution
|
35
35
|
support: full
|
ansible/plugins/filter/core.py
CHANGED
@@ -115,7 +115,10 @@ def to_bool(value: object) -> bool:
|
|
115
115
|
result = value_to_check == 1 # backwards compatibility with the old code which checked: value in ('yes', 'on', '1', 'true', 1)
|
116
116
|
|
117
117
|
# NB: update the doc string to reflect reality once this fallback is removed
|
118
|
-
display.deprecated(
|
118
|
+
display.deprecated(
|
119
|
+
msg=f'The `bool` filter coerced invalid value {value!r} ({native_type_name(value)}) to {result!r}.',
|
120
|
+
version='2.23',
|
121
|
+
)
|
119
122
|
|
120
123
|
return result
|
121
124
|
|
@@ -28,7 +28,7 @@ from collections.abc import Mapping
|
|
28
28
|
from ansible import template as _template
|
29
29
|
from ansible.errors import AnsibleError, AnsibleParserError, AnsibleValueOmittedError
|
30
30
|
from ansible.inventory.group import to_safe_group_name as original_safe
|
31
|
-
from ansible.module_utils._internal import
|
31
|
+
from ansible.module_utils._internal import _plugin_info
|
32
32
|
from ansible.parsing.utils.addresses import parse_address
|
33
33
|
from ansible.parsing.dataloader import DataLoader
|
34
34
|
from ansible.plugins import AnsiblePlugin, _ConfigurablePlugin
|
@@ -314,7 +314,7 @@ class BaseFileInventoryPlugin(_BaseInventoryPlugin):
|
|
314
314
|
super(BaseFileInventoryPlugin, self).__init__()
|
315
315
|
|
316
316
|
|
317
|
-
class Cacheable(
|
317
|
+
class Cacheable(_plugin_info.HasPluginInfo, _ConfigurablePlugin):
|
318
318
|
"""Mixin for inventory plugins which support caching."""
|
319
319
|
|
320
320
|
_cache: CachePluginAdjudicator
|