ansible-core 2.19.2__py3-none-any.whl → 2.20.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ansible-core might be problematic. Click here for more details.
- ansible/_internal/__init__.py +1 -4
- ansible/_internal/_ansiballz/_builder.py +1 -3
- ansible/_internal/_collection_proxy.py +7 -9
- ansible/_internal/_display_utils.py +145 -0
- ansible/_internal/_json/__init__.py +3 -4
- ansible/_internal/_templating/_engine.py +1 -1
- ansible/_internal/_templating/_jinja_plugins.py +1 -2
- ansible/_internal/_wrapt.py +105 -301
- ansible/cli/__init__.py +11 -10
- ansible/cli/adhoc.py +1 -2
- ansible/cli/arguments/option_helpers.py +1 -1
- ansible/cli/config.py +5 -6
- ansible/cli/doc.py +67 -67
- ansible/cli/galaxy.py +15 -24
- ansible/cli/inventory.py +0 -1
- ansible/cli/playbook.py +0 -1
- ansible/cli/pull.py +0 -1
- ansible/cli/scripts/ansible_connection_cli_stub.py +1 -1
- ansible/config/base.yml +1 -25
- ansible/config/manager.py +0 -2
- ansible/executor/play_iterator.py +42 -20
- ansible/executor/playbook_executor.py +0 -9
- ansible/executor/powershell/async_watchdog.ps1 +24 -4
- ansible/executor/task_executor.py +32 -22
- ansible/executor/task_queue_manager.py +1 -3
- ansible/galaxy/api.py +33 -80
- ansible/galaxy/collection/__init__.py +4 -17
- ansible/galaxy/dependency_resolution/dataclasses.py +0 -10
- ansible/galaxy/dependency_resolution/providers.py +1 -2
- ansible/galaxy/role.py +1 -33
- ansible/inventory/manager.py +2 -3
- ansible/keyword_desc.yml +0 -3
- ansible/module_utils/_internal/_datatag/__init__.py +2 -10
- ansible/module_utils/_internal/_no_six.py +86 -0
- ansible/module_utils/_text.py +28 -8
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/basic.py +27 -24
- ansible/module_utils/common/_collections_compat.py +11 -2
- ansible/module_utils/common/collections.py +8 -3
- ansible/module_utils/common/dict_transformations.py +1 -2
- ansible/module_utils/common/network.py +4 -2
- ansible/module_utils/common/parameters.py +32 -41
- ansible/module_utils/common/text/converters.py +109 -23
- ansible/module_utils/common/text/formatters.py +6 -2
- ansible/module_utils/common/validation.py +11 -9
- ansible/module_utils/connection.py +8 -3
- ansible/module_utils/facts/hardware/linux.py +23 -7
- ansible/module_utils/facts/hardware/netbsd.py +1 -1
- ansible/module_utils/facts/hardware/sunos.py +2 -1
- ansible/module_utils/facts/packages.py +6 -2
- ansible/module_utils/facts/system/distribution.py +2 -1
- ansible/module_utils/facts/system/env.py +6 -3
- ansible/module_utils/facts/system/local.py +3 -1
- ansible/module_utils/parsing/convert_bool.py +6 -2
- ansible/module_utils/service.py +2 -3
- ansible/module_utils/six/__init__.py +11 -6
- ansible/module_utils/urls.py +6 -2
- ansible/module_utils/yumdnf.py +0 -5
- ansible/modules/apt.py +18 -13
- ansible/modules/apt_repository.py +1 -1
- ansible/modules/assemble.py +5 -9
- ansible/modules/blockinfile.py +39 -23
- ansible/modules/cron.py +26 -35
- ansible/modules/deb822_repository.py +83 -12
- ansible/modules/dnf.py +3 -7
- ansible/modules/dnf5.py +4 -6
- ansible/modules/expect.py +0 -3
- ansible/modules/find.py +1 -2
- ansible/modules/get_url.py +1 -1
- ansible/modules/git.py +4 -5
- ansible/modules/include_vars.py +1 -1
- ansible/modules/lineinfile.py +71 -63
- ansible/modules/package_facts.py +1 -1
- ansible/modules/pip.py +8 -2
- ansible/modules/replace.py +6 -6
- ansible/modules/service.py +3 -4
- ansible/modules/stat.py +20 -0
- ansible/modules/uri.py +9 -10
- ansible/modules/user.py +1 -2
- ansible/modules/wait_for.py +2 -2
- ansible/modules/wait_for_connection.py +2 -1
- ansible/modules/yum_repository.py +1 -16
- ansible/parsing/dataloader.py +24 -31
- ansible/parsing/mod_args.py +3 -0
- ansible/parsing/vault/__init__.py +1 -2
- ansible/playbook/base.py +8 -56
- ansible/playbook/block.py +0 -60
- ansible/playbook/collectionsearch.py +1 -2
- ansible/playbook/handler.py +1 -7
- ansible/playbook/helpers.py +0 -7
- ansible/playbook/included_file.py +1 -1
- ansible/playbook/play.py +103 -37
- ansible/playbook/play_context.py +4 -0
- ansible/playbook/role/__init__.py +10 -65
- ansible/playbook/role/definition.py +3 -4
- ansible/playbook/role/include.py +2 -3
- ansible/playbook/role/metadata.py +1 -12
- ansible/playbook/role/requirement.py +1 -2
- ansible/playbook/role_include.py +1 -2
- ansible/playbook/taggable.py +16 -5
- ansible/playbook/task.py +51 -55
- ansible/plugins/action/__init__.py +20 -19
- ansible/plugins/action/add_host.py +1 -2
- ansible/plugins/action/fetch.py +2 -4
- ansible/plugins/action/group_by.py +1 -2
- ansible/plugins/action/include_vars.py +20 -22
- ansible/plugins/action/script.py +1 -3
- ansible/plugins/action/template.py +1 -2
- ansible/plugins/action/uri.py +4 -2
- ansible/plugins/cache/__init__.py +1 -0
- ansible/plugins/callback/__init__.py +13 -6
- ansible/plugins/connection/__init__.py +3 -7
- ansible/plugins/connection/local.py +2 -3
- ansible/plugins/connection/psrp.py +0 -2
- ansible/plugins/connection/ssh.py +2 -7
- ansible/plugins/connection/winrm.py +0 -2
- ansible/plugins/doc_fragments/result_format_callback.py +15 -0
- ansible/plugins/filter/core.py +4 -5
- ansible/plugins/filter/encryption.py +3 -27
- ansible/plugins/filter/mathstuff.py +1 -2
- ansible/plugins/filter/to_nice_yaml.yml +31 -3
- ansible/plugins/filter/to_yaml.yml +29 -12
- ansible/plugins/inventory/__init__.py +1 -2
- ansible/plugins/inventory/script.py +2 -1
- ansible/plugins/inventory/toml.py +3 -6
- ansible/plugins/inventory/yaml.py +1 -2
- ansible/plugins/list.py +10 -3
- ansible/plugins/loader.py +6 -6
- ansible/plugins/lookup/password.py +1 -2
- ansible/plugins/lookup/subelements.py +2 -3
- ansible/plugins/lookup/url.py +1 -1
- ansible/plugins/lookup/varnames.py +1 -2
- ansible/plugins/shell/__init__.py +9 -4
- ansible/plugins/shell/powershell.py +8 -24
- ansible/plugins/strategy/__init__.py +6 -3
- ansible/plugins/test/core.py +4 -1
- ansible/plugins/test/regex.yml +18 -6
- ansible/release.py +2 -2
- ansible/template/__init__.py +3 -7
- ansible/utils/collection_loader/_collection_config.py +5 -0
- ansible/utils/collection_loader/_collection_finder.py +11 -14
- ansible/utils/context_objects.py +7 -4
- ansible/utils/display.py +28 -167
- ansible/utils/encrypt.py +0 -5
- ansible/utils/helpers.py +6 -2
- ansible/utils/jsonrpc.py +7 -3
- ansible/utils/plugin_docs.py +49 -38
- ansible/utils/ssh_functions.py +0 -19
- ansible/utils/unsafe_proxy.py +7 -7
- ansible/vars/clean.py +2 -3
- ansible/vars/manager.py +27 -20
- ansible/vars/plugins.py +1 -31
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/METADATA +3 -3
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/RECORD +200 -200
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/network.txt +0 -1
- ansible_test/_data/completion/remote.txt +4 -4
- ansible_test/_data/requirements/ansible-test.txt +1 -1
- ansible_test/_data/requirements/sanity.changelog.txt +1 -1
- ansible_test/_data/requirements/sanity.pep8.txt +1 -1
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_internal/cache.py +2 -5
- ansible_test/_internal/cli/compat.py +1 -1
- ansible_test/_internal/commands/coverage/combine.py +1 -3
- ansible_test/_internal/commands/integration/__init__.py +3 -7
- ansible_test/_internal/commands/integration/cloud/httptester.py +1 -1
- ansible_test/_internal/commands/integration/coverage.py +1 -3
- ansible_test/_internal/commands/integration/filters.py +5 -10
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -5
- ansible_test/_internal/commands/units/__init__.py +1 -13
- ansible_test/_internal/completion.py +2 -5
- ansible_test/_internal/config.py +2 -7
- ansible_test/_internal/coverage_util.py +1 -1
- ansible_test/_internal/delegation.py +2 -0
- ansible_test/_internal/docker_util.py +1 -1
- ansible_test/_internal/host_profiles.py +6 -11
- ansible_test/_internal/provider/__init__.py +2 -5
- ansible_test/_internal/provisioning.py +2 -5
- ansible_test/_internal/pypi_proxy.py +1 -1
- ansible_test/_internal/target.py +2 -6
- ansible_test/_internal/thread.py +1 -4
- ansible_test/_internal/util.py +9 -14
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +14 -19
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +30 -27
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +31 -18
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +1 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +59 -71
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -2
- ansible_test/_util/target/cli/ansible_test_cli_stub.py +4 -2
- ansible_test/_util/target/common/constants.py +2 -2
- ansible_test/_util/target/setup/bootstrap.sh +0 -6
- ansible/utils/py3compat.py +0 -27
- ansible_test/_data/pytest/config/legacy.ini +0 -4
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.2.dist-info → ansible_core-2.20.0b1.dist-info}/top_level.txt +0 -0
ansible/module_utils/urls.py
CHANGED
|
@@ -1358,7 +1358,8 @@ def _split_multiext(name, min=3, max=4, count=2):
|
|
|
1358
1358
|
|
|
1359
1359
|
def fetch_file(module, url, data=None, headers=None, method=None,
|
|
1360
1360
|
use_proxy=True, force=False, last_mod_time=None, timeout=10,
|
|
1361
|
-
unredirected_headers=None, decompress=True, ciphers=None
|
|
1361
|
+
unredirected_headers=None, decompress=True, ciphers=None,
|
|
1362
|
+
ca_path=None, cookies=None):
|
|
1362
1363
|
"""Download and save a file via HTTP(S) or FTP (needs the module as parameter).
|
|
1363
1364
|
This is basically a wrapper around fetch_url().
|
|
1364
1365
|
|
|
@@ -1375,6 +1376,8 @@ def fetch_file(module, url, data=None, headers=None, method=None,
|
|
|
1375
1376
|
:kwarg unredirected_headers: (optional) A list of headers to not attach on a redirected request
|
|
1376
1377
|
:kwarg decompress: (optional) Whether to attempt to decompress gzip content-encoded responses
|
|
1377
1378
|
:kwarg ciphers: (optional) List of ciphers to use
|
|
1379
|
+
:kwarg ca_path: (optional) Path to CA bundle
|
|
1380
|
+
:kwarg cookies: (optional) CookieJar object to send with the request
|
|
1378
1381
|
|
|
1379
1382
|
:returns: A string, the path to the downloaded file.
|
|
1380
1383
|
"""
|
|
@@ -1386,7 +1389,8 @@ def fetch_file(module, url, data=None, headers=None, method=None,
|
|
|
1386
1389
|
module.add_cleanup_file(fetch_temp_file.name)
|
|
1387
1390
|
try:
|
|
1388
1391
|
rsp, info = fetch_url(module, url, data, headers, method, use_proxy, force, last_mod_time, timeout,
|
|
1389
|
-
unredirected_headers=unredirected_headers, decompress=decompress, ciphers=ciphers
|
|
1392
|
+
unredirected_headers=unredirected_headers, decompress=decompress, ciphers=ciphers,
|
|
1393
|
+
ca_path=ca_path, cookies=cookies)
|
|
1390
1394
|
if not rsp or (rsp.code and rsp.code >= 400):
|
|
1391
1395
|
module.fail_json(msg="Failure downloading %s, %s" % (url, info['msg']))
|
|
1392
1396
|
data = rsp.read(bufsize)
|
ansible/module_utils/yumdnf.py
CHANGED
|
@@ -32,10 +32,6 @@ yumdnf_argument_spec = dict(
|
|
|
32
32
|
enablerepo=dict(type='list', elements='str', default=[]),
|
|
33
33
|
exclude=dict(type='list', elements='str', default=[]),
|
|
34
34
|
installroot=dict(type='str', default="/"),
|
|
35
|
-
install_repoquery=dict(
|
|
36
|
-
type='bool', default=True,
|
|
37
|
-
removed_in_version='2.20', removed_from_collection='ansible.builtin',
|
|
38
|
-
),
|
|
39
35
|
install_weak_deps=dict(type='bool', default=True),
|
|
40
36
|
list=dict(type='str'),
|
|
41
37
|
name=dict(type='list', elements='str', aliases=['pkg'], default=[]),
|
|
@@ -85,7 +81,6 @@ class YumDnf(metaclass=ABCMeta):
|
|
|
85
81
|
self.enablerepo = self.module.params.get('enablerepo', [])
|
|
86
82
|
self.exclude = self.module.params['exclude']
|
|
87
83
|
self.installroot = self.module.params['installroot']
|
|
88
|
-
self.install_repoquery = self.module.params['install_repoquery']
|
|
89
84
|
self.install_weak_deps = self.module.params['install_weak_deps']
|
|
90
85
|
self.list = self.module.params['list']
|
|
91
86
|
self.names = [p.strip() for p in self.module.params['name']]
|
ansible/modules/apt.py
CHANGED
|
@@ -372,6 +372,7 @@ import locale as locale_module
|
|
|
372
372
|
import os
|
|
373
373
|
import re
|
|
374
374
|
import secrets
|
|
375
|
+
import shlex
|
|
375
376
|
import shutil
|
|
376
377
|
import sys
|
|
377
378
|
import tempfile
|
|
@@ -382,7 +383,6 @@ from ansible.module_utils.common.file import S_IRWXU_RXG_RXO
|
|
|
382
383
|
from ansible.module_utils.common.locale import get_best_parsable_locale
|
|
383
384
|
from ansible.module_utils.common.respawn import has_respawned, probe_interpreters_for_module, respawn_module
|
|
384
385
|
from ansible.module_utils.common.text.converters import to_native, to_text
|
|
385
|
-
from ansible.module_utils.six import string_types
|
|
386
386
|
from ansible.module_utils.urls import fetch_file
|
|
387
387
|
|
|
388
388
|
DPKG_OPTIONS = 'force-confdef,force-confold'
|
|
@@ -390,8 +390,6 @@ APT_GET_ZERO = "\n0 upgraded, 0 newly installed, 0 to remove"
|
|
|
390
390
|
APTITUDE_ZERO = "\n0 packages upgraded, 0 newly installed, 0 to remove"
|
|
391
391
|
APT_LISTS_PATH = "/var/lib/apt/lists"
|
|
392
392
|
APT_UPDATE_SUCCESS_STAMP_PATH = "/var/lib/apt/periodic/update-success-stamp"
|
|
393
|
-
APT_MARK_INVALID_OP = 'Invalid operation'
|
|
394
|
-
APT_MARK_INVALID_OP_DEB6 = 'Usage: apt-mark [options] {markauto|unmarkauto} packages'
|
|
395
393
|
|
|
396
394
|
CLEAN_OP_CHANGED_STR = dict(
|
|
397
395
|
autoremove='The following packages will be REMOVED',
|
|
@@ -634,7 +632,7 @@ def expand_pkgspec_from_fnmatches(m, pkgspec, cache):
|
|
|
634
632
|
if pkgspec:
|
|
635
633
|
for pkgspec_pattern in pkgspec:
|
|
636
634
|
|
|
637
|
-
if not isinstance(pkgspec_pattern,
|
|
635
|
+
if not isinstance(pkgspec_pattern, str):
|
|
638
636
|
m.fail_json(msg="Invalid type for package name, expected string but got %s" % type(pkgspec_pattern))
|
|
639
637
|
|
|
640
638
|
pkgname_pattern, version_cmp, version = package_split(pkgspec_pattern)
|
|
@@ -690,26 +688,30 @@ def parse_diff(output):
|
|
|
690
688
|
return {'prepared': '\n'.join(diff[diff_start:diff_end])}
|
|
691
689
|
|
|
692
690
|
|
|
693
|
-
def
|
|
691
|
+
def mark_installed(m: AnsibleModule, packages: list[str], manual: bool) -> None:
|
|
692
|
+
"""Mark packages as manually or automatically installed."""
|
|
694
693
|
if not packages:
|
|
695
694
|
return
|
|
696
695
|
|
|
696
|
+
if manual:
|
|
697
|
+
mark_msg = "manually"
|
|
698
|
+
mark_op = "manual"
|
|
699
|
+
else:
|
|
700
|
+
mark_msg = "auto"
|
|
701
|
+
mark_op = "auto"
|
|
702
|
+
|
|
697
703
|
apt_mark_cmd_path = m.get_bin_path("apt-mark")
|
|
698
704
|
|
|
699
705
|
# https://github.com/ansible/ansible/issues/40531
|
|
700
706
|
if apt_mark_cmd_path is None:
|
|
701
|
-
m.warn("Could not find apt-mark binary, not marking package(s) as
|
|
707
|
+
m.warn(f"Could not find apt-mark binary, not marking package(s) as {mark_msg} installed.")
|
|
702
708
|
return
|
|
703
709
|
|
|
704
|
-
cmd =
|
|
710
|
+
cmd = [apt_mark_cmd_path, mark_op] + packages
|
|
705
711
|
rc, out, err = m.run_command(cmd)
|
|
706
712
|
|
|
707
|
-
if APT_MARK_INVALID_OP in err or APT_MARK_INVALID_OP_DEB6 in err:
|
|
708
|
-
cmd = "%s unmarkauto %s" % (apt_mark_cmd_path, ' '.join(packages))
|
|
709
|
-
rc, out, err = m.run_command(cmd)
|
|
710
|
-
|
|
711
713
|
if rc != 0:
|
|
712
|
-
m.fail_json(msg="
|
|
714
|
+
m.fail_json(msg=f"Command {shlex.join(cmd)!r} failed.", stdout=out, stderr=err, rc=rc)
|
|
713
715
|
|
|
714
716
|
|
|
715
717
|
def install(m, pkgspec, cache, upgrade=False, default_release=None,
|
|
@@ -835,7 +837,7 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None,
|
|
|
835
837
|
data = dict(changed=False)
|
|
836
838
|
|
|
837
839
|
if not build_dep and not m.check_mode:
|
|
838
|
-
|
|
840
|
+
mark_installed(m, package_names, manual=True)
|
|
839
841
|
|
|
840
842
|
return (status, data)
|
|
841
843
|
|
|
@@ -914,6 +916,9 @@ def install_deb(
|
|
|
914
916
|
dpkg_options=install_dpkg_options)
|
|
915
917
|
if not success:
|
|
916
918
|
m.fail_json(**retvals)
|
|
919
|
+
# Mark the dependencies as auto installed
|
|
920
|
+
# https://github.com/ansible/ansible/issues/78123
|
|
921
|
+
mark_installed(m, deps_to_install, manual=False)
|
|
917
922
|
changed = retvals.get('changed', False)
|
|
918
923
|
|
|
919
924
|
if pkgs_to_install:
|
|
@@ -508,7 +508,7 @@ class UbuntuSourcesList(SourcesList):
|
|
|
508
508
|
try:
|
|
509
509
|
rc, out, err = self.module.run_command([self.gpg_bin, '--list-packets', key_file])
|
|
510
510
|
except OSError as ex:
|
|
511
|
-
self.debug(f"Could check key against file {key_file!r}: {ex}")
|
|
511
|
+
self.module.debug(f"Could check key against file {key_file!r}: {ex}")
|
|
512
512
|
continue
|
|
513
513
|
|
|
514
514
|
if key_fingerprint in out:
|
ansible/modules/assemble.py
CHANGED
|
@@ -131,7 +131,6 @@ import re
|
|
|
131
131
|
import tempfile
|
|
132
132
|
|
|
133
133
|
from ansible.module_utils.basic import AnsibleModule
|
|
134
|
-
from ansible.module_utils.six import b, indexbytes
|
|
135
134
|
from ansible.module_utils.common.text.converters import to_native
|
|
136
135
|
|
|
137
136
|
|
|
@@ -141,6 +140,7 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno
|
|
|
141
140
|
tmp = os.fdopen(tmpfd, 'wb')
|
|
142
141
|
delimit_me = False
|
|
143
142
|
add_newline = False
|
|
143
|
+
b_linesep = os.linesep.encode()
|
|
144
144
|
|
|
145
145
|
for f in sorted(os.listdir(src_path)):
|
|
146
146
|
if compiled_regexp and not compiled_regexp.search(f):
|
|
@@ -153,7 +153,7 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno
|
|
|
153
153
|
|
|
154
154
|
# always put a newline between fragments if the previous fragment didn't end with a newline.
|
|
155
155
|
if add_newline:
|
|
156
|
-
tmp.write(
|
|
156
|
+
tmp.write(b_linesep)
|
|
157
157
|
|
|
158
158
|
# delimiters should only appear between fragments
|
|
159
159
|
if delimit_me:
|
|
@@ -163,16 +163,12 @@ def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None, igno
|
|
|
163
163
|
tmp.write(delimiter)
|
|
164
164
|
# always make sure there's a newline after the
|
|
165
165
|
# delimiter, so lines don't run together
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
# use indexbytes for compat
|
|
169
|
-
# chr(10) == '\n'
|
|
170
|
-
if indexbytes(delimiter, -1) != 10:
|
|
171
|
-
tmp.write(b('\n'))
|
|
166
|
+
if not delimiter.endswith(b_linesep):
|
|
167
|
+
tmp.write(b_linesep)
|
|
172
168
|
|
|
173
169
|
tmp.write(fragment_content)
|
|
174
170
|
delimit_me = True
|
|
175
|
-
if fragment_content.endswith(
|
|
171
|
+
if fragment_content.endswith(b_linesep):
|
|
176
172
|
add_newline = False
|
|
177
173
|
else:
|
|
178
174
|
add_newline = True
|
ansible/modules/blockinfile.py
CHANGED
|
@@ -102,6 +102,13 @@ options:
|
|
|
102
102
|
type: bool
|
|
103
103
|
default: no
|
|
104
104
|
version_added: '2.16'
|
|
105
|
+
encoding:
|
|
106
|
+
description:
|
|
107
|
+
- The character set in which the target file is encoded.
|
|
108
|
+
- For a list of available built-in encodings, see U(https://docs.python.org/3/library/codecs.html#standard-encodings)
|
|
109
|
+
type: str
|
|
110
|
+
default: utf-8
|
|
111
|
+
version_added: '2.20'
|
|
105
112
|
notes:
|
|
106
113
|
- When using C(with_*) loops be aware that if you do not set a unique mark the block will be overwritten on each iteration.
|
|
107
114
|
- As of Ansible 2.3, the O(dest) option has been changed to O(path) as default, but O(dest) still works as well.
|
|
@@ -192,15 +199,16 @@ EXAMPLES = r"""
|
|
|
192
199
|
import re
|
|
193
200
|
import os
|
|
194
201
|
import tempfile
|
|
195
|
-
|
|
202
|
+
|
|
196
203
|
from ansible.module_utils.basic import AnsibleModule
|
|
197
|
-
from ansible.module_utils.common.text.converters import
|
|
204
|
+
from ansible.module_utils.common.text.converters import to_native
|
|
198
205
|
|
|
199
206
|
|
|
200
|
-
def write_changes(module, contents, path):
|
|
207
|
+
def write_changes(module, contents, path, encoding=None):
|
|
201
208
|
|
|
202
209
|
tmpfd, tmpfile = tempfile.mkstemp(dir=module.tmpdir)
|
|
203
|
-
with
|
|
210
|
+
# newline param set to translate newline sequences with system default line separator
|
|
211
|
+
with os.fdopen(tmpfd, 'w', encoding=encoding, newline=None) as tf:
|
|
204
212
|
tf.write(contents)
|
|
205
213
|
|
|
206
214
|
validate = module.params.get('validate', None)
|
|
@@ -246,6 +254,7 @@ def main():
|
|
|
246
254
|
marker_end=dict(type='str', default='END'),
|
|
247
255
|
append_newline=dict(type='bool', default=False),
|
|
248
256
|
prepend_newline=dict(type='bool', default=False),
|
|
257
|
+
encoding=dict(type='str', default='utf-8'),
|
|
249
258
|
),
|
|
250
259
|
mutually_exclusive=[['insertbefore', 'insertafter']],
|
|
251
260
|
add_file_common_args=True,
|
|
@@ -254,6 +263,8 @@ def main():
|
|
|
254
263
|
params = module.params
|
|
255
264
|
path = params['path']
|
|
256
265
|
|
|
266
|
+
encoding = module.params.get('encoding', None)
|
|
267
|
+
|
|
257
268
|
if os.path.isdir(path):
|
|
258
269
|
module.fail_json(rc=256,
|
|
259
270
|
msg='Path %s is a directory !' % path)
|
|
@@ -274,7 +285,8 @@ def main():
|
|
|
274
285
|
original = None
|
|
275
286
|
lines = []
|
|
276
287
|
else:
|
|
277
|
-
|
|
288
|
+
# newline param set to preserve newline sequences read from file
|
|
289
|
+
with open(path, 'r', encoding=encoding, newline='') as f:
|
|
278
290
|
original = f.read()
|
|
279
291
|
lines = original.splitlines(True)
|
|
280
292
|
|
|
@@ -288,10 +300,12 @@ def main():
|
|
|
288
300
|
|
|
289
301
|
insertbefore = params['insertbefore']
|
|
290
302
|
insertafter = params['insertafter']
|
|
291
|
-
block =
|
|
292
|
-
marker =
|
|
303
|
+
block = params['block']
|
|
304
|
+
marker = params['marker']
|
|
293
305
|
present = params['state'] == 'present'
|
|
294
|
-
|
|
306
|
+
|
|
307
|
+
line_separator = os.linesep
|
|
308
|
+
blank_line = [line_separator]
|
|
295
309
|
|
|
296
310
|
if not present and not path_exists:
|
|
297
311
|
module.exit_json(changed=False, msg="File %s not present" % path)
|
|
@@ -300,17 +314,19 @@ def main():
|
|
|
300
314
|
insertafter = 'EOF'
|
|
301
315
|
|
|
302
316
|
if insertafter not in (None, 'EOF'):
|
|
303
|
-
insertre = re.compile(
|
|
317
|
+
insertre = re.compile(insertafter)
|
|
304
318
|
elif insertbefore not in (None, 'BOF'):
|
|
305
|
-
insertre = re.compile(
|
|
319
|
+
insertre = re.compile(insertbefore)
|
|
306
320
|
else:
|
|
307
321
|
insertre = None
|
|
308
322
|
|
|
309
|
-
marker0 = re.sub(
|
|
310
|
-
marker1 = re.sub(
|
|
323
|
+
marker0 = re.sub(r'{mark}', params['marker_begin'], marker) + line_separator
|
|
324
|
+
marker1 = re.sub(r'{mark}', params['marker_end'], marker) + line_separator
|
|
325
|
+
|
|
311
326
|
if present and block:
|
|
312
|
-
if not block.endswith(
|
|
313
|
-
block +=
|
|
327
|
+
if not block.endswith(line_separator):
|
|
328
|
+
block += line_separator
|
|
329
|
+
|
|
314
330
|
blocklines = [marker0] + block.splitlines(True) + [marker1]
|
|
315
331
|
else:
|
|
316
332
|
blocklines = []
|
|
@@ -329,9 +345,9 @@ def main():
|
|
|
329
345
|
match = insertre.search(original)
|
|
330
346
|
if match:
|
|
331
347
|
if insertafter:
|
|
332
|
-
n0 =
|
|
348
|
+
n0 = original.count('\n', 0, match.end())
|
|
333
349
|
elif insertbefore:
|
|
334
|
-
n0 =
|
|
350
|
+
n0 = original.count('\n', 0, match.start())
|
|
335
351
|
else:
|
|
336
352
|
for i, line in enumerate(lines):
|
|
337
353
|
if insertre.search(line):
|
|
@@ -352,15 +368,15 @@ def main():
|
|
|
352
368
|
|
|
353
369
|
# Ensure there is a line separator before the block of lines to be inserted
|
|
354
370
|
if n0 > 0:
|
|
355
|
-
if not lines[n0 - 1].endswith(
|
|
356
|
-
lines[n0 - 1] +=
|
|
371
|
+
if not lines[n0 - 1].endswith(line_separator):
|
|
372
|
+
lines[n0 - 1] += line_separator
|
|
357
373
|
|
|
358
374
|
# Before the block: check if we need to prepend a blank line
|
|
359
375
|
# If yes, we need to add the blank line if we are not at the beginning of the file
|
|
360
376
|
# and the previous line is not a blank line
|
|
361
377
|
# In both cases, we need to shift by one on the right the inserting position of the block
|
|
362
378
|
if params['prepend_newline'] and present:
|
|
363
|
-
if n0 != 0 and lines[n0 - 1] !=
|
|
379
|
+
if n0 != 0 and lines[n0 - 1] != line_separator:
|
|
364
380
|
lines[n0:n0] = blank_line
|
|
365
381
|
n0 += 1
|
|
366
382
|
|
|
@@ -372,13 +388,13 @@ def main():
|
|
|
372
388
|
# and the line right after is not a blank line
|
|
373
389
|
if params['append_newline'] and present:
|
|
374
390
|
line_after_block = n0 + len(blocklines)
|
|
375
|
-
if line_after_block < len(lines) and lines[line_after_block] !=
|
|
391
|
+
if line_after_block < len(lines) and lines[line_after_block] != line_separator:
|
|
376
392
|
lines[line_after_block:line_after_block] = blank_line
|
|
377
393
|
|
|
378
394
|
if lines:
|
|
379
|
-
result =
|
|
395
|
+
result = ''.join(lines)
|
|
380
396
|
else:
|
|
381
|
-
result =
|
|
397
|
+
result = ''
|
|
382
398
|
|
|
383
399
|
if module._diff:
|
|
384
400
|
diff['after'] = result
|
|
@@ -402,7 +418,7 @@ def main():
|
|
|
402
418
|
backup_file = module.backup_local(path)
|
|
403
419
|
# We should always follow symlinks so that we change the real file
|
|
404
420
|
real_path = os.path.realpath(params['path'])
|
|
405
|
-
write_changes(module, result, real_path)
|
|
421
|
+
write_changes(module, result, real_path, encoding)
|
|
406
422
|
|
|
407
423
|
if module.check_mode and not path_exists:
|
|
408
424
|
module.exit_json(changed=changed, msg=msg, diff=diff)
|
ansible/modules/cron.py
CHANGED
|
@@ -219,20 +219,20 @@ import os
|
|
|
219
219
|
import platform
|
|
220
220
|
import pwd
|
|
221
221
|
import re
|
|
222
|
+
import shlex
|
|
222
223
|
import sys
|
|
223
224
|
import tempfile
|
|
224
225
|
|
|
225
226
|
from ansible.module_utils.basic import AnsibleModule
|
|
226
227
|
from ansible.module_utils.common.file import S_IRWU_RWG_RWO
|
|
227
228
|
from ansible.module_utils.common.text.converters import to_bytes, to_native
|
|
228
|
-
from ansible.module_utils.six.moves import shlex_quote
|
|
229
229
|
|
|
230
230
|
|
|
231
231
|
class CronTabError(Exception):
|
|
232
232
|
pass
|
|
233
233
|
|
|
234
234
|
|
|
235
|
-
class CronTab
|
|
235
|
+
class CronTab:
|
|
236
236
|
"""
|
|
237
237
|
CronTab object to write time based crontab file
|
|
238
238
|
|
|
@@ -243,8 +243,8 @@ class CronTab(object):
|
|
|
243
243
|
def __init__(self, module, user=None, cron_file=None):
|
|
244
244
|
self.module = module
|
|
245
245
|
self.user = user
|
|
246
|
-
self.root =
|
|
247
|
-
self.lines =
|
|
246
|
+
self.root = os.getuid() == 0
|
|
247
|
+
self.lines = []
|
|
248
248
|
self.ansible = "#Ansible: "
|
|
249
249
|
self.n_existing = ''
|
|
250
250
|
self.cron_cmd = self.module.get_bin_path('crontab', required=True)
|
|
@@ -264,7 +264,6 @@ class CronTab(object):
|
|
|
264
264
|
|
|
265
265
|
def read(self):
|
|
266
266
|
# Read in the crontab from the system
|
|
267
|
-
self.lines = []
|
|
268
267
|
if self.cron_file:
|
|
269
268
|
# read the cronfile
|
|
270
269
|
try:
|
|
@@ -280,7 +279,7 @@ class CronTab(object):
|
|
|
280
279
|
# FIXME: using safely quoted shell for now, but this really should be two non-shell calls instead.
|
|
281
280
|
(rc, out, err) = self.module.run_command(self._read_user_execute(), use_unsafe_shell=True)
|
|
282
281
|
|
|
283
|
-
if rc
|
|
282
|
+
if rc not in (0, 1): # 1 can mean that there are no jobs.
|
|
284
283
|
raise CronTabError("Unable to read crontab")
|
|
285
284
|
|
|
286
285
|
self.n_existing = out
|
|
@@ -300,11 +299,10 @@ class CronTab(object):
|
|
|
300
299
|
def is_empty(self):
|
|
301
300
|
if len(self.lines) == 0:
|
|
302
301
|
return True
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
return True
|
|
302
|
+
for line in self.lines:
|
|
303
|
+
if line.strip():
|
|
304
|
+
return False
|
|
305
|
+
return True
|
|
308
306
|
|
|
309
307
|
def write(self, backup_file=None):
|
|
310
308
|
"""
|
|
@@ -451,13 +449,10 @@ class CronTab(object):
|
|
|
451
449
|
if special:
|
|
452
450
|
if self.cron_file:
|
|
453
451
|
return "%s@%s %s %s" % (disable_prefix, special, self.user, job)
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
return "%s%s %s %s %s %s %s %s" % (disable_prefix, minute, hour, day, month, weekday, self.user, job)
|
|
459
|
-
else:
|
|
460
|
-
return "%s%s %s %s %s %s %s" % (disable_prefix, minute, hour, day, month, weekday, job)
|
|
452
|
+
return "%s@%s %s" % (disable_prefix, special, job)
|
|
453
|
+
if self.cron_file:
|
|
454
|
+
return "%s%s %s %s %s %s %s %s" % (disable_prefix, minute, hour, day, month, weekday, self.user, job)
|
|
455
|
+
return "%s%s %s %s %s %s %s" % (disable_prefix, minute, hour, day, month, weekday, job)
|
|
461
456
|
|
|
462
457
|
def get_jobnames(self):
|
|
463
458
|
jobnames = []
|
|
@@ -495,8 +490,7 @@ class CronTab(object):
|
|
|
495
490
|
|
|
496
491
|
if len(newlines) == 0:
|
|
497
492
|
return True
|
|
498
|
-
|
|
499
|
-
return False # TODO add some more error testing
|
|
493
|
+
return False # TODO add some more error testing
|
|
500
494
|
|
|
501
495
|
def _update_env(self, name, decl, addenvfunction):
|
|
502
496
|
newlines = []
|
|
@@ -529,13 +523,13 @@ class CronTab(object):
|
|
|
529
523
|
user = ''
|
|
530
524
|
if self.user:
|
|
531
525
|
if platform.system() == 'SunOS':
|
|
532
|
-
return "su %s -c '%s -l'" % (
|
|
533
|
-
|
|
534
|
-
return "%s -l %s" % (
|
|
535
|
-
|
|
536
|
-
return "%s %s %s" % (self.cron_cmd, '-l',
|
|
537
|
-
|
|
538
|
-
user = '-u %s' %
|
|
526
|
+
return "su %s -c '%s -l'" % (shlex.quote(self.user), shlex.quote(self.cron_cmd))
|
|
527
|
+
if platform.system() == 'AIX':
|
|
528
|
+
return "%s -l %s" % (shlex.quote(self.cron_cmd), shlex.quote(self.user))
|
|
529
|
+
if platform.system() == 'HP-UX':
|
|
530
|
+
return "%s %s %s" % (self.cron_cmd, '-l', shlex.quote(self.user))
|
|
531
|
+
if pwd.getpwuid(os.getuid())[0] != self.user:
|
|
532
|
+
user = '-u %s' % shlex.quote(self.user)
|
|
539
533
|
return "%s %s %s" % (self.cron_cmd, user, '-l')
|
|
540
534
|
|
|
541
535
|
def _write_execute(self, path):
|
|
@@ -546,10 +540,10 @@ class CronTab(object):
|
|
|
546
540
|
if self.user:
|
|
547
541
|
if platform.system() in ['SunOS', 'HP-UX', 'AIX']:
|
|
548
542
|
return "chown %s %s ; su '%s' -c '%s %s'" % (
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
user = '-u %s' %
|
|
552
|
-
return "%s %s %s" % (self.cron_cmd, user,
|
|
543
|
+
shlex.quote(self.user), shlex.quote(path), shlex.quote(self.user), self.cron_cmd, shlex.quote(path))
|
|
544
|
+
if pwd.getpwuid(os.getuid())[0] != self.user:
|
|
545
|
+
user = '-u %s' % shlex.quote(self.user)
|
|
546
|
+
return "%s %s %s" % (self.cron_cmd, user, shlex.quote(path))
|
|
553
547
|
|
|
554
548
|
|
|
555
549
|
def main():
|
|
@@ -668,7 +662,7 @@ def main():
|
|
|
668
662
|
|
|
669
663
|
# if requested make a backup before making a change
|
|
670
664
|
if backup and not module.check_mode:
|
|
671
|
-
(
|
|
665
|
+
(dummy, backup_file) = tempfile.mkstemp(prefix='crontab')
|
|
672
666
|
crontab.write(backup_file)
|
|
673
667
|
|
|
674
668
|
if env:
|
|
@@ -763,9 +757,6 @@ def main():
|
|
|
763
757
|
|
|
764
758
|
module.exit_json(**res_args)
|
|
765
759
|
|
|
766
|
-
# --- should never get here
|
|
767
|
-
module.exit_json(msg="Unable to execute cron task.")
|
|
768
|
-
|
|
769
760
|
|
|
770
761
|
if __name__ == '__main__':
|
|
771
762
|
main()
|
|
@@ -67,6 +67,17 @@ options:
|
|
|
67
67
|
- Determines the path to the C(InRelease) file, relative to the normal
|
|
68
68
|
position of an C(InRelease) file.
|
|
69
69
|
type: str
|
|
70
|
+
install_python_debian:
|
|
71
|
+
description:
|
|
72
|
+
- Whether to automatically try to install the Python C(debian) library or not, if it is not already installed.
|
|
73
|
+
Without this library, the module does not work.
|
|
74
|
+
- Runs C(apt install python3-debian).
|
|
75
|
+
- Only works with the system Python. If you are using a Python on the remote that is not
|
|
76
|
+
the system Python, set O(install_python_debian=false) and ensure that the Python C(debian) library
|
|
77
|
+
for your Python version is installed some other way.
|
|
78
|
+
type: bool
|
|
79
|
+
default: false
|
|
80
|
+
version_added: '2.20'
|
|
70
81
|
languages:
|
|
71
82
|
description:
|
|
72
83
|
- Defines which languages information such as translated
|
|
@@ -228,6 +239,7 @@ key_filename:
|
|
|
228
239
|
|
|
229
240
|
import os
|
|
230
241
|
import re
|
|
242
|
+
import sys
|
|
231
243
|
import tempfile
|
|
232
244
|
import textwrap
|
|
233
245
|
|
|
@@ -235,9 +247,9 @@ from ansible.module_utils.basic import AnsibleModule
|
|
|
235
247
|
from ansible.module_utils.basic import missing_required_lib
|
|
236
248
|
from ansible.module_utils.common.collections import is_sequence
|
|
237
249
|
from ansible.module_utils.common.file import S_IRWXU_RXG_RXO, S_IRWU_RG_RO
|
|
250
|
+
from ansible.module_utils.common.respawn import has_respawned, probe_interpreters_for_module, respawn_module
|
|
238
251
|
from ansible.module_utils.common.text.converters import to_bytes
|
|
239
252
|
from ansible.module_utils.common.text.converters import to_native
|
|
240
|
-
from ansible.module_utils.six import raise_from # type: ignore[attr-defined]
|
|
241
253
|
from ansible.module_utils.urls import generic_urlparse
|
|
242
254
|
from ansible.module_utils.urls import open_url
|
|
243
255
|
from ansible.module_utils.urls import get_user_agent
|
|
@@ -326,7 +338,7 @@ def write_signed_by_key(module, v, slug):
|
|
|
326
338
|
try:
|
|
327
339
|
r = open_url(v, http_agent=get_user_agent())
|
|
328
340
|
except Exception as exc:
|
|
329
|
-
|
|
341
|
+
raise RuntimeError('Could not fetch signed_by key.') from exc
|
|
330
342
|
else:
|
|
331
343
|
b_data = r.read()
|
|
332
344
|
else:
|
|
@@ -357,6 +369,21 @@ def write_signed_by_key(module, v, slug):
|
|
|
357
369
|
return changed, filename, None
|
|
358
370
|
|
|
359
371
|
|
|
372
|
+
def install_python_debian(module, deb_pkg_name):
|
|
373
|
+
|
|
374
|
+
if not module.check_mode:
|
|
375
|
+
apt_path = module.get_bin_path('apt', required=True)
|
|
376
|
+
if apt_path:
|
|
377
|
+
rc, so, se = module.run_command([apt_path, 'update'])
|
|
378
|
+
if rc != 0:
|
|
379
|
+
module.fail_json(msg=f"Failed update while auto installing {deb_pkg_name} due to '{se.strip()}'")
|
|
380
|
+
rc, so, se = module.run_command([apt_path, 'install', deb_pkg_name, '-y', '-q'])
|
|
381
|
+
if rc != 0:
|
|
382
|
+
module.fail_json(msg=f"Failed to auto-install {deb_pkg_name} due to : '{se.strip()}'")
|
|
383
|
+
else:
|
|
384
|
+
module.fail_json(msg=f"{deb_pkg_name} must be installed to use check mode")
|
|
385
|
+
|
|
386
|
+
|
|
360
387
|
def main():
|
|
361
388
|
module = AnsibleModule(
|
|
362
389
|
argument_spec={
|
|
@@ -395,6 +422,10 @@ def main():
|
|
|
395
422
|
'inrelease_path': {
|
|
396
423
|
'type': 'str',
|
|
397
424
|
},
|
|
425
|
+
'install_python_debian': {
|
|
426
|
+
'type': 'bool',
|
|
427
|
+
'default': False,
|
|
428
|
+
},
|
|
398
429
|
'languages': {
|
|
399
430
|
'elements': 'str',
|
|
400
431
|
'type': 'list',
|
|
@@ -453,8 +484,53 @@ def main():
|
|
|
453
484
|
)
|
|
454
485
|
|
|
455
486
|
if not HAS_DEBIAN:
|
|
456
|
-
|
|
457
|
-
|
|
487
|
+
deb_pkg_name = 'python3-debian'
|
|
488
|
+
# This interpreter can't see the debian Python library- we'll do the following to try and fix that as per
|
|
489
|
+
# the apt_repository module:
|
|
490
|
+
# 1) look in common locations for system-owned interpreters that can see it; if we find one, respawn under it
|
|
491
|
+
# 2) finding none, try to install a matching python-debian package for the current interpreter version;
|
|
492
|
+
# we limit to the current interpreter version to try and avoid installing a whole other Python just
|
|
493
|
+
# for deb support
|
|
494
|
+
# 3) if we installed a support package, try to respawn under what we think is the right interpreter (could be
|
|
495
|
+
# the current interpreter again, but we'll let it respawn anyway for simplicity)
|
|
496
|
+
# 4) if still not working, return an error and give up (some corner cases not covered, but this shouldn't be
|
|
497
|
+
# made any more complex than it already is to try and cover more, eg, custom interpreters taking over
|
|
498
|
+
# system locations)
|
|
499
|
+
|
|
500
|
+
if has_respawned():
|
|
501
|
+
# this shouldn't be possible; short-circuit early if it happens...
|
|
502
|
+
module.fail_json(msg=f"{deb_pkg_name} must be installed and visible from {sys.executable}.")
|
|
503
|
+
|
|
504
|
+
interpreters = ['/usr/bin/python3', '/usr/bin/python']
|
|
505
|
+
|
|
506
|
+
interpreter = probe_interpreters_for_module(interpreters, 'debian')
|
|
507
|
+
|
|
508
|
+
if interpreter:
|
|
509
|
+
# found the Python bindings; respawn this module under the interpreter where we found them
|
|
510
|
+
respawn_module(interpreter)
|
|
511
|
+
# this is the end of the line for this process, it will exit here once the respawned module has completed
|
|
512
|
+
|
|
513
|
+
# don't make changes if we're in check_mode
|
|
514
|
+
if module.check_mode:
|
|
515
|
+
module.fail_json(msg=f"{deb_pkg_name} must be installed to use check mode. If run with install_python_debian, this module can auto-install it.")
|
|
516
|
+
|
|
517
|
+
if module.params['install_python_debian']:
|
|
518
|
+
install_python_debian(module, deb_pkg_name)
|
|
519
|
+
else:
|
|
520
|
+
module.fail_json(msg=f'{deb_pkg_name} is not installed, and install_python_debian is False')
|
|
521
|
+
|
|
522
|
+
# try again to find the bindings in common places
|
|
523
|
+
interpreter = probe_interpreters_for_module(interpreters, 'debian')
|
|
524
|
+
|
|
525
|
+
if interpreter:
|
|
526
|
+
# found the Python bindings; respawn this module under the interpreter where we found them
|
|
527
|
+
# NB: respawn is somewhat wasteful if it's this interpreter, but simplifies the code
|
|
528
|
+
respawn_module(interpreter)
|
|
529
|
+
# this is the end of the line for this process, it will exit here once the respawned module has completed
|
|
530
|
+
else:
|
|
531
|
+
# we've done all we can do; just tell the user it's busted and get out
|
|
532
|
+
module.fail_json(msg=missing_required_lib(deb_pkg_name),
|
|
533
|
+
exception=DEBIAN_IMP_ERR)
|
|
458
534
|
|
|
459
535
|
check_mode = module.check_mode
|
|
460
536
|
|
|
@@ -510,14 +586,9 @@ def main():
|
|
|
510
586
|
elif is_sequence(value):
|
|
511
587
|
value = format_list(value)
|
|
512
588
|
elif key == 'signed_by':
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
changed |= key_changed
|
|
517
|
-
except RuntimeError as exc:
|
|
518
|
-
module.fail_json(
|
|
519
|
-
msg='Could not fetch signed_by key: %s' % to_native(exc)
|
|
520
|
-
)
|
|
589
|
+
key_changed, signed_by_filename, signed_by_data = write_signed_by_key(module, value, slug)
|
|
590
|
+
value = signed_by_filename or signed_by_data
|
|
591
|
+
changed |= key_changed
|
|
521
592
|
|
|
522
593
|
if value.count('\n') > 0:
|
|
523
594
|
value = format_multiline(value)
|