ansible-core 2.19.0b5__py3-none-any.whl → 2.19.0b7__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/_ansiballz/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/{_ansiballz.py → _ansiballz/_wrapper.py} +11 -11
- ansible/_internal/_templating/_jinja_bits.py +22 -4
- ansible/_internal/_templating/_jinja_common.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +5 -2
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +6 -0
- ansible/_internal/_yaml/_constructor.py +4 -4
- ansible/_internal/_yaml/_dumper.py +26 -18
- ansible/cli/__init__.py +9 -14
- ansible/cli/adhoc.py +6 -3
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/console.py +2 -2
- ansible/cli/doc.py +4 -4
- ansible/cli/inventory.py +5 -7
- ansible/config/base.yml +33 -6
- ansible/errors/__init__.py +2 -1
- ansible/executor/module_common.py +75 -44
- ansible/executor/powershell/psrp_put_file.ps1 +1 -1
- ansible/executor/process/worker.py +2 -2
- ansible/executor/task_executor.py +2 -2
- ansible/executor/task_queue_manager.py +34 -70
- ansible/executor/task_result.py +1 -1
- ansible/galaxy/api.py +3 -6
- ansible/galaxy/collection/__init__.py +1 -6
- ansible/galaxy/collection/concrete_artifact_manager.py +4 -10
- ansible/galaxy/dependency_resolution/providers.py +3 -3
- ansible/galaxy/role.py +2 -2
- ansible/inventory/group.py +6 -1
- ansible/inventory/host.py +6 -1
- ansible/module_utils/_internal/__init__.py +7 -4
- ansible/module_utils/_internal/_ansiballz/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/__init__.py +0 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_coverage.py +45 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +62 -0
- ansible/module_utils/_internal/{_ansiballz.py → _ansiballz/_loader.py} +10 -38
- ansible/module_utils/_internal/_ansiballz/_respawn.py +32 -0
- ansible/module_utils/_internal/_ansiballz/_respawn_wrapper.py +23 -0
- ansible/module_utils/_internal/_datatag/__init__.py +23 -1
- ansible/module_utils/_internal/_deprecator.py +39 -34
- ansible/module_utils/_internal/_json/_profiles/__init__.py +1 -0
- ansible/module_utils/_internal/_messages.py +26 -2
- ansible/module_utils/_internal/_plugin_info.py +14 -1
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +58 -70
- ansible/module_utils/common/respawn.py +4 -41
- ansible/module_utils/common/yaml.py +1 -1
- ansible/module_utils/connection.py +8 -11
- ansible/module_utils/csharp/Ansible.Basic.cs +1 -1
- ansible/module_utils/csharp/Ansible.Privilege.cs +2 -2
- ansible/module_utils/facts/hardware/base.py +1 -1
- ansible/module_utils/facts/hardware/linux.py +1 -1
- ansible/module_utils/facts/other/facter.py +1 -1
- ansible/module_utils/facts/sysctl.py +4 -6
- ansible/module_utils/facts/system/caps.py +2 -2
- ansible/module_utils/facts/system/distribution.py +2 -2
- ansible/module_utils/facts/system/local.py +1 -1
- ansible/module_utils/facts/virtual/linux.py +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.AddType.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CamelConversion.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.CommandUtil.psm1 +1 -1
- ansible/module_utils/powershell/Ansible.ModuleUtils.WebRequest.psm1 +1 -1
- ansible/module_utils/service.py +1 -1
- ansible/module_utils/urls.py +5 -5
- ansible/modules/apt.py +9 -3
- ansible/modules/apt_repository.py +10 -10
- ansible/modules/assemble.py +7 -5
- ansible/modules/async_wrapper.py +7 -17
- ansible/modules/command.py +3 -3
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +1 -1
- ansible/modules/expect.py +5 -5
- ansible/modules/file.py +16 -17
- ansible/modules/find.py +3 -3
- ansible/modules/get_url.py +17 -0
- ansible/modules/git.py +9 -7
- ansible/modules/hostname.py +2 -2
- ansible/modules/known_hosts.py +12 -14
- ansible/modules/package.py +6 -0
- ansible/modules/pip.py +9 -11
- ansible/modules/raw.py +2 -2
- ansible/modules/replace.py +2 -2
- ansible/modules/slurp.py +10 -13
- ansible/modules/stat.py +6 -8
- ansible/modules/unarchive.py +6 -6
- ansible/modules/user.py +1 -1
- ansible/modules/wait_for.py +38 -33
- ansible/modules/yum_repository.py +4 -3
- ansible/parsing/dataloader.py +2 -2
- ansible/parsing/mod_args.py +38 -20
- ansible/parsing/vault/__init__.py +9 -13
- ansible/playbook/base.py +7 -4
- ansible/playbook/helpers.py +1 -1
- ansible/playbook/included_file.py +3 -1
- ansible/playbook/play_context.py +2 -0
- ansible/playbook/playbook_include.py +23 -56
- ansible/playbook/role/__init__.py +38 -21
- ansible/playbook/taggable.py +19 -5
- ansible/playbook/task.py +2 -0
- ansible/plugins/action/__init__.py +2 -2
- ansible/plugins/action/assemble.py +2 -1
- ansible/plugins/action/assert.py +2 -2
- ansible/plugins/action/fetch.py +3 -3
- ansible/plugins/action/script.py +5 -4
- ansible/plugins/action/template.py +9 -3
- ansible/plugins/cache/__init__.py +17 -19
- ansible/plugins/callback/__init__.py +77 -87
- ansible/plugins/callback/default.py +0 -3
- ansible/plugins/callback/junit.py +0 -6
- ansible/plugins/callback/tree.py +5 -5
- ansible/plugins/connection/local.py +4 -4
- ansible/plugins/connection/paramiko_ssh.py +5 -5
- ansible/plugins/connection/ssh.py +9 -7
- ansible/plugins/connection/winrm.py +1 -1
- ansible/plugins/filter/core.py +19 -21
- ansible/plugins/filter/encryption.py +10 -2
- ansible/plugins/filter/pow.yml +1 -1
- ansible/plugins/filter/root.yml +1 -1
- ansible/plugins/filter/strftime.yml +3 -3
- ansible/plugins/filter/to_uuid.yml +1 -1
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +5 -4
- ansible/plugins/loader.py +5 -0
- ansible/plugins/lookup/password.py +4 -6
- ansible/plugins/lookup/template.py +9 -4
- ansible/plugins/shell/powershell.py +3 -2
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +3 -3
- ansible/plugins/test/core.py +2 -2
- ansible/release.py +1 -1
- ansible/template/__init__.py +9 -53
- ansible/utils/collection_loader/_collection_finder.py +3 -3
- ansible/utils/display.py +38 -37
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +6 -7
- ansible/utils/path.py +6 -8
- ansible/utils/py3compat.py +2 -1
- ansible/utils/ssh_functions.py +3 -2
- ansible/utils/vars.py +4 -1
- ansible/vars/manager.py +6 -3
- ansible/vars/plugins.py +3 -3
- ansible/vars/reserved.py +6 -4
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/RECORD +184 -173
- ansible_test/_internal/__init__.py +5 -0
- ansible_test/_internal/ansible_util.py +1 -1
- ansible_test/_internal/classification/python.py +6 -0
- ansible_test/_internal/cli/commands/__init__.py +0 -5
- ansible_test/_internal/cli/environments.py +51 -5
- ansible_test/_internal/commands/coverage/__init__.py +1 -1
- ansible_test/_internal/commands/integration/__init__.py +18 -5
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +7 -2
- ansible_test/_internal/commands/sanity/__init__.py +3 -1
- ansible_test/_internal/commands/sanity/integration_aliases.py +11 -0
- ansible_test/_internal/commands/shell/__init__.py +43 -4
- ansible_test/_internal/commands/units/__init__.py +4 -1
- ansible_test/_internal/config.py +21 -13
- ansible_test/_internal/debugging.py +166 -0
- ansible_test/_internal/delegation.py +21 -13
- ansible_test/_internal/host_profiles.py +259 -16
- ansible_test/_internal/inventory.py +4 -0
- ansible_test/_internal/metadata.py +94 -4
- ansible_test/_internal/processes.py +80 -0
- ansible_test/_internal/provisioning.py +10 -4
- ansible_test/_internal/python_requirements.py +27 -0
- ansible_test/_internal/ssh.py +1 -5
- ansible_test/_internal/target.py +8 -0
- ansible_test/_internal/thread.py +2 -1
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +20 -12
- ansible_test/_internal/util_common.py +13 -3
- ansible_test/_util/target/injector/python.py +8 -0
- ansible_test/_util/target/setup/requirements.py +3 -9
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b5.dist-info → ansible_core-2.19.0b7.dist-info}/top_level.txt +0 -0
ansible/module_utils/service.py
CHANGED
@@ -286,7 +286,7 @@ def is_systemd_managed(module):
|
|
286
286
|
with open('/proc/1/comm', 'r') as init_proc:
|
287
287
|
init = init_proc.readline().strip()
|
288
288
|
return init == 'systemd'
|
289
|
-
except
|
289
|
+
except OSError:
|
290
290
|
# If comm doesn't exist, old kernel, no systemd
|
291
291
|
return False
|
292
292
|
|
ansible/module_utils/urls.py
CHANGED
@@ -580,7 +580,7 @@ def get_ca_certs(cafile=None, capath=None):
|
|
580
580
|
cadata[b_der] = None
|
581
581
|
except Exception:
|
582
582
|
continue
|
583
|
-
except
|
583
|
+
except OSError:
|
584
584
|
pass
|
585
585
|
|
586
586
|
# paths_checked isn't used any more, but is kept just for ease of debugging
|
@@ -694,7 +694,7 @@ def _configure_auth(url, url_username, url_password, use_gssapi, force_basic_aut
|
|
694
694
|
try:
|
695
695
|
rc = netrc.netrc(os.environ.get('NETRC'))
|
696
696
|
login = rc.authenticators(parsed.hostname)
|
697
|
-
except
|
697
|
+
except OSError:
|
698
698
|
login = None
|
699
699
|
|
700
700
|
if login:
|
@@ -1155,7 +1155,7 @@ def url_argument_spec():
|
|
1155
1155
|
|
1156
1156
|
def url_redirect_argument_spec():
|
1157
1157
|
"""
|
1158
|
-
Creates an addition
|
1158
|
+
Creates an addition argument spec to `url_argument_spec`
|
1159
1159
|
for `follow_redirects` argument
|
1160
1160
|
"""
|
1161
1161
|
return dict(
|
@@ -1303,8 +1303,8 @@ def fetch_url(module, url, data=None, headers=None, method=None,
|
|
1303
1303
|
except urllib.error.URLError as e:
|
1304
1304
|
code = int(getattr(e, 'code', -1))
|
1305
1305
|
info.update(dict(msg="Request failed: %s" % to_native(e), status=code))
|
1306
|
-
except
|
1307
|
-
info.update(dict(msg="Connection failure:
|
1306
|
+
except OSError as ex:
|
1307
|
+
info.update(dict(msg=f"Connection failure: {ex}", status=-1))
|
1308
1308
|
except http.client.BadStatusLine as e:
|
1309
1309
|
info.update(dict(msg="Connection failure: connection was closed before a valid response was received: %s" % to_native(e.line), status=-1))
|
1310
1310
|
except Exception as ex:
|
ansible/modules/apt.py
CHANGED
@@ -855,6 +855,7 @@ def install_deb(
|
|
855
855
|
allow_downgrade,
|
856
856
|
allow_change_held_packages,
|
857
857
|
dpkg_options,
|
858
|
+
lock_timeout,
|
858
859
|
):
|
859
860
|
changed = False
|
860
861
|
deps_to_install = []
|
@@ -903,13 +904,14 @@ def install_deb(
|
|
903
904
|
# install the deps through apt
|
904
905
|
retvals = {}
|
905
906
|
if deps_to_install:
|
907
|
+
install_dpkg_options = f"{expand_dpkg_options(dpkg_options)} -o DPkg::Lock::Timeout={lock_timeout}"
|
906
908
|
(success, retvals) = install(m=m, pkgspec=deps_to_install, cache=cache,
|
907
909
|
install_recommends=install_recommends,
|
908
910
|
fail_on_autoremove=fail_on_autoremove,
|
909
911
|
allow_unauthenticated=allow_unauthenticated,
|
910
912
|
allow_downgrade=allow_downgrade,
|
911
913
|
allow_change_held_packages=allow_change_held_packages,
|
912
|
-
dpkg_options=
|
914
|
+
dpkg_options=install_dpkg_options)
|
913
915
|
if not success:
|
914
916
|
m.fail_json(**retvals)
|
915
917
|
changed = retvals.get('changed', False)
|
@@ -1269,7 +1271,7 @@ def main():
|
|
1269
1271
|
|
1270
1272
|
p = module.params
|
1271
1273
|
install_recommends = p['install_recommends']
|
1272
|
-
dpkg_options = expand_dpkg_options(p['dpkg_options'])
|
1274
|
+
dpkg_options = f"{expand_dpkg_options(p['dpkg_options'])} -o DPkg::Lock::Timeout={p['lock_timeout']}"
|
1273
1275
|
|
1274
1276
|
if not HAS_PYTHON_APT:
|
1275
1277
|
# This interpreter can't see the apt Python library- we'll do the following to try and fix that:
|
@@ -1470,7 +1472,11 @@ def main():
|
|
1470
1472
|
allow_unauthenticated=allow_unauthenticated,
|
1471
1473
|
allow_change_held_packages=allow_change_held_packages,
|
1472
1474
|
allow_downgrade=allow_downgrade,
|
1473
|
-
force=force_yes,
|
1475
|
+
force=force_yes,
|
1476
|
+
fail_on_autoremove=fail_on_autoremove,
|
1477
|
+
dpkg_options=p['dpkg_options'],
|
1478
|
+
lock_timeout=p['lock_timeout']
|
1479
|
+
)
|
1474
1480
|
|
1475
1481
|
unfiltered_packages = p['package'] or ()
|
1476
1482
|
packages = [package.strip() for package in unfiltered_packages if package != '*']
|
@@ -333,8 +333,8 @@ class SourcesList(object):
|
|
333
333
|
|
334
334
|
try:
|
335
335
|
fd, tmp_path = tempfile.mkstemp(prefix=".%s-" % fn, dir=d)
|
336
|
-
except
|
337
|
-
|
336
|
+
except OSError as ex:
|
337
|
+
raise Exception(f'Unable to create temp file at {d!r} for apt source.') from ex
|
338
338
|
|
339
339
|
f = os.fdopen(fd, 'w')
|
340
340
|
for n, valid, enabled, source, comment in sources:
|
@@ -350,8 +350,8 @@ class SourcesList(object):
|
|
350
350
|
|
351
351
|
try:
|
352
352
|
f.write(line)
|
353
|
-
except
|
354
|
-
|
353
|
+
except OSError as ex:
|
354
|
+
raise Exception(f"Failed to write to file {tmp_path!r}.") from ex
|
355
355
|
if filename in self.files_mapping:
|
356
356
|
# Write to symlink target instead of replacing symlink as a normal file
|
357
357
|
self.module.atomic_move(tmp_path, self.files_mapping[filename])
|
@@ -507,8 +507,8 @@ class UbuntuSourcesList(SourcesList):
|
|
507
507
|
if os.path.exists(key_file):
|
508
508
|
try:
|
509
509
|
rc, out, err = self.module.run_command([self.gpg_bin, '--list-packets', key_file])
|
510
|
-
except
|
511
|
-
self.debug("Could check key against file
|
510
|
+
except OSError as ex:
|
511
|
+
self.debug(f"Could check key against file {key_file!r}: {ex}")
|
512
512
|
continue
|
513
513
|
|
514
514
|
if key_fingerprint in out:
|
@@ -557,8 +557,8 @@ class UbuntuSourcesList(SourcesList):
|
|
557
557
|
with open(keyfile, 'wb') as f:
|
558
558
|
f.write(stdout)
|
559
559
|
self.module.log('Added repo key "%s" for apt to file "%s"' % (info['signing_key_fingerprint'], keyfile))
|
560
|
-
except
|
561
|
-
self.module.fail_json(msg='Unable to add required signing key
|
560
|
+
except OSError as ex:
|
561
|
+
self.module.fail_json(msg='Unable to add required signing key.', rc=rc, stderr=stderr, error=str(ex), exception=ex)
|
562
562
|
|
563
563
|
# apt source file
|
564
564
|
file = file or self._suggest_filename('%s_%s' % (line, self.codename))
|
@@ -752,9 +752,9 @@ def main():
|
|
752
752
|
)
|
753
753
|
module.fail_json(msg=msg)
|
754
754
|
|
755
|
-
except
|
755
|
+
except OSError as ex:
|
756
756
|
revert_sources_list(sources_before, sources_after, sourceslist_before)
|
757
|
-
|
757
|
+
raise
|
758
758
|
|
759
759
|
module.exit_json(changed=changed, repo=repo, sources_added=sources_added, sources_removed=sources_removed, state=state, diff=diff)
|
760
760
|
|
ansible/modules/assemble.py
CHANGED
@@ -80,7 +80,7 @@ attributes:
|
|
80
80
|
bypass_host_loop:
|
81
81
|
support: none
|
82
82
|
check_mode:
|
83
|
-
support:
|
83
|
+
support: full
|
84
84
|
diff_mode:
|
85
85
|
support: full
|
86
86
|
platform:
|
@@ -186,10 +186,10 @@ def cleanup(module, path, result=None):
|
|
186
186
|
if os.path.exists(path):
|
187
187
|
try:
|
188
188
|
os.remove(path)
|
189
|
-
except
|
189
|
+
except OSError as ex:
|
190
190
|
# don't error on possible race conditions, but keep warning
|
191
191
|
if result is not None:
|
192
|
-
module.
|
192
|
+
module.error_as_warning(f'Unable to remove temp file {path!r}.', exception=ex)
|
193
193
|
|
194
194
|
|
195
195
|
def main():
|
@@ -212,6 +212,7 @@ def main():
|
|
212
212
|
decrypt=dict(type='bool', default=True),
|
213
213
|
),
|
214
214
|
add_file_common_args=True,
|
215
|
+
supports_check_mode=True,
|
215
216
|
)
|
216
217
|
|
217
218
|
changed = False
|
@@ -266,12 +267,13 @@ def main():
|
|
266
267
|
if backup and dest_hash is not None:
|
267
268
|
result['backup_file'] = module.backup_local(dest)
|
268
269
|
|
269
|
-
|
270
|
+
if not module.check_mode:
|
271
|
+
module.atomic_move(path, dest, unsafe_writes=module.params['unsafe_writes'])
|
270
272
|
changed = True
|
271
273
|
|
272
274
|
cleanup(module, path, result)
|
273
275
|
|
274
|
-
# handle file permissions
|
276
|
+
# handle file permissions (check mode aware)
|
275
277
|
file_args = module.load_file_common_arguments(module.params)
|
276
278
|
result['changed'] = module.set_fs_attributes_if_different(file_args, changed)
|
277
279
|
|
ansible/modules/async_wrapper.py
CHANGED
@@ -6,7 +6,6 @@
|
|
6
6
|
from __future__ import annotations
|
7
7
|
|
8
8
|
|
9
|
-
import errno
|
10
9
|
import json
|
11
10
|
import shlex
|
12
11
|
import shutil
|
@@ -122,24 +121,14 @@ def _get_interpreter(module_path):
|
|
122
121
|
return head[2:head.index(b'\n')].strip().split(b' ')
|
123
122
|
|
124
123
|
|
125
|
-
def _make_temp_dir(path):
|
126
|
-
# TODO: Add checks for permissions on path.
|
127
|
-
try:
|
128
|
-
os.makedirs(path)
|
129
|
-
except OSError as e:
|
130
|
-
if e.errno != errno.EEXIST:
|
131
|
-
raise
|
132
|
-
|
133
|
-
|
134
124
|
def jwrite(info):
|
135
|
-
|
136
125
|
jobfile = job_path + ".tmp"
|
137
126
|
tjob = open(jobfile, "w")
|
138
127
|
try:
|
139
128
|
tjob.write(json.dumps(info))
|
140
|
-
except
|
141
|
-
notice('failed to write to
|
142
|
-
raise
|
129
|
+
except OSError as ex:
|
130
|
+
notice(f'failed to write to {jobfile!r}: {ex}')
|
131
|
+
raise
|
143
132
|
finally:
|
144
133
|
tjob.close()
|
145
134
|
os.rename(jobfile, job_path)
|
@@ -200,7 +189,7 @@ def _run_module(wrapped_cmd, jid):
|
|
200
189
|
result['stderr'] = stderr
|
201
190
|
jwrite(result)
|
202
191
|
|
203
|
-
except
|
192
|
+
except OSError:
|
204
193
|
e = sys.exc_info()[1]
|
205
194
|
result = {
|
206
195
|
"failed": True,
|
@@ -212,7 +201,7 @@ def _run_module(wrapped_cmd, jid):
|
|
212
201
|
result['ansible_job_id'] = jid
|
213
202
|
jwrite(result)
|
214
203
|
|
215
|
-
except
|
204
|
+
except Exception:
|
216
205
|
result = {
|
217
206
|
"failed": True,
|
218
207
|
"cmd": wrapped_cmd,
|
@@ -257,7 +246,8 @@ def main():
|
|
257
246
|
job_path = os.path.join(jobdir, jid)
|
258
247
|
|
259
248
|
try:
|
260
|
-
|
249
|
+
# TODO: Add checks for permissions on path.
|
250
|
+
os.makedirs(jobdir, exist_ok=True)
|
261
251
|
except Exception as e:
|
262
252
|
end({
|
263
253
|
"failed": True,
|
ansible/modules/command.py
CHANGED
@@ -299,9 +299,9 @@ def main():
|
|
299
299
|
|
300
300
|
try:
|
301
301
|
os.chdir(chdir)
|
302
|
-
except
|
303
|
-
r['msg'] = 'Unable to change directory before execution
|
304
|
-
module.fail_json(**r)
|
302
|
+
except OSError as ex:
|
303
|
+
r['msg'] = 'Unable to change directory before execution.'
|
304
|
+
module.fail_json(**r, exception=ex)
|
305
305
|
|
306
306
|
# check_mode partial support, since it only really works in checking creates/removes
|
307
307
|
if module.check_mode:
|
ansible/modules/copy.py
CHANGED
@@ -522,8 +522,8 @@ def main():
|
|
522
522
|
if os.path.isfile(src):
|
523
523
|
try:
|
524
524
|
checksum_src = module.sha1(src)
|
525
|
-
except
|
526
|
-
module.
|
525
|
+
except OSError as ex:
|
526
|
+
module.error_as_warning("Unable to calculate src checksum, assuming change.", exception=ex)
|
527
527
|
try:
|
528
528
|
# Backwards compat only. This will be None in FIPS mode
|
529
529
|
md5sum_src = module.md5(src)
|
@@ -636,8 +636,8 @@ def main():
|
|
636
636
|
# at this point we should always have tmp file
|
637
637
|
module.atomic_move(b_mysrc, dest, unsafe_writes=module.params['unsafe_writes'], keep_dest_attrs=not remote_src)
|
638
638
|
|
639
|
-
except
|
640
|
-
|
639
|
+
except OSError as ex:
|
640
|
+
raise Exception(f"Failed to copy {src!r} to {dest!r}.") from ex
|
641
641
|
changed = True
|
642
642
|
|
643
643
|
# If neither have checksums, both src and dest are directories.
|
ansible/modules/cron.py
CHANGED
@@ -271,7 +271,7 @@ class CronTab(object):
|
|
271
271
|
with open(self.b_cron_file, 'rb') as f:
|
272
272
|
self.n_existing = to_native(f.read(), errors='surrogate_or_strict')
|
273
273
|
self.lines = self.n_existing.splitlines()
|
274
|
-
except
|
274
|
+
except OSError:
|
275
275
|
# cron file does not exist
|
276
276
|
return
|
277
277
|
except Exception:
|
ansible/modules/expect.py
CHANGED
@@ -218,7 +218,7 @@ def main():
|
|
218
218
|
rc=0
|
219
219
|
)
|
220
220
|
|
221
|
-
|
221
|
+
start_date = datetime.datetime.now()
|
222
222
|
|
223
223
|
try:
|
224
224
|
try:
|
@@ -246,8 +246,8 @@ def main():
|
|
246
246
|
except pexpect.ExceptionPexpect as e:
|
247
247
|
module.fail_json(msg='%s' % to_native(e))
|
248
248
|
|
249
|
-
|
250
|
-
delta =
|
249
|
+
end_date = datetime.datetime.now()
|
250
|
+
delta = end_date - start_date
|
251
251
|
|
252
252
|
if b_out is None:
|
253
253
|
b_out = b''
|
@@ -256,8 +256,8 @@ def main():
|
|
256
256
|
cmd=args,
|
257
257
|
stdout=to_native(b_out).rstrip('\r\n'),
|
258
258
|
rc=rc,
|
259
|
-
start=str(
|
260
|
-
end=str(
|
259
|
+
start=str(start_date),
|
260
|
+
end=str(end_date),
|
261
261
|
delta=str(delta),
|
262
262
|
changed=True,
|
263
263
|
)
|
ansible/modules/file.py
CHANGED
@@ -323,11 +323,8 @@ def get_state(path):
|
|
323
323
|
return 'file'
|
324
324
|
|
325
325
|
return 'absent'
|
326
|
-
except
|
327
|
-
|
328
|
-
return 'absent'
|
329
|
-
else:
|
330
|
-
raise
|
326
|
+
except FileNotFoundError:
|
327
|
+
return 'absent'
|
331
328
|
|
332
329
|
|
333
330
|
# This should be moved into the common file utilities
|
@@ -527,12 +524,14 @@ def ensure_absent(path):
|
|
527
524
|
else:
|
528
525
|
try:
|
529
526
|
os.unlink(b_path)
|
530
|
-
except
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
527
|
+
except FileNotFoundError:
|
528
|
+
pass
|
529
|
+
except OSError as ex:
|
530
|
+
module.fail_json(
|
531
|
+
msg="Unlinking failed.",
|
532
|
+
path=path,
|
533
|
+
exception=ex,
|
534
|
+
)
|
536
535
|
|
537
536
|
result.update({'path': path, 'changed': True, 'diff': diff, 'state': 'absent'})
|
538
537
|
else:
|
@@ -560,10 +559,11 @@ def execute_touch(path, follow, timestamps):
|
|
560
559
|
try:
|
561
560
|
open(b_path, 'wb').close()
|
562
561
|
changed = True
|
563
|
-
except
|
562
|
+
except OSError as ex:
|
564
563
|
module.fail_json(
|
565
|
-
msg=
|
566
|
-
path=path
|
564
|
+
msg="Error, could not touch target.",
|
565
|
+
path=path,
|
566
|
+
exception=ex,
|
567
567
|
)
|
568
568
|
# Update the attributes on the file
|
569
569
|
diff = initial_diff(path, 'touch', prev_state)
|
@@ -894,9 +894,8 @@ def ensure_hardlink(path, src, follow, force, timestamps):
|
|
894
894
|
if os.path.exists(b_path):
|
895
895
|
try:
|
896
896
|
os.unlink(b_path)
|
897
|
-
except
|
898
|
-
|
899
|
-
raise
|
897
|
+
except FileNotFoundError:
|
898
|
+
pass
|
900
899
|
os.link(b_src, b_tmppath)
|
901
900
|
os.rename(b_tmppath, b_path)
|
902
901
|
except OSError as e:
|
ansible/modules/find.py
CHANGED
@@ -571,9 +571,9 @@ def main():
|
|
571
571
|
|
572
572
|
try:
|
573
573
|
st = os.lstat(fsname)
|
574
|
-
except
|
575
|
-
module.
|
576
|
-
skipped[fsname] =
|
574
|
+
except OSError as ex:
|
575
|
+
module.error_as_warning(f"Skipped entry {fsname!r} due to access issue.", exception=ex)
|
576
|
+
skipped[fsname] = str(ex)
|
577
577
|
has_warnings = True
|
578
578
|
continue
|
579
579
|
|
ansible/modules/get_url.py
CHANGED
@@ -436,6 +436,23 @@ def url_get(module, url, dest, use_proxy, last_mod_time, force, timeout=10, head
|
|
436
436
|
module.fail_json(msg="failed to create temporary content file: %s" % to_native(e), elapsed=elapsed)
|
437
437
|
f.close()
|
438
438
|
rsp.close()
|
439
|
+
|
440
|
+
# Since shutil.copyfileobj() will read from HTTPResponse in chunks, HTTPResponse.read() will not recognize
|
441
|
+
# if the entire content-length of data was not read. We need to do that validation here, unless a 'chunked'
|
442
|
+
# transfer-encoding was used, in which case we will not know content-length because it will not be returned.
|
443
|
+
# But in that case, HTTPResponse will behave correctly and recognize an IncompleteRead.
|
444
|
+
|
445
|
+
is_gzip = info.get('content-encoding') == 'gzip'
|
446
|
+
|
447
|
+
if not module.check_mode and 'content-length' in info:
|
448
|
+
# If data is decompressed, then content-length won't match the amount of data we've read, so skip.
|
449
|
+
if not is_gzip or (is_gzip and not decompress):
|
450
|
+
st = os.stat(tempname)
|
451
|
+
cl = int(info['content-length'])
|
452
|
+
if st.st_size != cl:
|
453
|
+
diff = cl - st.st_size
|
454
|
+
module.fail_json(msg=f'Incomplete read, ({rsp.length=}, {cl=}, {st.st_size=}) failed to read remaining {diff} bytes')
|
455
|
+
|
439
456
|
return tempname, info
|
440
457
|
|
441
458
|
|
ansible/modules/git.py
CHANGED
@@ -357,11 +357,11 @@ def relocate_repo(module, result, repo_dir, old_repo_dir, worktree_dir):
|
|
357
357
|
dot_git_file.write('gitdir: %s' % repo_dir)
|
358
358
|
result['git_dir_before'] = old_repo_dir
|
359
359
|
result['git_dir_now'] = repo_dir
|
360
|
-
except
|
360
|
+
except OSError as ex:
|
361
361
|
# if we already moved the .git dir, roll it back
|
362
362
|
if os.path.exists(repo_dir):
|
363
363
|
shutil.move(repo_dir, old_repo_dir)
|
364
|
-
|
364
|
+
raise Exception('Unable to move git dir.') from ex
|
365
365
|
|
366
366
|
|
367
367
|
def head_splitter(headfile, remote, module=None, fail_on_error=False):
|
@@ -439,7 +439,7 @@ def write_ssh_wrapper(module):
|
|
439
439
|
fd, wrapper_path = tempfile.mkstemp(prefix=module.tmpdir + '/')
|
440
440
|
else:
|
441
441
|
raise OSError
|
442
|
-
except
|
442
|
+
except OSError:
|
443
443
|
fd, wrapper_path = tempfile.mkstemp()
|
444
444
|
|
445
445
|
# use existing git_ssh/ssh_command, fallback to 'ssh'
|
@@ -824,13 +824,14 @@ def get_head_branch(git_path, module, dest, remote, bare=False):
|
|
824
824
|
"""
|
825
825
|
try:
|
826
826
|
repo_path = get_repo_path(dest, bare)
|
827
|
-
except (
|
827
|
+
except (OSError, ValueError) as ex:
|
828
828
|
# No repo path found
|
829
829
|
# ``.git`` file does not have a valid format for detached Git dir.
|
830
830
|
module.fail_json(
|
831
831
|
msg='Current repo does not have a valid reference to a '
|
832
832
|
'separate Git dir or it refers to the invalid path',
|
833
|
-
details=
|
833
|
+
details=str(ex),
|
834
|
+
exception=ex,
|
834
835
|
)
|
835
836
|
# Read .git/HEAD for the name of the branch.
|
836
837
|
# If we're in a detached HEAD state, look up the branch associated with
|
@@ -1290,13 +1291,14 @@ def main():
|
|
1290
1291
|
if not module.check_mode:
|
1291
1292
|
relocate_repo(module, result, separate_git_dir, repo_path, dest)
|
1292
1293
|
repo_path = separate_git_dir
|
1293
|
-
except (
|
1294
|
+
except (OSError, ValueError) as ex:
|
1294
1295
|
# No repo path found
|
1295
1296
|
# ``.git`` file does not have a valid format for detached Git dir.
|
1296
1297
|
module.fail_json(
|
1297
1298
|
msg='Current repo does not have a valid reference to a '
|
1298
1299
|
'separate Git dir or it refers to the invalid path',
|
1299
|
-
details=
|
1300
|
+
details=str(ex),
|
1301
|
+
exception=ex,
|
1300
1302
|
)
|
1301
1303
|
gitconfig = os.path.join(repo_path, 'config')
|
1302
1304
|
|
ansible/modules/hostname.py
CHANGED
@@ -608,8 +608,8 @@ class Hostname(object):
|
|
608
608
|
self.use = module.params['use']
|
609
609
|
|
610
610
|
if self.use is not None:
|
611
|
-
|
612
|
-
self.strategy =
|
611
|
+
strategy = globals()['%sStrategy' % STRATS[self.use]]
|
612
|
+
self.strategy = strategy(module)
|
613
613
|
elif platform.system() == 'Linux' and ServiceMgrFactCollector.is_systemd_managed(module):
|
614
614
|
# This is Linux and systemd is active
|
615
615
|
self.strategy = SystemdStrategy(module)
|
ansible/modules/known_hosts.py
CHANGED
@@ -102,7 +102,6 @@ EXAMPLES = r"""
|
|
102
102
|
|
103
103
|
import base64
|
104
104
|
import copy
|
105
|
-
import errno
|
106
105
|
import hashlib
|
107
106
|
import hmac
|
108
107
|
import os
|
@@ -169,11 +168,10 @@ def enforce_state(module, params):
|
|
169
168
|
if replace_or_add or found != (state == "present"):
|
170
169
|
try:
|
171
170
|
inf = open(path, "r")
|
172
|
-
except
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
module.fail_json(msg="Failed to read %s: %s" % (path, str(e)))
|
171
|
+
except FileNotFoundError:
|
172
|
+
inf = None
|
173
|
+
except OSError as ex:
|
174
|
+
raise Exception(f"Failed to read {path!r}.") from ex
|
177
175
|
try:
|
178
176
|
with tempfile.NamedTemporaryFile(mode='w+', dir=os.path.dirname(path), delete=False) as outf:
|
179
177
|
if inf is not None:
|
@@ -184,8 +182,8 @@ def enforce_state(module, params):
|
|
184
182
|
inf.close()
|
185
183
|
if state == 'present':
|
186
184
|
outf.write(key)
|
187
|
-
except
|
188
|
-
|
185
|
+
except OSError as ex:
|
186
|
+
raise Exception(f"Failed to write to file {path!r}.") from ex
|
189
187
|
else:
|
190
188
|
module.atomic_move(outf.name, path)
|
191
189
|
|
@@ -220,9 +218,8 @@ def sanity_check(module, host, key, sshkeygen):
|
|
220
218
|
try:
|
221
219
|
outf.write(key)
|
222
220
|
outf.flush()
|
223
|
-
except
|
224
|
-
|
225
|
-
(outf.name, to_native(e)))
|
221
|
+
except OSError as ex:
|
222
|
+
raise Exception(f"Failed to write to temporary file {outf.name!r}.") from ex
|
226
223
|
|
227
224
|
sshkeygen_command = [sshkeygen, '-F', host, '-f', outf.name]
|
228
225
|
rc, stdout, stderr = module.run_command(sshkeygen_command)
|
@@ -337,9 +334,10 @@ def compute_diff(path, found_line, replace_or_add, state, key):
|
|
337
334
|
}
|
338
335
|
try:
|
339
336
|
inf = open(path, "r")
|
340
|
-
except
|
341
|
-
|
342
|
-
|
337
|
+
except FileNotFoundError:
|
338
|
+
diff['before_header'] = '/dev/null'
|
339
|
+
except OSError:
|
340
|
+
pass
|
343
341
|
else:
|
344
342
|
diff['before'] = inf.read()
|
345
343
|
inf.close()
|
ansible/modules/package.py
CHANGED
ansible/modules/pip.py
CHANGED
@@ -60,7 +60,7 @@ options:
|
|
60
60
|
virtualenv_python:
|
61
61
|
description:
|
62
62
|
- The Python executable used for creating the virtual environment.
|
63
|
-
For example V(python3.
|
63
|
+
For example V(python3.13). When not specified, the
|
64
64
|
Python version used to run the ansible module is used. This parameter
|
65
65
|
should not be used when O(virtualenv_command) is using V(pyvenv) or
|
66
66
|
the C(-m venv) module.
|
@@ -93,8 +93,8 @@ options:
|
|
93
93
|
description:
|
94
94
|
- The explicit executable or pathname for the C(pip) executable,
|
95
95
|
if different from the Ansible Python interpreter. For
|
96
|
-
example V(pip3.
|
97
|
-
in the system and you want to run pip for the Python 3.
|
96
|
+
example V(pip3.13), if there are multiple Python installations
|
97
|
+
in the system and you want to run pip for the Python 3.13 installation.
|
98
98
|
- Mutually exclusive with O(virtualenv) (added in 2.1).
|
99
99
|
- Does not affect the Ansible Python interpreter.
|
100
100
|
- The C(setuptools) package must be installed for both the Ansible Python interpreter
|
@@ -134,7 +134,7 @@ notes:
|
|
134
134
|
the virtualenv needs to be created.
|
135
135
|
- Although it executes using the Ansible Python interpreter, the pip module shells out to
|
136
136
|
run the actual pip command, so it can use any pip version you specify with O(executable).
|
137
|
-
By default, it uses the pip version for the Ansible Python interpreter.
|
137
|
+
By default, it uses the pip version for the Ansible Python interpreter.
|
138
138
|
- The interpreter used by Ansible
|
139
139
|
(see R(ansible_python_interpreter, ansible_python_interpreter))
|
140
140
|
requires the setuptools package, regardless of the version of pip set with
|
@@ -197,11 +197,11 @@ EXAMPLES = """
|
|
197
197
|
virtualenv: /my_app/venv
|
198
198
|
virtualenv_site_packages: yes
|
199
199
|
|
200
|
-
- name: Install bottle into the specified (virtualenv), using Python
|
200
|
+
- name: Install bottle into the specified (virtualenv), using Python 3.13
|
201
201
|
ansible.builtin.pip:
|
202
202
|
name: bottle
|
203
203
|
virtualenv: /my_app/venv
|
204
|
-
virtualenv_command: virtualenv-
|
204
|
+
virtualenv_command: virtualenv-3.13
|
205
205
|
|
206
206
|
- name: Install bottle within a user home directory
|
207
207
|
ansible.builtin.pip:
|
@@ -227,10 +227,10 @@ EXAMPLES = """
|
|
227
227
|
requirements: /my_app/requirements.txt
|
228
228
|
extra_args: "--no-index --find-links=file:///my_downloaded_packages_dir"
|
229
229
|
|
230
|
-
- name: Install bottle for Python 3.
|
230
|
+
- name: Install bottle for Python 3.13 specifically, using the 'pip3.13' executable
|
231
231
|
ansible.builtin.pip:
|
232
232
|
name: bottle
|
233
|
-
executable: pip3.
|
233
|
+
executable: pip3.13
|
234
234
|
|
235
235
|
- name: Install bottle, forcing reinstallation if it's already installed
|
236
236
|
ansible.builtin.pip:
|
@@ -460,9 +460,7 @@ def _get_pip(module, env=None, executable=None):
|
|
460
460
|
candidate_pip_basenames = (executable,)
|
461
461
|
elif executable is None and env is None and _have_pip_module():
|
462
462
|
# If no executable or virtualenv were specified, use the pip module for the current Python interpreter if available.
|
463
|
-
|
464
|
-
# Without it Python 2.6 gives the following error: pip is a package and cannot be directly executed
|
465
|
-
pip = [sys.executable, '-m', 'pip.__main__']
|
463
|
+
pip = [sys.executable, '-m', 'pip']
|
466
464
|
|
467
465
|
if pip is None:
|
468
466
|
if env is None:
|
ansible/modules/raw.py
CHANGED
@@ -73,8 +73,8 @@ author:
|
|
73
73
|
"""
|
74
74
|
|
75
75
|
EXAMPLES = r"""
|
76
|
-
- name: Bootstrap a host without
|
77
|
-
ansible.builtin.raw: dnf install -y
|
76
|
+
- name: Bootstrap a host without Python installed
|
77
|
+
ansible.builtin.raw: dnf install -y python3 python3-libdnf
|
78
78
|
|
79
79
|
- name: Run a command that uses non-posix shell-isms (in this example /bin/sh doesn't handle redirection and wildcards together but bash does)
|
80
80
|
ansible.builtin.raw: cat < /tmp/*txt
|