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
@@ -33,7 +33,6 @@ import json
|
|
33
33
|
import pickle
|
34
34
|
import socket
|
35
35
|
import struct
|
36
|
-
import traceback
|
37
36
|
import uuid
|
38
37
|
|
39
38
|
from functools import partial
|
@@ -136,12 +135,11 @@ class Connection(object):
|
|
136
135
|
|
137
136
|
try:
|
138
137
|
out = self.send(data)
|
139
|
-
except
|
138
|
+
except OSError as ex:
|
140
139
|
raise ConnectionError(
|
141
|
-
'
|
142
|
-
'in the Network Debug and Troubleshooting Guide'
|
143
|
-
|
144
|
-
)
|
140
|
+
f'Unable to connect to socket {self.socket_path!r}. See Troubleshooting socket path issues '
|
141
|
+
'in the Network Debug and Troubleshooting Guide.'
|
142
|
+
) from ex
|
145
143
|
|
146
144
|
try:
|
147
145
|
response = json.loads(out)
|
@@ -192,13 +190,12 @@ class Connection(object):
|
|
192
190
|
send_data(sf, to_bytes(data))
|
193
191
|
response = recv_data(sf)
|
194
192
|
|
195
|
-
except
|
193
|
+
except OSError as ex:
|
196
194
|
sf.close()
|
197
195
|
raise ConnectionError(
|
198
|
-
'
|
199
|
-
'Network Debug and Troubleshooting Guide'
|
200
|
-
|
201
|
-
)
|
196
|
+
f'Unable to connect to socket {self.socket_path!r}. See the socket path issue category in '
|
197
|
+
'Network Debug and Troubleshooting Guide.',
|
198
|
+
) from ex
|
202
199
|
|
203
200
|
sf.close()
|
204
201
|
|
ansible/module_utils/datatag.py
CHANGED
@@ -3,13 +3,15 @@ from __future__ import annotations as _annotations
|
|
3
3
|
|
4
4
|
import typing as _t
|
5
5
|
|
6
|
-
from ._internal import _datatag, _deprecator
|
6
|
+
from ._internal import _datatag, _deprecator, _traceback, _messages
|
7
7
|
from ._internal._datatag import _tags
|
8
|
-
from .common import messages as _messages
|
9
8
|
|
10
9
|
_T = _t.TypeVar('_T')
|
11
10
|
|
12
11
|
|
12
|
+
deprecator_from_collection_name = _deprecator.deprecator_from_collection_name
|
13
|
+
|
14
|
+
|
13
15
|
def deprecate_value(
|
14
16
|
value: _T,
|
15
17
|
msg: str,
|
@@ -36,6 +38,7 @@ def deprecate_value(
|
|
36
38
|
date=date,
|
37
39
|
version=version,
|
38
40
|
deprecator=_deprecator.get_best_deprecator(deprecator=deprecator, collection_name=collection_name),
|
41
|
+
formatted_traceback=_traceback.maybe_capture_traceback(msg, _traceback.TracebackEvent.DEPRECATED_VALUE),
|
39
42
|
)
|
40
43
|
|
41
44
|
return deprecated.tag(value)
|
@@ -17,8 +17,6 @@ from __future__ import annotations
|
|
17
17
|
|
18
18
|
import re
|
19
19
|
|
20
|
-
from ansible.module_utils.common.text.converters import to_text
|
21
|
-
|
22
20
|
|
23
21
|
def get_sysctl(module, prefixes):
|
24
22
|
|
@@ -31,8 +29,8 @@ def get_sysctl(module, prefixes):
|
|
31
29
|
|
32
30
|
try:
|
33
31
|
rc, out, err = module.run_command(cmd)
|
34
|
-
except
|
35
|
-
module.
|
32
|
+
except OSError as ex:
|
33
|
+
module.error_as_warning('Unable to read sysctl.', exception=ex)
|
36
34
|
rc = 1
|
37
35
|
|
38
36
|
if rc == 0:
|
@@ -54,8 +52,8 @@ def get_sysctl(module, prefixes):
|
|
54
52
|
|
55
53
|
try:
|
56
54
|
(key, value) = re.split(r'\s?=\s?|: ', line, maxsplit=1)
|
57
|
-
except Exception as
|
58
|
-
module.
|
55
|
+
except Exception as ex:
|
56
|
+
module.error_as_warning(f'Unable to split sysctl line {line!r}.', exception=ex)
|
59
57
|
|
60
58
|
if key:
|
61
59
|
sysctl[key] = value.strip()
|
@@ -38,8 +38,8 @@ class SystemCapabilitiesFactCollector(BaseFactCollector):
|
|
38
38
|
# NOTE: -> get_caps_data()/parse_caps_data() for easier mocking -akl
|
39
39
|
try:
|
40
40
|
rc, out, err = module.run_command([capsh_path, "--print"], errors='surrogate_then_replace', handle_exceptions=False)
|
41
|
-
except
|
42
|
-
module.
|
41
|
+
except OSError as ex:
|
42
|
+
module.error_as_warning('Could not query system capabilities.', exception=ex)
|
43
43
|
|
44
44
|
if rc == 0:
|
45
45
|
enforced_caps = []
|
@@ -310,9 +310,22 @@ class DistributionFiles:
|
|
310
310
|
suse_facts['distribution_release'] = release.group(1)
|
311
311
|
suse_facts['distribution_version'] = collected_facts['distribution_version'] + '.' + release.group(1)
|
312
312
|
|
313
|
-
#
|
314
|
-
|
315
|
-
|
313
|
+
# Check VARIANT_ID first for SLES4SAP or SL-Micro
|
314
|
+
variant_id_match = re.search(r'^VARIANT_ID="?([^"\n]*)"?', data, re.MULTILINE)
|
315
|
+
if variant_id_match:
|
316
|
+
variant_id = variant_id_match.group(1)
|
317
|
+
if variant_id in ('server-sap', 'sles-sap'):
|
318
|
+
suse_facts['distribution'] = 'SLES_SAP'
|
319
|
+
elif variant_id == 'transactional':
|
320
|
+
suse_facts['distribution'] = 'SL-Micro'
|
321
|
+
else:
|
322
|
+
# Fallback for older SLES 15 using baseproduct symlink
|
323
|
+
if os.path.islink('/etc/products.d/baseproduct'):
|
324
|
+
resolved = os.path.realpath('/etc/products.d/baseproduct')
|
325
|
+
if resolved.endswith('SLES_SAP.prod'):
|
326
|
+
suse_facts['distribution'] = 'SLES_SAP'
|
327
|
+
elif resolved.endswith('SL-Micro.prod'):
|
328
|
+
suse_facts['distribution'] = 'SL-Micro'
|
316
329
|
|
317
330
|
return True, suse_facts
|
318
331
|
|
@@ -50,7 +50,7 @@ class LocalFactCollector(BaseFactCollector):
|
|
50
50
|
rc, out, err = module.run_command(fn)
|
51
51
|
if rc != 0:
|
52
52
|
failed = 'Failure executing fact script (%s), rc: %s, err: %s' % (fn, rc, err)
|
53
|
-
except
|
53
|
+
except OSError as e:
|
54
54
|
failed = 'Could not execute fact script (%s): %s' % (fn, to_text(e))
|
55
55
|
|
56
56
|
if failed is not None:
|
@@ -129,7 +129,7 @@ class LinuxVirtual(Virtual):
|
|
129
129
|
for line in get_file_lines('/proc/xen/capabilities'):
|
130
130
|
if "control_d" in line:
|
131
131
|
is_xen_host = True
|
132
|
-
except
|
132
|
+
except OSError:
|
133
133
|
pass
|
134
134
|
|
135
135
|
if is_xen_host:
|
@@ -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'
|
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
|
|
@@ -293,7 +286,7 @@ def is_systemd_managed(module):
|
|
293
286
|
with open('/proc/1/comm', 'r') as init_proc:
|
294
287
|
init = init_proc.readline().strip()
|
295
288
|
return init == 'systemd'
|
296
|
-
except
|
289
|
+
except OSError:
|
297
290
|
# If comm doesn't exist, old kernel, no systemd
|
298
291
|
return False
|
299
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:
|
@@ -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:
|
@@ -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')
|
@@ -355,8 +333,8 @@ class SourcesList(object):
|
|
355
333
|
|
356
334
|
try:
|
357
335
|
fd, tmp_path = tempfile.mkstemp(prefix=".%s-" % fn, dir=d)
|
358
|
-
except
|
359
|
-
|
336
|
+
except OSError as ex:
|
337
|
+
raise Exception(f'Unable to create temp file at {d!r} for apt source.') from ex
|
360
338
|
|
361
339
|
f = os.fdopen(fd, 'w')
|
362
340
|
for n, valid, enabled, source, comment in sources:
|
@@ -372,8 +350,8 @@ class SourcesList(object):
|
|
372
350
|
|
373
351
|
try:
|
374
352
|
f.write(line)
|
375
|
-
except
|
376
|
-
|
353
|
+
except OSError as ex:
|
354
|
+
raise Exception(f"Failed to write to file {tmp_path!r}.") from ex
|
377
355
|
if filename in self.files_mapping:
|
378
356
|
# Write to symlink target instead of replacing symlink as a normal file
|
379
357
|
self.module.atomic_move(tmp_path, self.files_mapping[filename])
|
@@ -529,8 +507,8 @@ class UbuntuSourcesList(SourcesList):
|
|
529
507
|
if os.path.exists(key_file):
|
530
508
|
try:
|
531
509
|
rc, out, err = self.module.run_command([self.gpg_bin, '--list-packets', key_file])
|
532
|
-
except
|
533
|
-
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}")
|
534
512
|
continue
|
535
513
|
|
536
514
|
if key_fingerprint in out:
|
@@ -579,8 +557,8 @@ class UbuntuSourcesList(SourcesList):
|
|
579
557
|
with open(keyfile, 'wb') as f:
|
580
558
|
f.write(stdout)
|
581
559
|
self.module.log('Added repo key "%s" for apt to file "%s"' % (info['signing_key_fingerprint'], keyfile))
|
582
|
-
except
|
583
|
-
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)
|
584
562
|
|
585
563
|
# apt source file
|
586
564
|
file = file or self._suggest_filename('%s_%s' % (line, self.codename))
|
@@ -774,9 +752,9 @@ def main():
|
|
774
752
|
)
|
775
753
|
module.fail_json(msg=msg)
|
776
754
|
|
777
|
-
except
|
755
|
+
except OSError as ex:
|
778
756
|
revert_sources_list(sources_before, sources_after, sourceslist_before)
|
779
|
-
|
757
|
+
raise
|
780
758
|
|
781
759
|
module.exit_json(changed=changed, repo=repo, sources_added=sources_added, sources_removed=sources_removed, state=state, diff=diff)
|
782
760
|
|
ansible/modules/assemble.py
CHANGED
@@ -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():
|
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
@@ -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)
|
@@ -149,7 +138,7 @@ def _run_module(wrapped_cmd, jid):
|
|
149
138
|
|
150
139
|
# DTFIX-FUTURE: needs rework for serialization profiles
|
151
140
|
|
152
|
-
jwrite({"started":
|
141
|
+
jwrite({"started": True, "finished": False, "ansible_job_id": jid})
|
153
142
|
|
154
143
|
result = {}
|
155
144
|
|
@@ -200,10 +189,10 @@ 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
|
-
"failed":
|
195
|
+
"failed": True,
|
207
196
|
"cmd": wrapped_cmd,
|
208
197
|
"msg": to_text(e),
|
209
198
|
"outdata": outdata, # temporary notice only
|
@@ -212,9 +201,9 @@ 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
|
-
"failed":
|
206
|
+
"failed": True,
|
218
207
|
"cmd": wrapped_cmd,
|
219
208
|
"data": outdata, # temporary notice only
|
220
209
|
"stderr": stderr,
|
@@ -257,10 +246,11 @@ 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
|
-
"failed":
|
253
|
+
"failed": True,
|
264
254
|
"msg": "could not create directory: %s - %s" % (jobdir, to_text(e)),
|
265
255
|
"exception": to_text(traceback.format_exc()), # NB: task executor compat will coerce to the correct dataclass type
|
266
256
|
}, 1)
|
@@ -293,7 +283,7 @@ def main():
|
|
293
283
|
continue
|
294
284
|
|
295
285
|
notice("Return async_wrapper task started.")
|
296
|
-
end({"failed":
|
286
|
+
end({"failed": False, "started": True, "finished": False, "ansible_job_id": jid, "results_file": job_path,
|
297
287
|
"_ansible_suppress_tmpdir_delete": (not preserve_tmp)}, 0)
|
298
288
|
else:
|
299
289
|
# The actual wrapper process
|
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:
|