ansible-core 2.15.0__py3-none-any.whl → 2.15.2__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/config/manager.py +1 -1
- ansible/galaxy/collection/__init__.py +17 -30
- ansible/galaxy/collection/concrete_artifact_manager.py +12 -6
- ansible/galaxy/dependency_resolution/dataclasses.py +6 -3
- ansible/module_utils/ansible_release.py +1 -1
- ansible/modules/apt_key.py +8 -5
- ansible/modules/apt_repository.py +2 -0
- ansible/modules/deb822_repository.py +1 -1
- ansible/modules/dnf5.py +8 -8
- ansible/modules/find.py +3 -0
- ansible/modules/uri.py +9 -1
- ansible/modules/validate_argument_spec.py +1 -1
- ansible/plugins/action/template.py +26 -15
- ansible/plugins/connection/paramiko_ssh.py +8 -0
- ansible/plugins/connection/psrp.py +3 -3
- ansible/plugins/connection/ssh.py +19 -2
- ansible/plugins/filter/comment.yml +1 -1
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/to_yaml.yml +1 -1
- ansible/plugins/lookup/template.py +11 -6
- ansible/plugins/strategy/__init__.py +20 -12
- ansible/plugins/test/change.yml +1 -1
- ansible/plugins/test/changed.yml +1 -1
- ansible/plugins/test/reachable.yml +1 -1
- ansible/plugins/test/succeeded.yml +1 -1
- ansible/plugins/test/success.yml +1 -1
- ansible/plugins/test/successful.yml +1 -1
- ansible/plugins/test/unreachable.yml +1 -1
- ansible/release.py +1 -1
- ansible/template/__init__.py +42 -28
- ansible/utils/_junit_xml.py +5 -1
- {ansible_core-2.15.0.dist-info → ansible_core-2.15.2.dist-info}/METADATA +1 -1
- {ansible_core-2.15.0.dist-info → ansible_core-2.15.2.dist-info}/RECORD +61 -61
- ansible_test/_data/completion/remote.txt +2 -1
- ansible_test/_internal/__init__.py +11 -0
- ansible_test/_internal/cli/commands/env.py +1 -1
- ansible_test/_internal/commands/env/__init__.py +14 -17
- ansible_test/_internal/commands/integration/__init__.py +1 -1
- ansible_test/_internal/commands/integration/cloud/__init__.py +3 -3
- ansible_test/_internal/commands/sanity/pylint.py +4 -4
- ansible_test/_internal/commands/sanity/validate_modules.py +2 -2
- ansible_test/_internal/containers.py +2 -2
- ansible_test/_internal/coverage_util.py +2 -2
- ansible_test/_internal/data.py +2 -7
- ansible_test/_internal/git.py +1 -1
- ansible_test/_internal/junit_xml.py +5 -1
- ansible_test/_internal/payload.py +2 -2
- ansible_test/_internal/provider/layout/__init__.py +1 -1
- ansible_test/_internal/provider/layout/ansible.py +15 -0
- ansible_test/_internal/provider/layout/collection.py +9 -1
- ansible_test/_internal/provisioning.py +5 -2
- ansible_test/_internal/pypi_proxy.py +4 -4
- ansible_test/_internal/test.py +3 -5
- ansible_test/_internal/timeout.py +56 -19
- ansible_test/_internal/util.py +4 -0
- ansible_test/_internal/util_common.py +38 -6
- {ansible_core-2.15.0.data → ansible_core-2.15.2.data}/scripts/ansible-test +0 -0
- {ansible_core-2.15.0.dist-info → ansible_core-2.15.2.dist-info}/COPYING +0 -0
- {ansible_core-2.15.0.dist-info → ansible_core-2.15.2.dist-info}/WHEEL +0 -0
- {ansible_core-2.15.0.dist-info → ansible_core-2.15.2.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.15.0.dist-info → ansible_core-2.15.2.dist-info}/top_level.txt +0 -0
|
@@ -50,10 +50,12 @@ DOCUMENTATION = """
|
|
|
50
50
|
description: The string marking the beginning of a comment statement.
|
|
51
51
|
version_added: '2.12'
|
|
52
52
|
type: str
|
|
53
|
+
default: '{#'
|
|
53
54
|
comment_end_string:
|
|
54
55
|
description: The string marking the end of a comment statement.
|
|
55
56
|
version_added: '2.12'
|
|
56
57
|
type: str
|
|
58
|
+
default: '#}'
|
|
57
59
|
"""
|
|
58
60
|
|
|
59
61
|
EXAMPLES = """
|
|
@@ -145,13 +147,16 @@ class LookupModule(LookupBase):
|
|
|
145
147
|
vars.update(generate_ansible_template_vars(term, lookupfile))
|
|
146
148
|
vars.update(lookup_template_vars)
|
|
147
149
|
|
|
148
|
-
with templar.set_temporary_context(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
with templar.set_temporary_context(available_variables=vars, searchpath=searchpath):
|
|
151
|
+
overrides = dict(
|
|
152
|
+
variable_start_string=variable_start_string,
|
|
153
|
+
variable_end_string=variable_end_string,
|
|
154
|
+
comment_start_string=comment_start_string,
|
|
155
|
+
comment_end_string=comment_end_string
|
|
156
|
+
)
|
|
153
157
|
res = templar.template(template_data, preserve_trailing_newlines=True,
|
|
154
|
-
convert_data=convert_data_p, escape_backslashes=False
|
|
158
|
+
convert_data=convert_data_p, escape_backslashes=False,
|
|
159
|
+
overrides=overrides)
|
|
155
160
|
|
|
156
161
|
if (C.DEFAULT_JINJA2_NATIVE and not jinja2_native) or not convert_data_p:
|
|
157
162
|
# jinja2_native is true globally but off for the lookup, we need this text
|
|
@@ -652,20 +652,28 @@ class StrategyBase:
|
|
|
652
652
|
# only ensure that notified handlers exist, if so save the notifications for when
|
|
653
653
|
# handlers are actually flushed so the last defined handlers are exexcuted,
|
|
654
654
|
# otherwise depending on the setting either error or warn
|
|
655
|
+
host_state = iterator.get_state_for_host(original_host.name)
|
|
655
656
|
for notification in result_item['_ansible_notify']:
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
657
|
+
for handler in self.search_handlers_by_notification(notification, iterator):
|
|
658
|
+
if host_state.run_state == IteratingStates.HANDLERS:
|
|
659
|
+
# we're currently iterating handlers, so we need to expand this now
|
|
660
|
+
if handler.notify_host(original_host):
|
|
661
|
+
# NOTE even with notifications deduplicated this can still happen in case of handlers being
|
|
662
|
+
# notified multiple times using different names, like role name or fqcn
|
|
663
|
+
self._tqm.send_callback('v2_playbook_on_notify', handler, original_host)
|
|
664
|
+
else:
|
|
665
|
+
iterator.add_notification(original_host.name, notification)
|
|
666
|
+
display.vv(f"Notification for handler {notification} has been saved.")
|
|
667
|
+
break
|
|
667
668
|
else:
|
|
668
|
-
|
|
669
|
+
msg = (
|
|
670
|
+
f"The requested handler '{notification}' was not found in either the main handlers"
|
|
671
|
+
" list nor in the listening handlers list"
|
|
672
|
+
)
|
|
673
|
+
if C.ERROR_ON_MISSING_HANDLER:
|
|
674
|
+
raise AnsibleError(msg)
|
|
675
|
+
else:
|
|
676
|
+
display.warning(msg)
|
|
669
677
|
|
|
670
678
|
if 'add_host' in result_item:
|
|
671
679
|
# this task added a new host (add_host module)
|
ansible/plugins/test/change.yml
CHANGED
ansible/plugins/test/changed.yml
CHANGED
ansible/plugins/test/success.yml
CHANGED
ansible/release.py
CHANGED
ansible/template/__init__.py
CHANGED
|
@@ -153,6 +153,39 @@ def _escape_backslashes(data, jinja_env):
|
|
|
153
153
|
return data
|
|
154
154
|
|
|
155
155
|
|
|
156
|
+
def _create_overlay(data, overrides, jinja_env):
|
|
157
|
+
if overrides is None:
|
|
158
|
+
overrides = {}
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
has_override_header = data.startswith(JINJA2_OVERRIDE)
|
|
162
|
+
except (TypeError, AttributeError):
|
|
163
|
+
has_override_header = False
|
|
164
|
+
|
|
165
|
+
if overrides or has_override_header:
|
|
166
|
+
overlay = jinja_env.overlay(**overrides)
|
|
167
|
+
else:
|
|
168
|
+
overlay = jinja_env
|
|
169
|
+
|
|
170
|
+
# Get jinja env overrides from template
|
|
171
|
+
if has_override_header:
|
|
172
|
+
eol = data.find('\n')
|
|
173
|
+
line = data[len(JINJA2_OVERRIDE):eol]
|
|
174
|
+
data = data[eol + 1:]
|
|
175
|
+
for pair in line.split(','):
|
|
176
|
+
if ':' not in pair:
|
|
177
|
+
raise AnsibleError("failed to parse jinja2 override '%s'."
|
|
178
|
+
" Did you use something different from colon as key-value separator?" % pair.strip())
|
|
179
|
+
(key, val) = pair.split(':', 1)
|
|
180
|
+
key = key.strip()
|
|
181
|
+
if hasattr(overlay, key):
|
|
182
|
+
setattr(overlay, key, ast.literal_eval(val.strip()))
|
|
183
|
+
else:
|
|
184
|
+
display.warning(f"Could not find Jinja2 environment setting to override: '{key}'")
|
|
185
|
+
|
|
186
|
+
return data, overlay
|
|
187
|
+
|
|
188
|
+
|
|
156
189
|
def is_possibly_template(data, jinja_env):
|
|
157
190
|
"""Determines if a string looks like a template, by seeing if it
|
|
158
191
|
contains a jinja2 start delimiter. Does not guarantee that the string
|
|
@@ -705,7 +738,7 @@ class Templar:
|
|
|
705
738
|
variable = self._convert_bare_variable(variable)
|
|
706
739
|
|
|
707
740
|
if isinstance(variable, string_types):
|
|
708
|
-
if not self.is_possibly_template(variable):
|
|
741
|
+
if not self.is_possibly_template(variable, overrides):
|
|
709
742
|
return variable
|
|
710
743
|
|
|
711
744
|
# Check to see if the string we are trying to render is just referencing a single
|
|
@@ -776,8 +809,9 @@ class Templar:
|
|
|
776
809
|
|
|
777
810
|
templatable = is_template
|
|
778
811
|
|
|
779
|
-
def is_possibly_template(self, data):
|
|
780
|
-
|
|
812
|
+
def is_possibly_template(self, data, overrides=None):
|
|
813
|
+
data, env = _create_overlay(data, overrides, self.environment)
|
|
814
|
+
return is_possibly_template(data, env)
|
|
781
815
|
|
|
782
816
|
def _convert_bare_variable(self, variable):
|
|
783
817
|
'''
|
|
@@ -918,31 +952,11 @@ class Templar:
|
|
|
918
952
|
if fail_on_undefined is None:
|
|
919
953
|
fail_on_undefined = self._fail_on_undefined_errors
|
|
920
954
|
|
|
921
|
-
has_template_overrides = data.startswith(JINJA2_OVERRIDE)
|
|
922
|
-
|
|
923
955
|
try:
|
|
924
956
|
# NOTE Creating an overlay that lives only inside do_template means that overrides are not applied
|
|
925
957
|
# when templating nested variables in AnsibleJ2Vars where Templar.environment is used, not the overlay.
|
|
926
958
|
# This is historic behavior that is kept for backwards compatibility.
|
|
927
|
-
|
|
928
|
-
myenv = self.environment.overlay(overrides)
|
|
929
|
-
elif has_template_overrides:
|
|
930
|
-
myenv = self.environment.overlay()
|
|
931
|
-
else:
|
|
932
|
-
myenv = self.environment
|
|
933
|
-
|
|
934
|
-
# Get jinja env overrides from template
|
|
935
|
-
if has_template_overrides:
|
|
936
|
-
eol = data.find('\n')
|
|
937
|
-
line = data[len(JINJA2_OVERRIDE):eol]
|
|
938
|
-
data = data[eol + 1:]
|
|
939
|
-
for pair in line.split(','):
|
|
940
|
-
if ':' not in pair:
|
|
941
|
-
raise AnsibleError("failed to parse jinja2 override '%s'."
|
|
942
|
-
" Did you use something different from colon as key-value separator?" % pair.strip())
|
|
943
|
-
(key, val) = pair.split(':', 1)
|
|
944
|
-
key = key.strip()
|
|
945
|
-
setattr(myenv, key, ast.literal_eval(val.strip()))
|
|
959
|
+
data, myenv = _create_overlay(data, overrides, self.environment)
|
|
946
960
|
|
|
947
961
|
if escape_backslashes:
|
|
948
962
|
# Allow users to specify backslashes in playbooks as "\\" instead of as "\\\\".
|
|
@@ -970,7 +984,7 @@ class Templar:
|
|
|
970
984
|
# In case this is a recursive call and we set different concat
|
|
971
985
|
# function up the stack, reset it in case the value of convert_data
|
|
972
986
|
# changed in this call
|
|
973
|
-
|
|
987
|
+
myenv.concat = myenv.__class__.concat
|
|
974
988
|
# the concat function is set for each Ansible environment,
|
|
975
989
|
# however for convert_data=False we need to use the concat
|
|
976
990
|
# function that avoids any evaluation and set it temporarily
|
|
@@ -978,13 +992,13 @@ class Templar:
|
|
|
978
992
|
# the concat function is called internally in Jinja,
|
|
979
993
|
# most notably for macro execution
|
|
980
994
|
if not self.jinja2_native and not convert_data:
|
|
981
|
-
|
|
995
|
+
myenv.concat = ansible_concat
|
|
982
996
|
|
|
983
997
|
self.cur_context = t.new_context(jvars, shared=True)
|
|
984
998
|
rf = t.root_render_func(self.cur_context)
|
|
985
999
|
|
|
986
1000
|
try:
|
|
987
|
-
res =
|
|
1001
|
+
res = myenv.concat(rf)
|
|
988
1002
|
unsafe = getattr(self.cur_context, 'unsafe', False)
|
|
989
1003
|
if unsafe:
|
|
990
1004
|
res = wrap_var(res)
|
|
@@ -1012,7 +1026,7 @@ class Templar:
|
|
|
1012
1026
|
# "Hello world\n!\n" instead of "Hello world!\n".
|
|
1013
1027
|
res_newlines = _count_newlines_from_end(res)
|
|
1014
1028
|
if data_newlines > res_newlines:
|
|
1015
|
-
res +=
|
|
1029
|
+
res += myenv.newline_sequence * (data_newlines - res_newlines)
|
|
1016
1030
|
if unsafe:
|
|
1017
1031
|
res = wrap_var(res)
|
|
1018
1032
|
return res
|
ansible/utils/_junit_xml.py
CHANGED
|
@@ -144,6 +144,10 @@ class TestSuite:
|
|
|
144
144
|
system_out: str | None = None
|
|
145
145
|
system_err: str | None = None
|
|
146
146
|
|
|
147
|
+
def __post_init__(self):
|
|
148
|
+
if self.timestamp and self.timestamp.tzinfo != datetime.timezone.utc:
|
|
149
|
+
raise ValueError(f'timestamp.tzinfo must be {datetime.timezone.utc!r}')
|
|
150
|
+
|
|
147
151
|
@property
|
|
148
152
|
def disabled(self) -> int:
|
|
149
153
|
"""The number of disabled test cases."""
|
|
@@ -187,7 +191,7 @@ class TestSuite:
|
|
|
187
191
|
skipped=self.skipped,
|
|
188
192
|
tests=self.tests,
|
|
189
193
|
time=self.time,
|
|
190
|
-
timestamp=self.timestamp.isoformat(timespec='seconds') if self.timestamp else None,
|
|
194
|
+
timestamp=self.timestamp.replace(tzinfo=None).isoformat(timespec='seconds') if self.timestamp else None,
|
|
191
195
|
)
|
|
192
196
|
|
|
193
197
|
def get_xml_element(self) -> ET.Element:
|