ansible-core 2.19.0rc1__py3-none-any.whl → 2.19.1rc1__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/_ansiballz/_builder.py +25 -14
- ansible/_internal/_templating/_engine.py +6 -4
- ansible/_internal/_templating/_jinja_bits.py +3 -1
- ansible/_internal/_templating/_jinja_plugins.py +7 -2
- ansible/_internal/_templating/_lazy_containers.py +5 -5
- ansible/config/base.yml +16 -6
- ansible/config/manager.py +37 -16
- ansible/executor/task_executor.py +5 -2
- ansible/executor/task_queue_manager.py +2 -2
- ansible/module_utils/_internal/_ansiballz/_extensions/_debugpy.py +97 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +2 -4
- ansible/module_utils/_internal/_traceback.py +1 -1
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +10 -2
- ansible/module_utils/common/validation.py +4 -1
- ansible/modules/dnf.py +36 -50
- ansible/modules/dnf5.py +36 -29
- ansible/modules/meta.py +2 -1
- ansible/modules/service_facts.py +5 -1
- ansible/playbook/helpers.py +1 -0
- ansible/playbook/taggable.py +1 -2
- ansible/plugins/__init__.py +18 -10
- ansible/plugins/callback/__init__.py +6 -1
- ansible/plugins/filter/to_json.yml +8 -4
- ansible/plugins/filter/to_nice_json.yml +3 -2
- ansible/plugins/lookup/template.py +6 -1
- ansible/release.py +1 -1
- ansible/utils/encrypt.py +2 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/RECORD +48 -47
- ansible_test/_internal/commands/integration/coverage.py +2 -2
- ansible_test/_internal/commands/shell/__init__.py +67 -28
- ansible_test/_internal/coverage_util.py +28 -25
- ansible_test/_internal/debugging.py +337 -49
- ansible_test/_internal/host_profiles.py +43 -43
- ansible_test/_internal/metadata.py +7 -42
- ansible_test/_internal/python_requirements.py +2 -2
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +1 -0
- ansible_test/_util/target/setup/bootstrap.sh +37 -16
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0rc1.dist-info → ansible_core-2.19.1rc1.dist-info}/top_level.txt +0 -0
ansible/modules/dnf.py
CHANGED
|
@@ -208,6 +208,8 @@ options:
|
|
|
208
208
|
packages to install (because dependencies between the downgraded
|
|
209
209
|
package and others can cause changes to the packages which were
|
|
210
210
|
in the earlier transaction).
|
|
211
|
+
- Since this feature is not provided by C(dnf) itself but by M(ansible.builtin.dnf) module,
|
|
212
|
+
using this in combination with wildcard characters in O(name) may result in an unexpected results.
|
|
211
213
|
type: bool
|
|
212
214
|
default: "no"
|
|
213
215
|
version_added: "2.7"
|
|
@@ -708,72 +710,56 @@ class DnfModule(YumDnf):
|
|
|
708
710
|
self.module.exit_json(msg="", results=results)
|
|
709
711
|
|
|
710
712
|
def _is_installed(self, pkg):
|
|
711
|
-
|
|
712
|
-
if dnf.util.is_glob_pattern(pkg):
|
|
713
|
-
available_query = dnf.subject.Subject(pkg).get_best_query(sack=self.base.sack).available()
|
|
714
|
-
return not (
|
|
715
|
-
{p.name for p in available_query} - {p.name for p in installed_query}
|
|
716
|
-
)
|
|
717
|
-
else:
|
|
718
|
-
return bool(installed_query)
|
|
713
|
+
return bool(dnf.subject.Subject(pkg).get_best_query(sack=self.base.sack).installed())
|
|
719
714
|
|
|
720
715
|
def _is_newer_version_installed(self, pkg_spec):
|
|
716
|
+
# expects a versioned package spec
|
|
721
717
|
try:
|
|
722
718
|
if isinstance(pkg_spec, dnf.package.Package):
|
|
723
719
|
installed = sorted(self.base.sack.query().installed().filter(name=pkg_spec.name, arch=pkg_spec.arch))[-1]
|
|
724
720
|
return installed.evr_gt(pkg_spec)
|
|
725
721
|
else:
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
if installed_pkg.evr_gt(available_pkg):
|
|
735
|
-
return True
|
|
736
|
-
return False
|
|
722
|
+
solution = dnf.subject.Subject(pkg_spec).get_best_solution(self.base.sack)
|
|
723
|
+
q = solution["query"]
|
|
724
|
+
if not q or not solution['nevra'] or solution['nevra'].has_just_name():
|
|
725
|
+
return False
|
|
726
|
+
installed = self.base.sack.query().installed().filter(name=solution['nevra'].name)
|
|
727
|
+
if not installed:
|
|
728
|
+
return False
|
|
729
|
+
return installed[0].evr_gt(q[0])
|
|
737
730
|
except IndexError:
|
|
738
731
|
return False
|
|
739
732
|
|
|
740
733
|
def _mark_package_install(self, pkg_spec, upgrade=False):
|
|
741
734
|
"""Mark the package for install."""
|
|
742
|
-
is_newer_version_installed = self._is_newer_version_installed(pkg_spec)
|
|
743
|
-
is_installed = self._is_installed(pkg_spec)
|
|
744
735
|
msg = ''
|
|
745
736
|
try:
|
|
746
|
-
if
|
|
737
|
+
if dnf.util.is_glob_pattern(pkg_spec):
|
|
738
|
+
# Special case for package specs that contain glob characters.
|
|
739
|
+
# For these we skip `is_installed` and `is_newer_version_installed` tests that allow for the
|
|
740
|
+
# allow_downgrade feature and pass the package specs to dnf.
|
|
741
|
+
# Since allow_downgrade is not available in dnf and while it is relatively easy to implement it for
|
|
742
|
+
# package specs that evaluate to a single package, trying to mimic what would the dnf machinery do
|
|
743
|
+
# for glob package specs and then filtering those for allow_downgrade appears to always
|
|
744
|
+
# result in naive/inferior solution.
|
|
745
|
+
# NOTE this has historically never worked even before https://github.com/ansible/ansible/pull/82725
|
|
746
|
+
# where our (buggy) custom code ignored wildcards for the installed checks.
|
|
747
|
+
# TODO reasearch how feasible it is to implement the above
|
|
748
|
+
if upgrade:
|
|
749
|
+
# for upgrade we pass the spec to both upgrade and install, to satisfy both available and installed
|
|
750
|
+
# packages evaluated from the glob spec
|
|
751
|
+
try:
|
|
752
|
+
self.base.upgrade(pkg_spec)
|
|
753
|
+
except dnf.exceptions.PackagesNotInstalledError:
|
|
754
|
+
pass
|
|
755
|
+
self.base.install(pkg_spec, strict=self.base.conf.strict)
|
|
756
|
+
elif self._is_newer_version_installed(pkg_spec):
|
|
747
757
|
if self.allow_downgrade:
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
# NVRs indexed)
|
|
752
|
-
if upgrade:
|
|
753
|
-
if is_installed: # Case 1
|
|
754
|
-
# TODO: Is this case reachable?
|
|
755
|
-
#
|
|
756
|
-
# _is_installed() demands a name (*not* NVR) or else is always False
|
|
757
|
-
# (wildcards are treated literally).
|
|
758
|
-
#
|
|
759
|
-
# Meanwhile, _is_newer_version_installed() demands something versioned
|
|
760
|
-
# or else is always false.
|
|
761
|
-
#
|
|
762
|
-
# I fail to see how they can both be true at the same time for any
|
|
763
|
-
# given pkg_spec. -re
|
|
764
|
-
self.base.upgrade(pkg_spec)
|
|
765
|
-
else: # Case 2
|
|
766
|
-
self.base.install(pkg_spec, strict=self.base.conf.strict)
|
|
767
|
-
else: # Case 3
|
|
768
|
-
self.base.install(pkg_spec, strict=self.base.conf.strict)
|
|
769
|
-
else: # Case 4, Nothing to do, report back
|
|
770
|
-
pass
|
|
771
|
-
elif is_installed: # A potentially older (or same) version is installed
|
|
772
|
-
if upgrade: # Case 5
|
|
758
|
+
self.base.install(pkg_spec, strict=self.base.conf.strict)
|
|
759
|
+
elif self._is_installed(pkg_spec):
|
|
760
|
+
if upgrade:
|
|
773
761
|
self.base.upgrade(pkg_spec)
|
|
774
|
-
|
|
775
|
-
pass
|
|
776
|
-
else: # Case 7, The package is not installed, simply install it
|
|
762
|
+
else:
|
|
777
763
|
self.base.install(pkg_spec, strict=self.base.conf.strict)
|
|
778
764
|
except dnf.exceptions.MarkingError as e:
|
|
779
765
|
msg = "No package {0} available.".format(pkg_spec)
|
ansible/modules/dnf5.py
CHANGED
|
@@ -178,6 +178,8 @@ options:
|
|
|
178
178
|
packages to install (because dependencies between the downgraded
|
|
179
179
|
package and others can cause changes to the packages which were
|
|
180
180
|
in the earlier transaction).
|
|
181
|
+
- Since this feature is not provided by C(dnf5) itself but by M(ansible.builtin.dnf5) module,
|
|
182
|
+
using this in combination with wildcard characters in O(name) may result in an unexpected results.
|
|
181
183
|
type: bool
|
|
182
184
|
default: "no"
|
|
183
185
|
install_repoquery:
|
|
@@ -368,7 +370,7 @@ libdnf5 = None
|
|
|
368
370
|
LIBDNF5_ERRORS = RuntimeError
|
|
369
371
|
|
|
370
372
|
|
|
371
|
-
def
|
|
373
|
+
def get_resolve_spec_settings():
|
|
372
374
|
settings = libdnf5.base.ResolveSpecSettings()
|
|
373
375
|
try:
|
|
374
376
|
settings.set_group_with_name(True)
|
|
@@ -394,47 +396,34 @@ def is_installed(base, spec):
|
|
|
394
396
|
settings.group_with_name = True
|
|
395
397
|
settings.with_binaries = False
|
|
396
398
|
settings.with_provides = False
|
|
399
|
+
return settings
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def is_installed(base, spec):
|
|
403
|
+
settings = get_resolve_spec_settings()
|
|
397
404
|
|
|
398
405
|
installed_query = libdnf5.rpm.PackageQuery(base)
|
|
399
406
|
installed_query.filter_installed()
|
|
400
407
|
match, nevra = installed_query.resolve_pkg_spec(spec, settings, True)
|
|
401
|
-
|
|
402
|
-
# FIXME use `is_glob_pattern` function when available:
|
|
403
|
-
# https://github.com/rpm-software-management/dnf5/issues/1563
|
|
404
|
-
glob_patterns = set("*[?")
|
|
405
|
-
if any(set(char) & glob_patterns for char in spec):
|
|
406
|
-
available_query = libdnf5.rpm.PackageQuery(base)
|
|
407
|
-
available_query.filter_available()
|
|
408
|
-
available_query.resolve_pkg_spec(spec, settings, True)
|
|
409
|
-
|
|
410
|
-
return not (
|
|
411
|
-
{p.get_name() for p in available_query} - {p.get_name() for p in installed_query}
|
|
412
|
-
)
|
|
413
|
-
else:
|
|
414
|
-
return match
|
|
408
|
+
return match
|
|
415
409
|
|
|
416
410
|
|
|
417
411
|
def is_newer_version_installed(base, spec):
|
|
418
|
-
#
|
|
412
|
+
# expects a versioned package spec
|
|
419
413
|
if "/" in spec:
|
|
420
414
|
spec = spec.split("/")[-1]
|
|
421
415
|
if spec.endswith(".rpm"):
|
|
422
416
|
spec = spec[:-4]
|
|
423
417
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return False
|
|
428
|
-
except StopIteration:
|
|
429
|
-
return False
|
|
430
|
-
|
|
431
|
-
spec_version = spec_nevra.get_version()
|
|
432
|
-
if not spec_version:
|
|
418
|
+
settings = get_resolve_spec_settings()
|
|
419
|
+
match, spec_nevra = libdnf5.rpm.PackageQuery(base).resolve_pkg_spec(spec, settings, True)
|
|
420
|
+
if not match or spec_nevra.has_just_name():
|
|
433
421
|
return False
|
|
422
|
+
spec_name = spec_nevra.get_name()
|
|
434
423
|
|
|
435
424
|
installed = libdnf5.rpm.PackageQuery(base)
|
|
436
425
|
installed.filter_installed()
|
|
437
|
-
installed.filter_name([
|
|
426
|
+
installed.filter_name([spec_name])
|
|
438
427
|
installed.filter_latest_evr()
|
|
439
428
|
try:
|
|
440
429
|
installed_package = list(installed)[-1]
|
|
@@ -442,8 +431,8 @@ def is_newer_version_installed(base, spec):
|
|
|
442
431
|
return False
|
|
443
432
|
|
|
444
433
|
target = libdnf5.rpm.PackageQuery(base)
|
|
445
|
-
target.filter_name([
|
|
446
|
-
target.filter_version([
|
|
434
|
+
target.filter_name([spec_name])
|
|
435
|
+
target.filter_version([spec_nevra.get_version()])
|
|
447
436
|
spec_release = spec_nevra.get_release()
|
|
448
437
|
if spec_release:
|
|
449
438
|
target.filter_release([spec_release])
|
|
@@ -725,8 +714,26 @@ class Dnf5Module(YumDnf):
|
|
|
725
714
|
goal.add_rpm_upgrade(settings)
|
|
726
715
|
elif self.state in {"installed", "present", "latest"}:
|
|
727
716
|
upgrade = self.state == "latest"
|
|
717
|
+
# FIXME use `is_glob_pattern` function when available:
|
|
718
|
+
# https://github.com/rpm-software-management/dnf5/issues/1563
|
|
719
|
+
glob_patterns = set("*[?")
|
|
728
720
|
for spec in self.names:
|
|
729
|
-
if
|
|
721
|
+
if any(set(char) & glob_patterns for char in spec):
|
|
722
|
+
# Special case for package specs that contain glob characters.
|
|
723
|
+
# For these we skip `is_installed` and `is_newer_version_installed` tests that allow for the
|
|
724
|
+
# allow_downgrade feature and pass the package specs to dnf.
|
|
725
|
+
# Since allow_downgrade is not available in dnf and while it is relatively easy to implement it for
|
|
726
|
+
# package specs that evaluate to a single package, trying to mimic what would the dnf machinery do
|
|
727
|
+
# for glob package specs and then filtering those for allow_downgrade appears to always
|
|
728
|
+
# result in naive/inferior solution.
|
|
729
|
+
# TODO reasearch how feasible it is to implement the above
|
|
730
|
+
if upgrade:
|
|
731
|
+
# for upgrade we pass the spec to both upgrade and install, to satisfy both available and installed
|
|
732
|
+
# packages evaluated from the glob spec
|
|
733
|
+
goal.add_upgrade(spec, settings)
|
|
734
|
+
if not self.update_only:
|
|
735
|
+
goal.add_install(spec, settings)
|
|
736
|
+
elif is_newer_version_installed(base, spec):
|
|
730
737
|
if self.allow_downgrade:
|
|
731
738
|
goal.add_install(spec, settings)
|
|
732
739
|
elif is_installed(base, spec):
|
ansible/modules/meta.py
CHANGED
|
@@ -33,6 +33,7 @@ options:
|
|
|
33
33
|
- V(clear_facts) (added in Ansible 2.1) causes the gathered facts for the hosts specified in the play's list of hosts to be cleared,
|
|
34
34
|
including the fact cache.
|
|
35
35
|
- V(clear_host_errors) (added in Ansible 2.1) clears the failed state (if any) from hosts specified in the play's list of hosts.
|
|
36
|
+
This will make them available for targetting in subsequent plays, but not continue execution in the current play.
|
|
36
37
|
- V(end_play) (added in Ansible 2.2) causes the play to end without failing the host(s). Note that this affects all hosts.
|
|
37
38
|
- V(reset_connection) (added in Ansible 2.3) interrupts a persistent connection (i.e. ssh + control persist)
|
|
38
39
|
- V(end_host) (added in Ansible 2.8) is a per-host variation of V(end_play). Causes the play to end for the current host without failing it.
|
|
@@ -108,7 +109,7 @@ EXAMPLES = r"""
|
|
|
108
109
|
- name: Clear gathered facts from all currently targeted hosts
|
|
109
110
|
ansible.builtin.meta: clear_facts
|
|
110
111
|
|
|
111
|
-
# Example showing how to continue using a failed target
|
|
112
|
+
# Example showing how to continue using a failed target, for the next play
|
|
112
113
|
- name: Bring host back to play after failure
|
|
113
114
|
ansible.builtin.copy:
|
|
114
115
|
src: file
|
ansible/modules/service_facts.py
CHANGED
|
@@ -232,7 +232,11 @@ class ServiceScanService(BaseService):
|
|
|
232
232
|
if service_name == "*":
|
|
233
233
|
continue
|
|
234
234
|
service_state = line_data[1]
|
|
235
|
-
|
|
235
|
+
try:
|
|
236
|
+
service_runlevels = all_services_runlevels[service_name]
|
|
237
|
+
except KeyError:
|
|
238
|
+
self.module.warn(f"Service {service_name} not found in the service list")
|
|
239
|
+
continue
|
|
236
240
|
service_data = {"name": service_name, "runlevels": service_runlevels, "state": service_state, "source": "openrc"}
|
|
237
241
|
services[service_name] = service_data
|
|
238
242
|
|
ansible/playbook/helpers.py
CHANGED
|
@@ -169,6 +169,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
|
|
|
169
169
|
if not isinstance(parent_include, TaskInclude):
|
|
170
170
|
parent_include = parent_include._parent
|
|
171
171
|
continue
|
|
172
|
+
parent_include.post_validate(templar=templar)
|
|
172
173
|
parent_include_dir = os.path.dirname(parent_include.args.get('_raw_params'))
|
|
173
174
|
if cumulative_path is None:
|
|
174
175
|
cumulative_path = parent_include_dir
|
ansible/playbook/taggable.py
CHANGED
|
@@ -20,7 +20,6 @@ from __future__ import annotations
|
|
|
20
20
|
import typing as t
|
|
21
21
|
|
|
22
22
|
from ansible.errors import AnsibleError
|
|
23
|
-
from ansible.module_utils.six import string_types
|
|
24
23
|
from ansible.module_utils.common.sentinel import Sentinel
|
|
25
24
|
from ansible.module_utils._internal._datatag import AnsibleTagHelper
|
|
26
25
|
from ansible.playbook.attribute import FieldAttribute
|
|
@@ -40,7 +39,7 @@ def _flatten_tags(tags: list[str | int]) -> list[str | int]:
|
|
|
40
39
|
class Taggable:
|
|
41
40
|
|
|
42
41
|
untagged = frozenset(['untagged'])
|
|
43
|
-
tags = FieldAttribute(isa='list', default=list, listof=(
|
|
42
|
+
tags = FieldAttribute(isa='list', default=list, listof=(str, int), extend=True)
|
|
44
43
|
|
|
45
44
|
def _load_tags(self, attr, ds):
|
|
46
45
|
if isinstance(ds, list):
|
ansible/plugins/__init__.py
CHANGED
|
@@ -79,6 +79,7 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|
|
79
79
|
|
|
80
80
|
def __init__(self):
|
|
81
81
|
self._options = {}
|
|
82
|
+
self._origins = {}
|
|
82
83
|
self._defs = None
|
|
83
84
|
|
|
84
85
|
@property
|
|
@@ -98,11 +99,16 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|
|
98
99
|
return bool(possible_fqcns.intersection(set(self.ansible_aliases)))
|
|
99
100
|
|
|
100
101
|
def get_option_and_origin(self, option, hostvars=None):
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
if option not in self._options:
|
|
103
|
+
try:
|
|
104
|
+
# some plugins don't use set_option(s) and cannot use direct settings, so this populates the local copy for them
|
|
105
|
+
self._options[option], self._origins[option] = C.config.get_config_value_and_origin(option, plugin_type=self.plugin_type,
|
|
106
|
+
plugin_name=self._load_name, variables=hostvars)
|
|
107
|
+
except AnsibleError as e:
|
|
108
|
+
# callers expect key error on missing
|
|
109
|
+
raise KeyError() from e
|
|
110
|
+
|
|
111
|
+
return self._options[option], self._origins[option]
|
|
106
112
|
|
|
107
113
|
@functools.cached_property
|
|
108
114
|
def __plugin_info(self):
|
|
@@ -113,11 +119,10 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|
|
113
119
|
return _plugin_info.get_plugin_info(self)
|
|
114
120
|
|
|
115
121
|
def get_option(self, option, hostvars=None):
|
|
116
|
-
|
|
117
122
|
if option not in self._options:
|
|
118
|
-
|
|
119
|
-
self.
|
|
120
|
-
return self._options
|
|
123
|
+
# let it populate _options
|
|
124
|
+
self.get_option_and_origin(option, hostvars=hostvars)
|
|
125
|
+
return self._options[option]
|
|
121
126
|
|
|
122
127
|
def get_options(self, hostvars=None):
|
|
123
128
|
options = {}
|
|
@@ -127,6 +132,7 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|
|
127
132
|
|
|
128
133
|
def set_option(self, option, value):
|
|
129
134
|
self._options[option] = C.config.get_config_value(option, plugin_type=self.plugin_type, plugin_name=self._load_name, direct={option: value})
|
|
135
|
+
self._origins[option] = 'Direct'
|
|
130
136
|
_display._report_config_warnings(self.__plugin_info)
|
|
131
137
|
|
|
132
138
|
def set_options(self, task_keys=None, var_options=None, direct=None):
|
|
@@ -137,12 +143,14 @@ class AnsiblePlugin(_AnsiblePluginInfoMixin, _ConfigurablePlugin, metaclass=abc.
|
|
|
137
143
|
:arg var_options: Dict with either 'connection variables'
|
|
138
144
|
:arg direct: Dict with 'direct assignment'
|
|
139
145
|
"""
|
|
140
|
-
self._options = C.config.
|
|
146
|
+
self._options, self._origins = C.config.get_plugin_options_and_origins(self.plugin_type, self._load_name, keys=task_keys,
|
|
147
|
+
variables=var_options, direct=direct)
|
|
141
148
|
|
|
142
149
|
# allow extras/wildcards from vars that are not directly consumed in configuration
|
|
143
150
|
# this is needed to support things like winrm that can have extended protocol options we don't directly handle
|
|
144
151
|
if self.allow_extras and var_options and '_extras' in var_options:
|
|
145
152
|
# these are largely unvalidated passthroughs, either plugin or underlying API will validate
|
|
153
|
+
# TODO: deprecate and remove, most plugins that needed this don't use this facility anymore
|
|
146
154
|
self._options['_extras'] = var_options['_extras']
|
|
147
155
|
_display._report_config_warnings(self.__plugin_info)
|
|
148
156
|
|
|
@@ -228,10 +228,14 @@ class CallbackBase(AnsiblePlugin):
|
|
|
228
228
|
|
|
229
229
|
def set_option(self, k, v):
|
|
230
230
|
self._plugin_options[k] = C.config.get_config_value(k, plugin_type=self.plugin_type, plugin_name=self._load_name, direct={k: v})
|
|
231
|
+
self._origins[k] = 'direct'
|
|
231
232
|
|
|
232
233
|
def get_option(self, k, hostvars=None):
|
|
233
234
|
return self._plugin_options[k]
|
|
234
235
|
|
|
236
|
+
def get_option_and_origin(self, k, hostvars=None):
|
|
237
|
+
return self._plugin_options[k], self._origins[k]
|
|
238
|
+
|
|
235
239
|
def has_option(self, option):
|
|
236
240
|
return (option in self._plugin_options)
|
|
237
241
|
|
|
@@ -241,7 +245,8 @@ class CallbackBase(AnsiblePlugin):
|
|
|
241
245
|
"""
|
|
242
246
|
|
|
243
247
|
# load from config
|
|
244
|
-
self._plugin_options = C.config.
|
|
248
|
+
self._plugin_options, self._origins = C.config.get_plugin_options_and_origins(self.plugin_type, self._load_name,
|
|
249
|
+
keys=task_keys, variables=var_options, direct=direct)
|
|
245
250
|
|
|
246
251
|
@staticmethod
|
|
247
252
|
def host_label(result: CallbackTaskResult) -> str:
|
|
@@ -23,8 +23,9 @@ DOCUMENTATION:
|
|
|
23
23
|
default: True
|
|
24
24
|
version_added: '2.9'
|
|
25
25
|
allow_nan:
|
|
26
|
-
description:
|
|
27
|
-
|
|
26
|
+
description:
|
|
27
|
+
- When V(False), out-of-range float values C(nan), C(inf) and C(-inf) will result in an error.
|
|
28
|
+
- When V(True), out-of-range float values will be represented using their JavaScript equivalents, C(NaN), C(Infinity) and C(-Infinity).
|
|
28
29
|
default: True
|
|
29
30
|
type: bool
|
|
30
31
|
check_circular:
|
|
@@ -42,8 +43,11 @@ DOCUMENTATION:
|
|
|
42
43
|
separators:
|
|
43
44
|
description: The C(item) and C(key) separator to be used in the serialized output,
|
|
44
45
|
default may change depending on O(indent) and Python version.
|
|
45
|
-
default:
|
|
46
|
-
|
|
46
|
+
default:
|
|
47
|
+
- ', '
|
|
48
|
+
- ': '
|
|
49
|
+
type: list
|
|
50
|
+
elements: str
|
|
47
51
|
skipkeys:
|
|
48
52
|
description: If V(True), keys that are not basic Python types will be skipped.
|
|
49
53
|
default: False
|
|
@@ -23,8 +23,9 @@ DOCUMENTATION:
|
|
|
23
23
|
default: True
|
|
24
24
|
version_added: '2.9'
|
|
25
25
|
allow_nan:
|
|
26
|
-
description:
|
|
27
|
-
|
|
26
|
+
description:
|
|
27
|
+
- When V(False), out-of-range float values C(nan), C(inf) and C(-inf) will result in an error.
|
|
28
|
+
- When V(True), out-of-range float values will be represented using their JavaScript equivalents, C(NaN), C(Infinity) and C(-Infinity).
|
|
28
29
|
default: True
|
|
29
30
|
type: bool
|
|
30
31
|
check_circular:
|
|
@@ -107,6 +107,7 @@ from ansible.errors import AnsibleError
|
|
|
107
107
|
from ansible.plugins.lookup import LookupBase
|
|
108
108
|
from ansible.template import trust_as_template
|
|
109
109
|
from ansible._internal._templating import _template_vars
|
|
110
|
+
from ansible._internal._templating._engine import TemplateOptions, TemplateOverrides
|
|
110
111
|
from ansible.utils.display import Display
|
|
111
112
|
|
|
112
113
|
|
|
@@ -174,7 +175,11 @@ class LookupModule(LookupBase):
|
|
|
174
175
|
)
|
|
175
176
|
|
|
176
177
|
data_templar = templar.copy_with_new_env(available_variables=vars, searchpath=searchpath)
|
|
177
|
-
|
|
178
|
+
# use the internal template API to avoid forced top-level finalization behavior imposed by the public API
|
|
179
|
+
res = data_templar._engine.template(template_data, options=TemplateOptions(
|
|
180
|
+
escape_backslashes=False,
|
|
181
|
+
overrides=TemplateOverrides.from_kwargs(overrides),
|
|
182
|
+
))
|
|
178
183
|
|
|
179
184
|
ret.append(res)
|
|
180
185
|
else:
|
ansible/release.py
CHANGED
ansible/utils/encrypt.py
CHANGED
|
@@ -99,6 +99,8 @@ class PasslibHash(BaseHash):
|
|
|
99
99
|
salt = self._clean_salt(salt)
|
|
100
100
|
rounds = self._clean_rounds(rounds)
|
|
101
101
|
ident = self._clean_ident(ident)
|
|
102
|
+
if salt_size is not None and not isinstance(salt_size, int):
|
|
103
|
+
raise TypeError("salt_size must be an integer")
|
|
102
104
|
return self._hash(secret, salt=salt, salt_size=salt_size, rounds=rounds, ident=ident)
|
|
103
105
|
|
|
104
106
|
def _clean_ident(self, ident):
|