ansible-core 2.19.0b3__py3-none-any.whl → 2.19.0b5__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 +2 -2
- ansible/_internal/_collection_proxy.py +1 -1
- ansible/_internal/_errors/_alarm_timeout.py +66 -0
- ansible/_internal/_errors/_captured.py +25 -30
- ansible/_internal/_errors/_error_factory.py +89 -0
- ansible/_internal/_errors/_error_utils.py +240 -0
- ansible/_internal/_errors/_task_timeout.py +28 -0
- ansible/_internal/_event_formatting.py +127 -0
- ansible/_internal/_json/__init__.py +6 -6
- ansible/_internal/_json/_profiles/_cache_persistence.py +2 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +1 -1
- ansible/_internal/_json/_profiles/_legacy.py +3 -11
- ansible/_internal/_ssh/__init__.py +0 -0
- ansible/_internal/_ssh/_agent_launch.py +91 -0
- ansible/{utils → _internal/_ssh}/_ssh_agent.py +55 -93
- ansible/_internal/_templating/__init__.py +5 -3
- ansible/_internal/_templating/_datatag.py +2 -1
- ansible/_internal/_templating/_engine.py +3 -4
- ansible/_internal/_templating/_jinja_bits.py +21 -16
- ansible/_internal/_templating/_jinja_common.py +18 -27
- ansible/_internal/_templating/_jinja_plugins.py +31 -3
- ansible/_internal/_templating/_lazy_containers.py +5 -5
- ansible/_internal/_templating/_transform.py +20 -19
- ansible/_internal/_templating/_utils.py +1 -1
- ansible/_internal/_testing.py +26 -0
- ansible/_internal/_yaml/_dumper.py +1 -1
- ansible/_internal/_yaml/_errors.py +7 -7
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +1 -1
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +1 -1
- ansible/cli/__init__.py +5 -82
- ansible/cli/arguments/option_helpers.py +8 -5
- ansible/cli/doc.py +84 -28
- ansible/cli/inventory.py +1 -1
- ansible/compat/importlib_resources.py +9 -12
- ansible/config/base.yml +27 -23
- ansible/config/manager.py +142 -101
- ansible/constants.py +1 -1
- ansible/errors/__init__.py +96 -49
- ansible/executor/module_common.py +8 -10
- ansible/executor/powershell/async_watchdog.ps1 +2 -2
- ansible/executor/powershell/async_wrapper.ps1 +3 -3
- ansible/executor/powershell/become_wrapper.ps1 +20 -2
- ansible/executor/powershell/bootstrap_wrapper.ps1 +28 -6
- ansible/executor/powershell/coverage_wrapper.ps1 +15 -6
- ansible/executor/powershell/exec_wrapper.ps1 +219 -6
- ansible/executor/powershell/module_manifest.py +52 -0
- ansible/executor/powershell/module_wrapper.ps1 +47 -21
- ansible/executor/powershell/powershell_expand_user.ps1 +20 -0
- ansible/executor/powershell/powershell_mkdtemp.ps1 +17 -0
- ansible/executor/process/worker.py +38 -113
- ansible/executor/task_executor.py +26 -61
- ansible/executor/task_result.py +2 -4
- ansible/galaxy/collection/__init__.py +1 -4
- ansible/inventory/manager.py +1 -0
- ansible/module_utils/_internal/__init__.py +0 -3
- ansible/module_utils/_internal/_ambient_context.py +3 -3
- ansible/module_utils/_internal/_ansiballz.py +4 -2
- ansible/module_utils/_internal/_datatag/__init__.py +20 -14
- ansible/module_utils/_internal/_datatag/_tags.py +2 -2
- ansible/module_utils/_internal/_deprecator.py +66 -48
- ansible/module_utils/_internal/_errors.py +88 -17
- ansible/module_utils/_internal/_event_utils.py +61 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +21 -4
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +2 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +2 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +3 -1
- ansible/module_utils/{common/messages.py → _internal/_messages.py} +28 -47
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +1 -3
- ansible/module_utils/_internal/_plugin_info.py +1 -1
- ansible/module_utils/_internal/_stack.py +22 -0
- ansible/module_utils/_internal/_text_utils.py +6 -0
- ansible/module_utils/_internal/_traceback.py +11 -8
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +49 -15
- ansible/module_utils/common/arg_spec.py +2 -2
- ansible/module_utils/common/collections.py +6 -0
- ansible/module_utils/common/json.py +2 -2
- ansible/module_utils/common/text/converters.py +3 -3
- ansible/module_utils/common/validation.py +1 -1
- ansible/module_utils/common/warnings.py +80 -23
- ansible/module_utils/common/yaml.py +1 -1
- ansible/module_utils/datatag.py +5 -2
- ansible/module_utils/facts/system/distribution.py +16 -3
- ansible/module_utils/facts/virtual/linux.py +2 -2
- ansible/module_utils/parsing/convert_bool.py +6 -0
- ansible/module_utils/service.py +2 -9
- ansible/modules/apt_repository.py +7 -29
- ansible/modules/assemble.py +4 -4
- ansible/modules/async_status.py +13 -11
- ansible/modules/async_wrapper.py +5 -5
- ansible/modules/cron.py +3 -5
- ansible/modules/dnf5.py +15 -22
- ansible/modules/git.py +1 -6
- ansible/modules/hostname.py +0 -1
- ansible/modules/pip.py +2 -4
- ansible/modules/service.py +3 -9
- ansible/modules/sysvinit.py +3 -3
- ansible/parsing/ajson.py +3 -5
- ansible/parsing/dataloader.py +4 -4
- ansible/parsing/mod_args.py +1 -1
- ansible/parsing/plugin_docs.py +2 -2
- ansible/parsing/utils/yaml.py +3 -3
- ansible/parsing/vault/__init__.py +4 -4
- ansible/playbook/playbook_include.py +1 -1
- ansible/playbook/taggable.py +0 -3
- ansible/plugins/__init__.py +0 -25
- ansible/plugins/action/__init__.py +9 -32
- ansible/plugins/action/add_host.py +1 -1
- ansible/plugins/action/assemble.py +8 -16
- ansible/plugins/action/async_status.py +7 -2
- ansible/plugins/action/copy.py +8 -7
- ansible/plugins/action/gather_facts.py +8 -8
- ansible/plugins/action/package.py +5 -8
- ansible/plugins/action/script.py +8 -15
- ansible/plugins/action/service.py +3 -7
- ansible/plugins/action/template.py +6 -8
- ansible/plugins/action/unarchive.py +5 -15
- ansible/plugins/action/uri.py +9 -20
- ansible/plugins/callback/__init__.py +4 -6
- ansible/plugins/callback/junit.py +4 -2
- ansible/plugins/connection/local.py +2 -2
- ansible/plugins/connection/ssh.py +17 -9
- ansible/plugins/connection/winrm.py +5 -2
- ansible/plugins/doc_fragments/constructed.py +2 -2
- ansible/plugins/filter/core.py +13 -6
- ansible/plugins/filter/encryption.py +4 -4
- ansible/plugins/inventory/__init__.py +11 -10
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +69 -16
- ansible/plugins/loader.py +10 -9
- ansible/plugins/lookup/csvfile.py +16 -71
- ansible/plugins/lookup/first_found.py +2 -1
- ansible/plugins/shell/__init__.py +56 -2
- ansible/plugins/shell/powershell.py +66 -9
- ansible/plugins/shell/sh.py +9 -5
- ansible/plugins/test/core.py +21 -15
- ansible/plugins/test/finished.yml +1 -1
- ansible/plugins/test/uri.py +2 -5
- ansible/release.py +1 -1
- ansible/template/__init__.py +30 -2
- ansible/utils/collection_loader/__init__.py +2 -0
- ansible/utils/display.py +107 -128
- ansible/utils/hashing.py +0 -1
- ansible/utils/listify.py +6 -4
- ansible/utils/plugin_docs.py +2 -1
- ansible/utils/unsafe_proxy.py +1 -1
- ansible/vars/hostvars.py +1 -1
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/METADATA +3 -2
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/RECORD +173 -161
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/WHEEL +1 -1
- ansible_test/_data/completion/docker.txt +3 -3
- ansible_test/_data/completion/remote.txt +1 -0
- ansible_test/_data/requirements/sanity.ansible-doc.txt +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +2 -2
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_internal/util.py +20 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated_calls.py +73 -8
- ansible_test/_util/target/setup/bootstrap.sh +31 -0
- ansible/_internal/_errors/_utils.py +0 -310
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses}/COPYING +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/Apache-License.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/MIT-license.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/PSF-license.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info/licenses/licenses}/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b3.dist-info → ansible_core-2.19.0b5.dist-info}/top_level.txt +0 -0
@@ -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'
|
@@ -201,7 +201,7 @@ class LinuxVirtual(Virtual):
|
|
201
201
|
virtual_facts['virtualization_type'] = 'virtualbox'
|
202
202
|
found_virt = True
|
203
203
|
|
204
|
-
if bios_vendor in ('Amazon EC2', 'DigitalOcean', 'Hetzner'):
|
204
|
+
if bios_vendor in ('Amazon EC2', 'DigitalOcean', 'Hetzner', 'Linode'):
|
205
205
|
guest_tech.add('kvm')
|
206
206
|
if not found_virt:
|
207
207
|
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/module_utils/service.py
CHANGED
@@ -36,7 +36,7 @@ import select
|
|
36
36
|
import shlex
|
37
37
|
import subprocess
|
38
38
|
|
39
|
-
from ansible.module_utils.six import
|
39
|
+
from ansible.module_utils.six import b
|
40
40
|
from ansible.module_utils.common.text.converters import to_bytes, to_text
|
41
41
|
|
42
42
|
|
@@ -187,12 +187,8 @@ def daemonize(module, cmd):
|
|
187
187
|
if pid == 0:
|
188
188
|
os.close(pipe[0])
|
189
189
|
|
190
|
-
# if command is string deal with py2 vs py3 conversions for shlex
|
191
190
|
if not isinstance(cmd, list):
|
192
|
-
|
193
|
-
cmd = shlex.split(to_bytes(cmd, errors=errors))
|
194
|
-
else:
|
195
|
-
cmd = shlex.split(to_text(cmd, errors=errors))
|
191
|
+
cmd = shlex.split(to_text(cmd, errors=errors))
|
196
192
|
|
197
193
|
# make sure we always use byte strings
|
198
194
|
run_cmd = []
|
@@ -247,9 +243,6 @@ def daemonize(module, cmd):
|
|
247
243
|
break
|
248
244
|
return_data += to_bytes(data, errors=errors)
|
249
245
|
|
250
|
-
# Note: no need to specify encoding on py3 as this module sends the
|
251
|
-
# pickle to itself (thus same python interpreter so we aren't mixing
|
252
|
-
# py2 and py3)
|
253
246
|
return pickle.loads(to_bytes(return_data, errors=errors))
|
254
247
|
|
255
248
|
|
@@ -88,8 +88,8 @@ options:
|
|
88
88
|
description:
|
89
89
|
- Whether to automatically try to install the Python apt library or not, if it is not already installed.
|
90
90
|
Without this library, the module does not work.
|
91
|
-
- Runs C(apt-get install
|
92
|
-
- Only works with the system Python
|
91
|
+
- Runs C(apt-get install python3-apt).
|
92
|
+
- Only works with the system Python. If you are using a Python on the remote that is not
|
93
93
|
the system Python, set O(install_python_apt=false) and ensure that the Python apt library
|
94
94
|
for your Python version is installed some other way.
|
95
95
|
type: bool
|
@@ -98,8 +98,7 @@ author:
|
|
98
98
|
- Alexander Saltanov (@sashka)
|
99
99
|
version_added: "0.7"
|
100
100
|
requirements:
|
101
|
-
-
|
102
|
-
- python3-apt (python 3)
|
101
|
+
- python3-apt
|
103
102
|
- apt-key or gpg
|
104
103
|
"""
|
105
104
|
|
@@ -232,14 +231,15 @@ class SourcesList(object):
|
|
232
231
|
self.files_mapping = {} # internal DS for tracking symlinks
|
233
232
|
# Repositories that we're adding -- used to implement mode param
|
234
233
|
self.new_repos = set()
|
235
|
-
self.default_file =
|
234
|
+
self.default_file = apt_pkg.config.find_file('Dir::Etc::sourcelist')
|
236
235
|
|
237
236
|
# read sources.list if it exists
|
238
237
|
if os.path.isfile(self.default_file):
|
239
238
|
self.load(self.default_file)
|
240
239
|
|
241
240
|
# read sources.list.d
|
242
|
-
|
241
|
+
self.sources_dir = apt_pkg.config.find_dir('Dir::Etc::sourceparts')
|
242
|
+
for file in glob.iglob(f'{self.sources_dir}/*.list'):
|
243
243
|
if os.path.islink(file):
|
244
244
|
self.files_mapping[file] = os.readlink(file)
|
245
245
|
self.load(file)
|
@@ -255,7 +255,7 @@ class SourcesList(object):
|
|
255
255
|
if '/' in filename:
|
256
256
|
return filename
|
257
257
|
else:
|
258
|
-
return os.path.abspath(os.path.join(self.
|
258
|
+
return os.path.abspath(os.path.join(self.sources_dir, filename))
|
259
259
|
|
260
260
|
def _suggest_filename(self, line):
|
261
261
|
def _cleanup_filename(s):
|
@@ -313,28 +313,6 @@ class SourcesList(object):
|
|
313
313
|
|
314
314
|
return valid, enabled, source, comment
|
315
315
|
|
316
|
-
@staticmethod
|
317
|
-
def _apt_cfg_file(filespec):
|
318
|
-
"""
|
319
|
-
Wrapper for `apt_pkg` module for running with Python 2.5
|
320
|
-
"""
|
321
|
-
try:
|
322
|
-
result = apt_pkg.config.find_file(filespec)
|
323
|
-
except AttributeError:
|
324
|
-
result = apt_pkg.Config.FindFile(filespec)
|
325
|
-
return result
|
326
|
-
|
327
|
-
@staticmethod
|
328
|
-
def _apt_cfg_dir(dirspec):
|
329
|
-
"""
|
330
|
-
Wrapper for `apt_pkg` module for running with Python 2.5
|
331
|
-
"""
|
332
|
-
try:
|
333
|
-
result = apt_pkg.config.find_dir(dirspec)
|
334
|
-
except AttributeError:
|
335
|
-
result = apt_pkg.Config.FindDir(dirspec)
|
336
|
-
return result
|
337
|
-
|
338
316
|
def load(self, file):
|
339
317
|
group = []
|
340
318
|
f = open(file, 'r')
|
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
@@ -28,6 +28,8 @@ options:
|
|
28
28
|
type: str
|
29
29
|
choices: [ cleanup, status ]
|
30
30
|
default: status
|
31
|
+
notes:
|
32
|
+
- The RV(started) and RV(finished) return values were updated to return V(True) or V(False) instead of V(1) or V(0) in ansible-core 2.19.
|
31
33
|
extends_documentation_fragment:
|
32
34
|
- action_common_attributes
|
33
35
|
- action_common_attributes.flow
|
@@ -85,15 +87,15 @@ ansible_job_id:
|
|
85
87
|
type: str
|
86
88
|
sample: '360874038559.4169'
|
87
89
|
finished:
|
88
|
-
description: Whether the asynchronous job has finished
|
90
|
+
description: Whether the asynchronous job has finished or not
|
89
91
|
returned: always
|
90
|
-
type:
|
91
|
-
sample:
|
92
|
+
type: bool
|
93
|
+
sample: true
|
92
94
|
started:
|
93
|
-
description: Whether the asynchronous job has started
|
95
|
+
description: Whether the asynchronous job has started or not
|
94
96
|
returned: always
|
95
|
-
type:
|
96
|
-
sample:
|
97
|
+
type: bool
|
98
|
+
sample: true
|
97
99
|
stdout:
|
98
100
|
description: Any output returned by async_wrapper
|
99
101
|
returned: always
|
@@ -134,7 +136,7 @@ def main():
|
|
134
136
|
log_path = os.path.join(async_dir, jid)
|
135
137
|
|
136
138
|
if not os.path.exists(log_path):
|
137
|
-
module.fail_json(msg="could not find job", ansible_job_id=jid, started=
|
139
|
+
module.fail_json(msg="could not find job", ansible_job_id=jid, started=True, finished=True)
|
138
140
|
|
139
141
|
if mode == 'cleanup':
|
140
142
|
os.unlink(log_path)
|
@@ -151,16 +153,16 @@ def main():
|
|
151
153
|
except Exception:
|
152
154
|
if not data:
|
153
155
|
# file not written yet? That means it is running
|
154
|
-
module.exit_json(results_file=log_path, ansible_job_id=jid, started=
|
156
|
+
module.exit_json(results_file=log_path, ansible_job_id=jid, started=True, finished=False)
|
155
157
|
else:
|
156
158
|
module.fail_json(ansible_job_id=jid, results_file=log_path,
|
157
|
-
msg="Could not parse job output: %s" % data, started=
|
159
|
+
msg="Could not parse job output: %s" % data, started=True, finished=True)
|
158
160
|
|
159
161
|
if 'started' not in data:
|
160
|
-
data['finished'] =
|
162
|
+
data['finished'] = True
|
161
163
|
data['ansible_job_id'] = jid
|
162
164
|
elif 'finished' not in data:
|
163
|
-
data['finished'] =
|
165
|
+
data['finished'] = False
|
164
166
|
|
165
167
|
# just write the module output directly to stdout and exit; bypass other processing done by exit_json since it's already been done
|
166
168
|
print(f"\n{json.dumps(data)}") # pylint: disable=ansible-bad-function
|
ansible/modules/async_wrapper.py
CHANGED
@@ -149,7 +149,7 @@ def _run_module(wrapped_cmd, jid):
|
|
149
149
|
|
150
150
|
# DTFIX-FUTURE: needs rework for serialization profiles
|
151
151
|
|
152
|
-
jwrite({"started":
|
152
|
+
jwrite({"started": True, "finished": False, "ansible_job_id": jid})
|
153
153
|
|
154
154
|
result = {}
|
155
155
|
|
@@ -203,7 +203,7 @@ def _run_module(wrapped_cmd, jid):
|
|
203
203
|
except (OSError, IOError):
|
204
204
|
e = sys.exc_info()[1]
|
205
205
|
result = {
|
206
|
-
"failed":
|
206
|
+
"failed": True,
|
207
207
|
"cmd": wrapped_cmd,
|
208
208
|
"msg": to_text(e),
|
209
209
|
"outdata": outdata, # temporary notice only
|
@@ -214,7 +214,7 @@ def _run_module(wrapped_cmd, jid):
|
|
214
214
|
|
215
215
|
except (ValueError, Exception):
|
216
216
|
result = {
|
217
|
-
"failed":
|
217
|
+
"failed": True,
|
218
218
|
"cmd": wrapped_cmd,
|
219
219
|
"data": outdata, # temporary notice only
|
220
220
|
"stderr": stderr,
|
@@ -260,7 +260,7 @@ def main():
|
|
260
260
|
_make_temp_dir(jobdir)
|
261
261
|
except Exception as e:
|
262
262
|
end({
|
263
|
-
"failed":
|
263
|
+
"failed": True,
|
264
264
|
"msg": "could not create directory: %s - %s" % (jobdir, to_text(e)),
|
265
265
|
"exception": to_text(traceback.format_exc()), # NB: task executor compat will coerce to the correct dataclass type
|
266
266
|
}, 1)
|
@@ -293,7 +293,7 @@ def main():
|
|
293
293
|
continue
|
294
294
|
|
295
295
|
notice("Return async_wrapper task started.")
|
296
|
-
end({"failed":
|
296
|
+
end({"failed": False, "started": True, "finished": False, "ansible_job_id": jid, "results_file": job_path,
|
297
297
|
"_ansible_suppress_tmpdir_delete": (not preserve_tmp)}, 0)
|
298
298
|
else:
|
299
299
|
# The actual wrapper process
|
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
@@ -365,7 +365,7 @@ from ansible.module_utils.yumdnf import YumDnf, yumdnf_argument_spec
|
|
365
365
|
|
366
366
|
libdnf5 = None
|
367
367
|
# Through dnf5-5.2.12 all exceptions raised through swig became RuntimeError
|
368
|
-
|
368
|
+
LIBDNF5_ERRORS = RuntimeError
|
369
369
|
|
370
370
|
|
371
371
|
def is_installed(base, spec):
|
@@ -423,7 +423,9 @@ def is_newer_version_installed(base, spec):
|
|
423
423
|
|
424
424
|
try:
|
425
425
|
spec_nevra = next(iter(libdnf5.rpm.Nevra.parse(spec)))
|
426
|
-
except
|
426
|
+
except LIBDNF5_ERRORS:
|
427
|
+
return False
|
428
|
+
except StopIteration:
|
427
429
|
return False
|
428
430
|
|
429
431
|
spec_version = spec_nevra.get_version()
|
@@ -517,7 +519,7 @@ class Dnf5Module(YumDnf):
|
|
517
519
|
os.environ["LANGUAGE"] = os.environ["LANG"] = locale
|
518
520
|
|
519
521
|
global libdnf5
|
520
|
-
global
|
522
|
+
global LIBDNF5_ERRORS
|
521
523
|
has_dnf = True
|
522
524
|
try:
|
523
525
|
import libdnf5 # type: ignore[import]
|
@@ -526,7 +528,7 @@ class Dnf5Module(YumDnf):
|
|
526
528
|
|
527
529
|
try:
|
528
530
|
import libdnf5.exception # type: ignore[import-not-found]
|
529
|
-
|
531
|
+
LIBDNF5_ERRORS = (libdnf5.exception.Error, libdnf5.exception.NonLibdnf5Exception)
|
530
532
|
except (ImportError, AttributeError):
|
531
533
|
pass
|
532
534
|
|
@@ -581,15 +583,7 @@ class Dnf5Module(YumDnf):
|
|
581
583
|
if self.conf_file:
|
582
584
|
conf.config_file_path = self.conf_file
|
583
585
|
|
584
|
-
|
585
|
-
base.load_config()
|
586
|
-
except LIBDNF5_ERROR as e:
|
587
|
-
self.module.fail_json(
|
588
|
-
msg=str(e),
|
589
|
-
conf_file=self.conf_file,
|
590
|
-
failures=[],
|
591
|
-
rc=1,
|
592
|
-
)
|
586
|
+
base.load_config()
|
593
587
|
|
594
588
|
if self.releasever is not None:
|
595
589
|
variables = base.get_vars()
|
@@ -722,6 +716,7 @@ class Dnf5Module(YumDnf):
|
|
722
716
|
if self.security:
|
723
717
|
types.append("security")
|
724
718
|
advisory_query.filter_type(types)
|
719
|
+
conf.skip_unavailable = True # ignore packages that are of a different type, for backwards compat
|
725
720
|
settings.set_advisory_filter(advisory_query)
|
726
721
|
|
727
722
|
goal = libdnf5.base.Goal(base)
|
@@ -744,19 +739,13 @@ class Dnf5Module(YumDnf):
|
|
744
739
|
goal.add_install(spec, settings)
|
745
740
|
elif self.state in {"absent", "removed"}:
|
746
741
|
for spec in self.names:
|
747
|
-
|
748
|
-
goal.add_remove(spec, settings)
|
749
|
-
except LIBDNF5_ERROR as e:
|
750
|
-
self.module.fail_json(msg=str(e), failures=[], rc=1)
|
742
|
+
goal.add_remove(spec, settings)
|
751
743
|
if self.autoremove:
|
752
744
|
for pkg in get_unneeded_pkgs(base):
|
753
745
|
goal.add_rpm_remove(pkg, settings)
|
754
746
|
|
755
747
|
goal.set_allow_erasing(self.allowerasing)
|
756
|
-
|
757
|
-
transaction = goal.resolve()
|
758
|
-
except LIBDNF5_ERROR as e:
|
759
|
-
self.module.fail_json(msg=str(e), failures=[], rc=1)
|
748
|
+
transaction = goal.resolve()
|
760
749
|
|
761
750
|
if transaction.get_problems():
|
762
751
|
failures = []
|
@@ -832,7 +821,11 @@ def main():
|
|
832
821
|
auto_install_module_deps=dict(type="bool", default=True),
|
833
822
|
)
|
834
823
|
)
|
835
|
-
|
824
|
+
module = AnsibleModule(**yumdnf_argument_spec)
|
825
|
+
try:
|
826
|
+
Dnf5Module(module).run()
|
827
|
+
except LIBDNF5_ERRORS as e:
|
828
|
+
module.fail_json(msg=str(e), failures=[], rc=1)
|
836
829
|
|
837
830
|
|
838
831
|
if __name__ == "__main__":
|
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/hostname.py
CHANGED
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/service.py
CHANGED
@@ -180,7 +180,7 @@ from ansible.module_utils.basic import AnsibleModule
|
|
180
180
|
from ansible.module_utils.common.locale import get_best_parsable_locale
|
181
181
|
from ansible.module_utils.common.sys_info import get_platform_subclass
|
182
182
|
from ansible.module_utils.service import fail_if_missing, is_systemd_managed
|
183
|
-
from ansible.module_utils.six import
|
183
|
+
from ansible.module_utils.six import b
|
184
184
|
|
185
185
|
|
186
186
|
class Service(object):
|
@@ -285,14 +285,8 @@ class Service(object):
|
|
285
285
|
os._exit(0)
|
286
286
|
|
287
287
|
# Start the command
|
288
|
-
|
289
|
-
|
290
|
-
cmd = to_bytes(cmd, errors='surrogate_or_strict')
|
291
|
-
cmd = shlex.split(cmd)
|
292
|
-
else:
|
293
|
-
# Python3.x shex.split text strings.
|
294
|
-
cmd = to_text(cmd, errors='surrogate_or_strict')
|
295
|
-
cmd = [to_bytes(c, errors='surrogate_or_strict') for c in shlex.split(cmd)]
|
288
|
+
cmd = to_text(cmd, errors='surrogate_or_strict')
|
289
|
+
cmd = [to_bytes(c, errors='surrogate_or_strict') for c in shlex.split(cmd)]
|
296
290
|
# In either of the above cases, pass a list of byte strings to Popen
|
297
291
|
|
298
292
|
# chkconfig localizes messages and we're screen scraping so make
|
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/parsing/ajson.py
CHANGED
@@ -4,15 +4,13 @@
|
|
4
4
|
from __future__ import annotations as _annotations
|
5
5
|
|
6
6
|
# from ansible.utils.display import Display as _Display
|
7
|
-
|
8
|
-
|
9
|
-
# DTFIX-RELEASE: The pylint deprecated checker does not detect `Display().deprecated` calls, of which we have many.
|
10
|
-
|
7
|
+
#
|
8
|
+
#
|
11
9
|
# deprecated: description='deprecate ajson' core_version='2.23'
|
12
10
|
# _Display().deprecated(
|
13
11
|
# msg='The `ansible.parsing.ajson` module is deprecated.',
|
14
12
|
# version='2.27',
|
15
|
-
# help_text="", # DTFIX-
|
13
|
+
# help_text="", # DTFIX-FUTURE: complete this help text
|
16
14
|
# )
|
17
15
|
|
18
16
|
# Imported for backward compat
|
ansible/parsing/dataloader.py
CHANGED
@@ -15,7 +15,7 @@ import typing as t
|
|
15
15
|
|
16
16
|
from ansible import constants as C
|
17
17
|
from ansible.errors import AnsibleFileNotFound, AnsibleParserError
|
18
|
-
from ansible._internal._errors import
|
18
|
+
from ansible._internal._errors import _error_utils
|
19
19
|
from ansible.module_utils.basic import is_executable
|
20
20
|
from ansible._internal._datatag._tags import Origin, TrustedAsTemplate, SourceWasEncrypted
|
21
21
|
from ansible.module_utils._internal._datatag import AnsibleTagHelper
|
@@ -81,12 +81,12 @@ class DataLoader:
|
|
81
81
|
def load(
|
82
82
|
self,
|
83
83
|
data: str,
|
84
|
-
file_name: str | None = None, # DTFIX-
|
85
|
-
show_content: bool = True, # DTFIX-
|
84
|
+
file_name: str | None = None, # DTFIX-FUTURE: consider deprecating this in favor of tagging Origin on data
|
85
|
+
show_content: bool = True, # DTFIX-FUTURE: consider future deprecation, but would need RedactAnnotatedSourceContext public
|
86
86
|
json_only: bool = False,
|
87
87
|
) -> t.Any:
|
88
88
|
"""Backwards compat for now"""
|
89
|
-
with
|
89
|
+
with _error_utils.RedactAnnotatedSourceContext.when(not show_content):
|
90
90
|
return from_yaml(data=data, file_name=file_name, json_only=json_only)
|
91
91
|
|
92
92
|
def load_from_file(self, file_name: str, cache: str = 'all', unsafe: bool = False, json_only: bool = False, trusted_as_template: bool = False) -> t.Any:
|
ansible/parsing/mod_args.py
CHANGED
@@ -160,7 +160,7 @@ class ModuleArgsParser:
|
|
160
160
|
final_args = dict()
|
161
161
|
if additional_args:
|
162
162
|
if isinstance(additional_args, (str, EncryptedString)):
|
163
|
-
#
|
163
|
+
# DTFIX5: should this be is_possibly_template?
|
164
164
|
if TemplateEngine().is_template(additional_args):
|
165
165
|
final_args['_variable_params'] = additional_args
|
166
166
|
else:
|
ansible/parsing/plugin_docs.py
CHANGED
@@ -41,7 +41,7 @@ def read_docstring_from_yaml_file(filename, verbose=True, ignore_errors=True):
|
|
41
41
|
file_data = yaml.load(yamlfile, Loader=AnsibleLoader)
|
42
42
|
except Exception as ex:
|
43
43
|
msg = f"Unable to parse yaml file {filename}"
|
44
|
-
# DTFIX-
|
44
|
+
# DTFIX-FUTURE: find a better pattern for this (can we use the new optional error behavior?)
|
45
45
|
if not ignore_errors:
|
46
46
|
raise AnsibleParserError(f'{msg}.') from ex
|
47
47
|
elif verbose:
|
@@ -93,7 +93,7 @@ def read_docstring_from_python_file(filename, verbose=True, ignore_errors=True):
|
|
93
93
|
|
94
94
|
except Exception as ex:
|
95
95
|
msg = f"Unable to parse documentation in python file {filename!r}"
|
96
|
-
# DTFIX-
|
96
|
+
# DTFIX-FUTURE: better pattern to conditionally raise/display
|
97
97
|
if not ignore_errors:
|
98
98
|
raise AnsibleParserError(f'{msg}.') from ex
|
99
99
|
elif verbose:
|
ansible/parsing/utils/yaml.py
CHANGED
@@ -11,7 +11,7 @@ import typing as t
|
|
11
11
|
import yaml
|
12
12
|
|
13
13
|
from ansible.errors import AnsibleJSONParserError
|
14
|
-
from ansible._internal._errors import
|
14
|
+
from ansible._internal._errors import _error_utils
|
15
15
|
from ansible.parsing.vault import VaultSecret
|
16
16
|
from ansible.parsing.yaml.loader import AnsibleLoader
|
17
17
|
from ansible._internal._yaml._errors import AnsibleYAMLParserError
|
@@ -34,7 +34,7 @@ def from_yaml(
|
|
34
34
|
|
35
35
|
data = origin.tag(data)
|
36
36
|
|
37
|
-
with
|
37
|
+
with _error_utils.RedactAnnotatedSourceContext.when(not show_content):
|
38
38
|
try:
|
39
39
|
# we first try to load this data as JSON.
|
40
40
|
# Fixes issues with extra vars json strings not being parsed correctly by the yaml parser
|
@@ -48,6 +48,6 @@ def from_yaml(
|
|
48
48
|
try:
|
49
49
|
return yaml.load(data, Loader=AnsibleLoader) # type: ignore[arg-type]
|
50
50
|
except Exception as yaml_ex:
|
51
|
-
# DTFIX-
|
51
|
+
# DTFIX-FUTURE: how can we indicate in Origin that the data is in-memory only, to support context information -- is that useful?
|
52
52
|
# we'd need to pass data to handle_exception so it could be used as the content instead of reading from disk
|
53
53
|
AnsibleYAMLParserError.handle_exception(yaml_ex, origin=origin)
|
@@ -149,7 +149,7 @@ def _parse_vaulttext_envelope(b_vaulttext_envelope, default_vault_id=None):
|
|
149
149
|
vault_id = to_text(b_tmpheader[3].strip())
|
150
150
|
|
151
151
|
b_ciphertext = b''.join(b_tmpdata[1:])
|
152
|
-
#
|
152
|
+
# DTFIX7: possible candidate for propagate_origin
|
153
153
|
b_ciphertext = AnsibleTagHelper.tag_copy(b_vaulttext_envelope, b_ciphertext)
|
154
154
|
|
155
155
|
return b_ciphertext, b_version, cipher_name, vault_id
|
@@ -222,7 +222,7 @@ def format_vaulttext_envelope(b_ciphertext, cipher_name, version=None, vault_id=
|
|
222
222
|
|
223
223
|
def _unhexlify(b_data):
|
224
224
|
try:
|
225
|
-
#
|
225
|
+
# DTFIX7: possible candidate for propagate_origin
|
226
226
|
return AnsibleTagHelper.tag_copy(b_data, unhexlify(b_data))
|
227
227
|
except (BinasciiError, TypeError) as ex:
|
228
228
|
raise AnsibleVaultFormatError('Vault format unhexlify error.', obj=b_data) from ex
|
@@ -712,7 +712,7 @@ class VaultLib:
|
|
712
712
|
# secret = self.secrets[vault_secret_id]
|
713
713
|
display.vvvv(u'Trying secret %s for vault_id=%s' % (to_text(vault_secret), to_text(vault_secret_id)))
|
714
714
|
b_plaintext = this_cipher.decrypt(b_vaulttext, vault_secret)
|
715
|
-
#
|
715
|
+
# DTFIX7: possible candidate for propagate_origin
|
716
716
|
b_plaintext = AnsibleTagHelper.tag_copy(vaulttext, b_plaintext)
|
717
717
|
if b_plaintext is not None:
|
718
718
|
vault_id_used = vault_secret_id
|
@@ -1520,7 +1520,7 @@ class VaultHelper:
|
|
1520
1520
|
tags = AnsibleTagHelper.tags(ciphertext) # ciphertext has tags but value does not
|
1521
1521
|
elif value_type is EncryptedString:
|
1522
1522
|
ciphertext = value._ciphertext
|
1523
|
-
elif value_type in _jinja_common.Marker.
|
1523
|
+
elif value_type in _jinja_common.Marker._concrete_subclasses: # avoid wasteful raise/except of Marker when calling get_tag below
|
1524
1524
|
ciphertext = None
|
1525
1525
|
elif vaulted_value := VaultedValue.get_tag(value):
|
1526
1526
|
ciphertext = vaulted_value.ciphertext
|
@@ -164,5 +164,5 @@ class PlaybookInclude(Base, Conditional, Taggable):
|
|
164
164
|
if len(items) == 0:
|
165
165
|
raise AnsibleParserError("import_playbook statements must specify the file name to import", obj=ds)
|
166
166
|
|
167
|
-
#
|
167
|
+
# DTFIX3: investigate this as a possible "problematic strip"
|
168
168
|
new_ds['import_playbook'] = AnsibleTagHelper.tag_copy(v, items[0].strip())
|