ansible-core 2.19.0b4__py3-none-any.whl → 2.19.0b6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansible/_internal/__init__.py +1 -1
- ansible/_internal/_ansiballz/__init__.py +0 -0
- ansible/_internal/_ansiballz/_builder.py +101 -0
- ansible/_internal/{_ansiballz.py → _ansiballz/_wrapper.py} +11 -11
- 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 +5 -5
- 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 +28 -20
- ansible/_internal/_templating/_jinja_common.py +18 -27
- ansible/_internal/_templating/_jinja_plugins.py +36 -5
- ansible/_internal/_templating/_lazy_containers.py +5 -5
- ansible/_internal/_templating/_template_vars.py +72 -0
- ansible/_internal/_templating/_transform.py +26 -19
- ansible/_internal/_templating/_utils.py +1 -1
- ansible/_internal/_yaml/_constructor.py +4 -4
- ansible/_internal/_yaml/_dumper.py +26 -18
- 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 +11 -93
- ansible/cli/arguments/option_helpers.py +3 -4
- ansible/cli/console.py +1 -1
- ansible/cli/doc.py +86 -30
- ansible/cli/inventory.py +5 -7
- ansible/compat/importlib_resources.py +9 -12
- ansible/config/base.yml +46 -0
- ansible/errors/__init__.py +98 -50
- ansible/executor/module_common.py +75 -49
- 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 +40 -115
- ansible/executor/task_executor.py +26 -61
- ansible/executor/task_result.py +2 -4
- ansible/galaxy/api.py +1 -4
- ansible/galaxy/collection/__init__.py +2 -10
- ansible/galaxy/collection/concrete_artifact_manager.py +2 -8
- ansible/galaxy/role.py +2 -2
- ansible/inventory/manager.py +1 -1
- ansible/module_utils/_internal/__init__.py +7 -7
- ansible/module_utils/_internal/_ambient_context.py +3 -3
- 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} +13 -39
- 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 +43 -15
- ansible/module_utils/_internal/_datatag/_tags.py +2 -2
- ansible/module_utils/_internal/_deprecator.py +67 -55
- 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 +22 -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} +54 -49
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +1 -3
- ansible/module_utils/_internal/_plugin_info.py +15 -2
- 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 +95 -71
- 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/respawn.py +4 -41
- 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/connection.py +8 -11
- ansible/module_utils/datatag.py +5 -2
- ansible/module_utils/facts/hardware/linux.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 +16 -3
- ansible/module_utils/facts/system/local.py +1 -1
- ansible/module_utils/facts/virtual/linux.py +2 -2
- ansible/module_utils/service.py +3 -10
- ansible/module_utils/urls.py +4 -4
- ansible/modules/apt_repository.py +17 -39
- ansible/modules/assemble.py +2 -2
- ansible/modules/async_status.py +13 -11
- ansible/modules/async_wrapper.py +12 -22
- ansible/modules/command.py +3 -3
- ansible/modules/copy.py +4 -4
- ansible/modules/cron.py +1 -1
- ansible/modules/dnf5.py +14 -22
- 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 +0 -1
- ansible/modules/known_hosts.py +12 -14
- ansible/modules/package.py +6 -0
- ansible/modules/replace.py +2 -2
- ansible/modules/service.py +3 -9
- ansible/modules/slurp.py +10 -13
- ansible/modules/stat.py +5 -7
- ansible/modules/unarchive.py +6 -6
- ansible/modules/user.py +1 -1
- ansible/modules/wait_for.py +28 -30
- ansible/modules/yum_repository.py +4 -3
- ansible/parsing/ajson.py +3 -5
- ansible/parsing/dataloader.py +6 -6
- 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 +10 -14
- ansible/playbook/base.py +7 -2
- ansible/playbook/included_file.py +3 -1
- ansible/playbook/play_context.py +2 -0
- ansible/playbook/playbook_include.py +1 -1
- ansible/playbook/taggable.py +19 -8
- ansible/playbook/task.py +2 -0
- ansible/plugins/__init__.py +0 -25
- ansible/plugins/action/__init__.py +8 -31
- 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/fetch.py +3 -3
- 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 +11 -10
- ansible/plugins/action/unarchive.py +5 -15
- ansible/plugins/action/uri.py +9 -20
- ansible/plugins/cache/__init__.py +17 -19
- ansible/plugins/callback/__init__.py +4 -6
- ansible/plugins/callback/junit.py +4 -2
- ansible/plugins/callback/tree.py +5 -5
- ansible/plugins/connection/local.py +6 -6
- ansible/plugins/connection/paramiko_ssh.py +5 -5
- ansible/plugins/connection/ssh.py +25 -15
- ansible/plugins/connection/winrm.py +6 -3
- ansible/plugins/doc_fragments/constructed.py +2 -2
- ansible/plugins/filter/core.py +32 -27
- ansible/plugins/filter/encryption.py +14 -6
- ansible/plugins/inventory/__init__.py +11 -10
- ansible/plugins/inventory/script.py +1 -1
- ansible/plugins/list.py +73 -19
- ansible/plugins/loader.py +7 -7
- ansible/plugins/lookup/csvfile.py +16 -71
- ansible/plugins/lookup/first_found.py +2 -1
- ansible/plugins/lookup/template.py +9 -4
- ansible/plugins/shell/__init__.py +56 -2
- ansible/plugins/shell/powershell.py +67 -9
- ansible/plugins/shell/sh.py +10 -5
- ansible/plugins/strategy/__init__.py +3 -3
- ansible/plugins/test/core.py +22 -16
- ansible/plugins/test/finished.yml +1 -1
- ansible/plugins/test/uri.py +2 -5
- ansible/release.py +1 -1
- ansible/template/__init__.py +38 -54
- ansible/utils/collection_loader/_collection_finder.py +3 -3
- ansible/utils/display.py +124 -138
- ansible/utils/galaxy.py +2 -2
- ansible/utils/hashing.py +6 -8
- ansible/utils/listify.py +6 -4
- ansible/utils/path.py +5 -7
- ansible/utils/py3compat.py +2 -1
- ansible/utils/ssh_functions.py +3 -2
- ansible/utils/unsafe_proxy.py +1 -1
- ansible/vars/hostvars.py +1 -1
- ansible/vars/plugins.py +3 -3
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/RECORD +224 -204
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.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/commands/integration/coverage.py +7 -2
- ansible_test/_internal/host_profiles.py +62 -10
- ansible_test/_internal/provisioning.py +10 -4
- ansible_test/_internal/ssh.py +1 -5
- ansible_test/_internal/thread.py +2 -1
- ansible_test/_internal/timeout.py +1 -1
- ansible_test/_internal/util.py +40 -12
- 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 +61 -7
- ansible_test/_util/target/setup/bootstrap.sh +31 -0
- ansible_test/_util/target/setup/requirements.py +3 -9
- ansible/_internal/_errors/_utils.py +0 -310
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0b4.dist-info → ansible_core-2.19.0b6.dist-info}/top_level.txt +0 -0
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()
|
@@ -745,19 +739,13 @@ class Dnf5Module(YumDnf):
|
|
745
739
|
goal.add_install(spec, settings)
|
746
740
|
elif self.state in {"absent", "removed"}:
|
747
741
|
for spec in self.names:
|
748
|
-
|
749
|
-
goal.add_remove(spec, settings)
|
750
|
-
except LIBDNF5_ERROR as e:
|
751
|
-
self.module.fail_json(msg=str(e), failures=[], rc=1)
|
742
|
+
goal.add_remove(spec, settings)
|
752
743
|
if self.autoremove:
|
753
744
|
for pkg in get_unneeded_pkgs(base):
|
754
745
|
goal.add_rpm_remove(pkg, settings)
|
755
746
|
|
756
747
|
goal.set_allow_erasing(self.allowerasing)
|
757
|
-
|
758
|
-
transaction = goal.resolve()
|
759
|
-
except LIBDNF5_ERROR as e:
|
760
|
-
self.module.fail_json(msg=str(e), failures=[], rc=1)
|
748
|
+
transaction = goal.resolve()
|
761
749
|
|
762
750
|
if transaction.get_problems():
|
763
751
|
failures = []
|
@@ -833,7 +821,11 @@ def main():
|
|
833
821
|
auto_install_module_deps=dict(type="bool", default=True),
|
834
822
|
)
|
835
823
|
)
|
836
|
-
|
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)
|
837
829
|
|
838
830
|
|
839
831
|
if __name__ == "__main__":
|
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
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/replace.py
CHANGED
@@ -256,8 +256,8 @@ def main():
|
|
256
256
|
try:
|
257
257
|
with open(path, 'rb') as f:
|
258
258
|
contents = to_text(f.read(), errors='surrogate_or_strict', encoding=encoding)
|
259
|
-
except
|
260
|
-
|
259
|
+
except OSError as ex:
|
260
|
+
raise Exception(f"Unable to read the contents of {path!r}.") from ex
|
261
261
|
|
262
262
|
pattern = u''
|
263
263
|
if params['after'] and params['before']:
|
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/slurp.py
CHANGED
@@ -85,7 +85,6 @@ import base64
|
|
85
85
|
import errno
|
86
86
|
|
87
87
|
from ansible.module_utils.basic import AnsibleModule
|
88
|
-
from ansible.module_utils.common.text.converters import to_native
|
89
88
|
|
90
89
|
|
91
90
|
def main():
|
@@ -99,20 +98,18 @@ def main():
|
|
99
98
|
|
100
99
|
try:
|
101
100
|
with open(source, 'rb') as source_fh:
|
102
|
-
|
103
|
-
except
|
104
|
-
if
|
105
|
-
msg = "
|
106
|
-
elif
|
107
|
-
msg = "
|
108
|
-
elif
|
109
|
-
msg = "
|
101
|
+
data = base64.b64encode(source_fh.read())
|
102
|
+
except OSError as ex:
|
103
|
+
if ex.errno == errno.ENOENT:
|
104
|
+
msg = f"File not found: {source}"
|
105
|
+
elif ex.errno == errno.EACCES:
|
106
|
+
msg = f"File is not readable: {source}"
|
107
|
+
elif ex.errno == errno.EISDIR:
|
108
|
+
msg = f"Source is a directory and must be a file: {source}"
|
110
109
|
else:
|
111
|
-
msg = "
|
110
|
+
msg = "Unable to slurp file: {source}"
|
112
111
|
|
113
|
-
module.fail_json(msg)
|
114
|
-
|
115
|
-
data = base64.b64encode(source_content)
|
112
|
+
module.fail_json(msg, exception=ex)
|
116
113
|
|
117
114
|
module.exit_json(content=data, source=source, encoding='base64')
|
118
115
|
|
ansible/modules/stat.py
CHANGED
@@ -354,7 +354,6 @@ stat:
|
|
354
354
|
version_added: 2.3
|
355
355
|
"""
|
356
356
|
|
357
|
-
import errno
|
358
357
|
import grp
|
359
358
|
import os
|
360
359
|
import pwd
|
@@ -456,12 +455,11 @@ def main():
|
|
456
455
|
st = os.stat(b_path)
|
457
456
|
else:
|
458
457
|
st = os.lstat(b_path)
|
459
|
-
except
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
module.fail_json(msg=e.strerror)
|
458
|
+
except FileNotFoundError:
|
459
|
+
output = {'exists': False}
|
460
|
+
module.exit_json(changed=False, stat=output)
|
461
|
+
except OSError as ex:
|
462
|
+
module.fail_json(msg=ex.strerror, exception=ex)
|
465
463
|
|
466
464
|
# process base results
|
467
465
|
output = format_output(module, path, st)
|
ansible/modules/unarchive.py
CHANGED
@@ -1132,8 +1132,8 @@ def main():
|
|
1132
1132
|
res_args['extract_results'] = handler.unarchive()
|
1133
1133
|
if res_args['extract_results']['rc'] != 0:
|
1134
1134
|
module.fail_json(msg="failed to unpack %s to %s" % (src, dest), **res_args)
|
1135
|
-
except
|
1136
|
-
module.fail_json(
|
1135
|
+
except OSError as ex:
|
1136
|
+
module.fail_json(f"Failed to unpack {src!r} to {dest!r}.", exception=ex, **res_args)
|
1137
1137
|
else:
|
1138
1138
|
res_args['changed'] = True
|
1139
1139
|
|
@@ -1150,8 +1150,8 @@ def main():
|
|
1150
1150
|
|
1151
1151
|
try:
|
1152
1152
|
res_args['changed'] = module.set_fs_attributes_if_different(file_args, res_args['changed'], expand=False)
|
1153
|
-
except
|
1154
|
-
module.fail_json(
|
1153
|
+
except OSError as ex:
|
1154
|
+
module.fail_json("Unexpected error when accessing exploded file.", exception=ex, **res_args)
|
1155
1155
|
|
1156
1156
|
if '/' in filename:
|
1157
1157
|
top_folder_path = filename.split('/')[0]
|
@@ -1165,8 +1165,8 @@ def main():
|
|
1165
1165
|
file_args['path'] = "%s/%s" % (dest, f)
|
1166
1166
|
try:
|
1167
1167
|
res_args['changed'] = module.set_fs_attributes_if_different(file_args, res_args['changed'], expand=False)
|
1168
|
-
except
|
1169
|
-
module.fail_json(
|
1168
|
+
except OSError as ex:
|
1169
|
+
module.fail_json("Unexpected error when accessing exploded file.", exception=ex, **res_args)
|
1170
1170
|
|
1171
1171
|
if module.params['list_files']:
|
1172
1172
|
res_args['files'] = handler.files_in_archive
|
ansible/modules/user.py
CHANGED
ansible/modules/wait_for.py
CHANGED
@@ -380,31 +380,29 @@ class LinuxTCPConnectionInfo(TCPConnectionInfo):
|
|
380
380
|
if not os.path.isfile(self.source_file[family]):
|
381
381
|
continue
|
382
382
|
try:
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
except
|
383
|
+
with open(self.source_file[family]) as f:
|
384
|
+
for tcp_connection in f.readlines():
|
385
|
+
tcp_connection = tcp_connection.strip().split()
|
386
|
+
if tcp_connection[self.local_address_field] == 'local_address':
|
387
|
+
continue
|
388
|
+
if (tcp_connection[self.connection_state_field] not in
|
389
|
+
[get_connection_state_id(_connection_state) for _connection_state in self.module.params['active_connection_states']]):
|
390
|
+
continue
|
391
|
+
(local_ip, local_port) = tcp_connection[self.local_address_field].split(':')
|
392
|
+
if self.port != local_port:
|
393
|
+
continue
|
394
|
+
(remote_ip, remote_port) = tcp_connection[self.remote_address_field].split(':')
|
395
|
+
if (family, remote_ip) in self.exclude_ips:
|
396
|
+
continue
|
397
|
+
if any((
|
398
|
+
(family, local_ip) in self.ips,
|
399
|
+
(family, self.match_all_ips[family]) in self.ips,
|
400
|
+
local_ip.startswith(self.ipv4_mapped_ipv6_address['prefix']) and
|
401
|
+
(family, self.ipv4_mapped_ipv6_address['match_all']) in self.ips,
|
402
|
+
)):
|
403
|
+
active_connections += 1
|
404
|
+
except OSError:
|
405
405
|
pass
|
406
|
-
finally:
|
407
|
-
f.close()
|
408
406
|
|
409
407
|
return active_connections
|
410
408
|
|
@@ -549,7 +547,7 @@ def main():
|
|
549
547
|
try:
|
550
548
|
if not os.access(b_path, os.F_OK):
|
551
549
|
break
|
552
|
-
except
|
550
|
+
except OSError:
|
553
551
|
break
|
554
552
|
elif port:
|
555
553
|
try:
|
@@ -609,7 +607,7 @@ def main():
|
|
609
607
|
break
|
610
608
|
except Exception as e:
|
611
609
|
module.warn('wait_for failed on "%s", unexpected exception(%s): %s.).' % (path, to_native(e.__class__), to_native(e)))
|
612
|
-
except
|
610
|
+
except OSError:
|
613
611
|
pass
|
614
612
|
elif port:
|
615
613
|
alt_connect_timeout = math.ceil(
|
@@ -648,8 +646,8 @@ def main():
|
|
648
646
|
# Shutdown the client socket
|
649
647
|
try:
|
650
648
|
s.shutdown(socket.SHUT_RDWR)
|
651
|
-
except
|
652
|
-
if
|
649
|
+
except OSError as ex:
|
650
|
+
if ex.errno != errno.ENOTCONN:
|
653
651
|
raise
|
654
652
|
# else, the server broke the connection on its end, assume it's not ready
|
655
653
|
else:
|
@@ -661,8 +659,8 @@ def main():
|
|
661
659
|
# Connection established, success!
|
662
660
|
try:
|
663
661
|
s.shutdown(socket.SHUT_RDWR)
|
664
|
-
except
|
665
|
-
if
|
662
|
+
except OSError as ex:
|
663
|
+
if ex.errno != errno.ENOTCONN:
|
666
664
|
raise
|
667
665
|
# else, the server broke the connection on its end, assume it's not ready
|
668
666
|
else:
|
@@ -502,10 +502,11 @@ class YumRepo:
|
|
502
502
|
try:
|
503
503
|
with open(self.dest, 'w') as fd:
|
504
504
|
self.repofile.write(fd)
|
505
|
-
except
|
505
|
+
except OSError as ex:
|
506
506
|
self.module.fail_json(
|
507
|
-
msg=f"Problems handling file {self.dest}.",
|
508
|
-
details=
|
507
|
+
msg=f"Problems handling file {self.dest!r}.",
|
508
|
+
details=str(ex),
|
509
|
+
exception=ex,
|
509
510
|
)
|
510
511
|
else:
|
511
512
|
try:
|
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:
|
@@ -217,7 +217,7 @@ class DataLoader:
|
|
217
217
|
except FileNotFoundError as ex:
|
218
218
|
# DTFIX-FUTURE: why not just let the builtin one fly?
|
219
219
|
raise AnsibleFileNotFound("Unable to retrieve file contents.", file_name=file_name) from ex
|
220
|
-
except
|
220
|
+
except OSError as ex:
|
221
221
|
raise AnsibleParserError(f"An error occurred while trying to read the file {file_name!r}.") from ex
|
222
222
|
|
223
223
|
data = Origin(path=file_name).tag(data)
|
@@ -448,7 +448,7 @@ class DataLoader:
|
|
448
448
|
|
449
449
|
return real_path
|
450
450
|
|
451
|
-
except
|
451
|
+
except OSError as ex:
|
452
452
|
raise AnsibleParserError(f"an error occurred while trying to read the file {to_text(real_path)!r}.") from ex
|
453
453
|
|
454
454
|
def cleanup_tmp_file(self, file_path: str) -> None:
|