ansible-core 2.18.6__py3-none-any.whl → 2.18.7__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/cli/pull.py CHANGED
@@ -31,6 +31,34 @@ from ansible.utils.display import Display
31
31
 
32
32
  display = Display()
33
33
 
34
+ SAFE_OUTPUT_ENV = {
35
+ 'ANSIBLE_CALLBACK_RESULT_FORMAT': 'json',
36
+ 'ANSIBLE_LOAD_CALLBACK_PLUGINS': '0',
37
+ }
38
+
39
+
40
+ def safe_output_env(f):
41
+
42
+ def wrapper(*args, **kwargs):
43
+
44
+ orig = {}
45
+
46
+ for k, v in SAFE_OUTPUT_ENV.items():
47
+ orig[k] = os.environ.get(k, None)
48
+ os.environ[k] = v
49
+
50
+ result = f(*args, **kwargs)
51
+
52
+ for key in orig.keys():
53
+ if orig[key] is None:
54
+ del os.environ[key]
55
+ else:
56
+ os.environ[key] = orig[key]
57
+
58
+ return result
59
+
60
+ return wrapper
61
+
34
62
 
35
63
  class PullCLI(CLI):
36
64
  ''' Used to pull a remote copy of ansible on each managed node,
@@ -42,7 +70,7 @@ class PullCLI(CLI):
42
70
  you should use an external scheduler and/or locking to ensure there are no clashing operations.
43
71
 
44
72
  The setup playbook can be tuned to change the cron frequency, logging locations, and parameters to ansible-pull.
45
- This is useful both for extreme scale-out as well as periodic remediation.
73
+ This is useful both for extreme scale-out and periodic remediation.
46
74
  Usage of the 'fetch' module to retrieve logs from ansible-pull runs would be an
47
75
  excellent way to gather and analyze remote logs from ansible-pull.
48
76
  '''
@@ -76,8 +104,9 @@ class PullCLI(CLI):
76
104
  return inv_opts
77
105
 
78
106
  def init_parser(self):
79
- ''' create an options parser for bin/ansible '''
107
+ """ Specific args/option parser for pull """
80
108
 
109
+ # signature is different from parent as caller should not need to add usage/desc
81
110
  super(PullCLI, self).init_parser(
82
111
  usage='%prog -U <repository> [options] [<playbook.yml>]',
83
112
  desc="pulls playbooks from a VCS repo and executes them on target host")
@@ -106,10 +135,12 @@ class PullCLI(CLI):
106
135
  help='path to the directory to which Ansible will checkout the repository.')
107
136
  self.parser.add_argument('-U', '--url', dest='url', default=None, help='URL of the playbook repository')
108
137
  self.parser.add_argument('--full', dest='fullclone', action='store_true', help='Do a full clone, instead of a shallow one.')
138
+ # TODO: resolve conflict with check mode, added manually below
109
139
  self.parser.add_argument('-C', '--checkout', dest='checkout',
110
140
  help='branch/tag/commit to checkout. Defaults to behavior of repository module.')
111
141
  self.parser.add_argument('--accept-host-key', default=False, dest='accept_host_key', action='store_true',
112
142
  help='adds the hostkey for the repo url if not already added')
143
+ # Overloaded with adhoc ... but really passthrough to adhoc
113
144
  self.parser.add_argument('-m', '--module-name', dest='module_name', default=self.DEFAULT_REPO_TYPE,
114
145
  help='Repository module name, which ansible will use to check out the repo. Choices are %s. Default is %s.'
115
146
  % (self.REPO_CHOICES, self.DEFAULT_REPO_TYPE))
@@ -121,7 +152,7 @@ class PullCLI(CLI):
121
152
  self.parser.add_argument('--track-subs', dest='tracksubs', default=False, action='store_true',
122
153
  help='submodules will track the latest changes. This is equivalent to specifying the --remote flag to git submodule update')
123
154
  # add a subset of the check_opts flag group manually, as the full set's
124
- # shortcodes conflict with above --checkout/-C
155
+ # shortcodes conflict with above --checkout/-C, see to-do above
125
156
  self.parser.add_argument("--check", default=False, dest='check', action='store_true',
126
157
  help="don't make any changes; instead, try to predict some of the changes that may occur")
127
158
  self.parser.add_argument("--diff", default=C.DIFF_ALWAYS, dest='diff', action='store_true',
@@ -177,7 +208,7 @@ class PullCLI(CLI):
177
208
  limit_opts = 'localhost,127.0.0.1'
178
209
  base_opts = '-c local '
179
210
  if context.CLIARGS['verbosity'] > 0:
180
- base_opts += ' -%s' % ''.join(["v" for x in range(0, context.CLIARGS['verbosity'])])
211
+ base_opts += ' -%s' % ''.join(["v" for dummy in range(0, context.CLIARGS['verbosity'])])
181
212
 
182
213
  # Attempt to use the inventory passed in as an argument
183
214
  # It might not yet have been downloaded so use localhost as default
@@ -250,16 +281,22 @@ class PullCLI(CLI):
250
281
  # RUN the Checkout command
251
282
  display.debug("running ansible with VCS module to checkout repo")
252
283
  display.vvvv('EXEC: %s' % cmd)
253
- rc, b_out, b_err = run_cmd(cmd, live=True)
284
+ rc, b_out, b_err = safe_output_env(run_cmd)(cmd, live=True)
254
285
 
255
286
  if rc != 0:
256
287
  if context.CLIARGS['force']:
257
288
  display.warning("Unable to update repository. Continuing with (forced) run of playbook.")
258
289
  else:
259
290
  return rc
260
- elif context.CLIARGS['ifchanged'] and b'"changed": true' not in b_out:
261
- display.display("Repository has not changed, quitting.")
262
- return 0
291
+ elif context.CLIARGS['ifchanged']:
292
+ # detect json/yaml/header, any count as 'changed'
293
+ for detect in (b'"changed": true', b"changed: True", b"| CHANGED =>"):
294
+ if detect in b_out:
295
+ break
296
+ else:
297
+ # no change, we bail
298
+ display.display(f"Repository has not changed, quitting: {b_out!r}")
299
+ return 0
263
300
 
264
301
  playbook = self.select_playbook(context.CLIARGS['dest'])
265
302
  if playbook is None:
@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.18.6'
20
+ __version__ = '2.18.7'
21
21
  __author__ = 'Ansible, Inc.'
22
22
  __codename__ = "Fool in the Rain"
ansible/modules/dnf5.py CHANGED
@@ -355,7 +355,7 @@ from ansible.module_utils.yumdnf import YumDnf, yumdnf_argument_spec
355
355
 
356
356
  libdnf5 = None
357
357
  # Through dnf5-5.2.12 all exceptions raised through swig became RuntimeError
358
- LIBDNF5_ERROR = RuntimeError
358
+ LIBDNF5_ERRORS = RuntimeError
359
359
 
360
360
 
361
361
  def is_installed(base, spec):
@@ -413,7 +413,9 @@ def is_newer_version_installed(base, spec):
413
413
 
414
414
  try:
415
415
  spec_nevra = next(iter(libdnf5.rpm.Nevra.parse(spec)))
416
- except (LIBDNF5_ERROR, StopIteration):
416
+ except LIBDNF5_ERRORS:
417
+ return False
418
+ except StopIteration:
417
419
  return False
418
420
 
419
421
  spec_version = spec_nevra.get_version()
@@ -505,7 +507,7 @@ class Dnf5Module(YumDnf):
505
507
  os.environ["LANGUAGE"] = os.environ["LANG"] = locale
506
508
 
507
509
  global libdnf5
508
- global LIBDNF5_ERROR
510
+ global LIBDNF5_ERRORS
509
511
  has_dnf = True
510
512
  try:
511
513
  import libdnf5 # type: ignore[import]
@@ -514,7 +516,7 @@ class Dnf5Module(YumDnf):
514
516
 
515
517
  try:
516
518
  import libdnf5.exception # type: ignore[import-not-found]
517
- LIBDNF5_ERROR = libdnf5.exception.Error
519
+ LIBDNF5_ERRORS = (libdnf5.exception.Error, libdnf5.exception.NonLibdnf5Exception)
518
520
  except (ImportError, AttributeError):
519
521
  pass
520
522
 
@@ -560,15 +562,7 @@ class Dnf5Module(YumDnf):
560
562
  if self.conf_file:
561
563
  conf.config_file_path = self.conf_file
562
564
 
563
- try:
564
- base.load_config()
565
- except LIBDNF5_ERROR as e:
566
- self.module.fail_json(
567
- msg=str(e),
568
- conf_file=self.conf_file,
569
- failures=[],
570
- rc=1,
571
- )
565
+ base.load_config()
572
566
 
573
567
  if self.releasever is not None:
574
568
  variables = base.get_vars()
@@ -724,19 +718,13 @@ class Dnf5Module(YumDnf):
724
718
  goal.add_install(spec, settings)
725
719
  elif self.state in {"absent", "removed"}:
726
720
  for spec in self.names:
727
- try:
728
- goal.add_remove(spec, settings)
729
- except LIBDNF5_ERROR as e:
730
- self.module.fail_json(msg=str(e), failures=[], rc=1)
721
+ goal.add_remove(spec, settings)
731
722
  if self.autoremove:
732
723
  for pkg in get_unneeded_pkgs(base):
733
724
  goal.add_rpm_remove(pkg, settings)
734
725
 
735
726
  goal.set_allow_erasing(self.allowerasing)
736
- try:
737
- transaction = goal.resolve()
738
- except LIBDNF5_ERROR as e:
739
- self.module.fail_json(msg=str(e), failures=[], rc=1)
727
+ transaction = goal.resolve()
740
728
 
741
729
  if transaction.get_problems():
742
730
  failures = []
@@ -807,7 +795,11 @@ class Dnf5Module(YumDnf):
807
795
 
808
796
 
809
797
  def main():
810
- Dnf5Module(AnsibleModule(**yumdnf_argument_spec)).run()
798
+ module = AnsibleModule(**yumdnf_argument_spec)
799
+ try:
800
+ Dnf5Module(module).run()
801
+ except LIBDNF5_ERRORS as e:
802
+ module.fail_json(msg=str(e), failures=[], rc=1)
811
803
 
812
804
 
813
805
  if __name__ == "__main__":
ansible/modules/user.py CHANGED
@@ -490,6 +490,7 @@ uid:
490
490
 
491
491
 
492
492
  import ctypes.util
493
+ from datetime import datetime
493
494
  import grp
494
495
  import calendar
495
496
  import os
@@ -1279,11 +1280,16 @@ class User(object):
1279
1280
  env=env)
1280
1281
  out_buffer = b''
1281
1282
  err_buffer = b''
1283
+ first_prompt = b'Enter passphrase'
1284
+ second_prompt = b'Enter same passphrase again'
1285
+ prompt = first_prompt
1286
+ start = datetime.now()
1287
+ timeout = 900
1282
1288
  while p.poll() is None:
1283
1289
  r_list = select.select([master_out_fd, master_err_fd], [], [], 1)[0]
1284
- first_prompt = b'Enter passphrase (empty for no passphrase):'
1285
- second_prompt = b'Enter same passphrase again'
1286
- prompt = first_prompt
1290
+ now = datetime.now()
1291
+ if (now - start).seconds > timeout:
1292
+ return (1, '', f'Timeout after {timeout} while reading passphrase for SSH key')
1287
1293
  for fd in r_list:
1288
1294
  if fd == master_out_fd:
1289
1295
  chunk = os.read(master_out_fd, 10240)
ansible/playbook/task.py CHANGED
@@ -137,9 +137,8 @@ class Task(Base, Conditional, Taggable, CollectionSearch, Notifiable, Delegatabl
137
137
  def __repr__(self):
138
138
  ''' returns a human-readable representation of the task '''
139
139
  if self.action in C._ACTION_META:
140
- return "TASK: meta (%s)" % self.args['_raw_params']
141
- else:
142
- return "TASK: %s" % self.get_name()
140
+ return "TASK: meta (%s)" % self.args.get('_raw_params')
141
+ return "TASK: %s" % self.get_name()
143
142
 
144
143
  def _preprocess_with_loop(self, ds, new_ds, k, v):
145
144
  ''' take a lookup plugin name and store it correctly '''
@@ -23,8 +23,9 @@ DOCUMENTATION:
23
23
  default: True
24
24
  version_added: '2.9'
25
25
  allow_nan:
26
- description: When V(False), strict adherence to float value limits of the JSON specifications, so C(nan), C(inf) and C(-inf) values will produce errors.
27
- When V(True), JavaScript equivalents will be used (C(NaN), C(Infinity), C(-Infinity)).
26
+ description:
27
+ - When V(False), out-of-range float values C(nan), C(inf) and C(-inf) will result in an error.
28
+ - When V(True), out-of-range float values will be represented using their JavaScript equivalents, C(NaN), C(Infinity) and C(-Infinity).
28
29
  default: True
29
30
  type: bool
30
31
  check_circular:
@@ -42,8 +43,11 @@ DOCUMENTATION:
42
43
  separators:
43
44
  description: The C(item) and C(key) separator to be used in the serialized output,
44
45
  default may change depending on O(indent) and Python version.
45
- default: "(', ', ': ')"
46
- type: tuple
46
+ default:
47
+ - ', '
48
+ - ': '
49
+ type: list
50
+ elements: str
47
51
  skipkeys:
48
52
  description: If V(True), keys that are not basic Python types will be skipped.
49
53
  default: False
@@ -23,8 +23,9 @@ DOCUMENTATION:
23
23
  default: True
24
24
  version_added: '2.9'
25
25
  allow_nan:
26
- description: When V(False), strict adherence to float value limits of the JSON specification, so C(nan), C(inf) and C(-inf) values will produce errors.
27
- When V(True), JavaScript equivalents will be used (C(NaN), C(Infinity), C(-Infinity)).
26
+ description:
27
+ - When V(False), out-of-range float values C(nan), C(inf) and C(-inf) will result in an error.
28
+ - When V(True), out-of-range float values will be represented using their JavaScript equivalents, C(NaN), C(Infinity) and C(-Infinity).
28
29
  default: True
29
30
  type: bool
30
31
  check_circular:
ansible/plugins/list.py CHANGED
@@ -42,7 +42,7 @@ def get_composite_name(collection, name, path, depth):
42
42
  return '.'.join(composite)
43
43
 
44
44
 
45
- def _list_plugins_from_paths(ptype, dirs, collection, depth=0):
45
+ def _list_plugins_from_paths(ptype, dirs, collection, depth=0, docs=False):
46
46
  # TODO: update to use importlib.resources
47
47
 
48
48
  plugins = {}
@@ -77,14 +77,15 @@ def _list_plugins_from_paths(ptype, dirs, collection, depth=0):
77
77
  continue
78
78
 
79
79
  # actually recurse dirs
80
- plugins.update(_list_plugins_from_paths(ptype, [to_native(full_path)], collection, depth=depth + 1))
80
+ plugins.update(_list_plugins_from_paths(ptype, [to_native(full_path)], collection, depth=depth + 1, docs=docs))
81
81
  else:
82
82
  if any([
83
83
  plugin in C.IGNORE_FILES, # general files to ignore
84
84
  to_native(b_ext) in C.REJECT_EXTS, # general extensions to ignore
85
- b_ext in (b'.yml', b'.yaml', b'.json'), # ignore docs files TODO: constant!
85
+ b_ext in (b'.yml', b'.yaml', b'.json'), # ignore docs files
86
86
  plugin in IGNORE.get(bkey, ()), # plugin in reject list
87
87
  os.path.islink(full_path), # skip aliases, author should document in 'aliases' field
88
+ not docs and b_ext in (b''), # ignore no ext when looking for docs files
88
89
  ]):
89
90
  continue
90
91
 
@@ -147,7 +148,7 @@ def list_collection_plugins(ptype, collections, search_paths=None):
147
148
 
148
149
  # raise Exception('bad acr for %s, %s' % (collection, ptype))
149
150
 
150
- plugins.update(_list_plugins_from_paths(ptype, dirs, collection))
151
+ plugins.update(_list_plugins_from_paths(ptype, dirs, collection, docs=True))
151
152
 
152
153
  # return plugin and it's class object, None for those not verifiable or failing
153
154
  if ptype in ('module',):
@@ -126,6 +126,7 @@ _raw:
126
126
  elements: str
127
127
  """
128
128
 
129
+ import contextlib
129
130
  import os
130
131
  import string
131
132
  import time
@@ -269,15 +270,12 @@ def _get_lock(b_path):
269
270
  b_pathdir = os.path.dirname(b_path)
270
271
  lockfile_name = to_bytes("%s.ansible_lockfile" % hashlib.sha1(b_path).hexdigest())
271
272
  lockfile = os.path.join(b_pathdir, lockfile_name)
272
- if not os.path.exists(lockfile) and b_path != to_bytes('/dev/null'):
273
- try:
274
- makedirs_safe(b_pathdir, mode=0o700)
273
+ if b_path != b'/dev/null':
274
+ makedirs_safe(b_pathdir, mode=0o700)
275
+ with contextlib.suppress(FileExistsError):
275
276
  fd = os.open(lockfile, os.O_CREAT | os.O_EXCL)
276
277
  os.close(fd)
277
278
  first_process = True
278
- except OSError as e:
279
- if e.strerror != 'File exists':
280
- raise
281
279
 
282
280
  counter = 0
283
281
  # if the lock is got by other process, wait until it's released
ansible/release.py CHANGED
@@ -17,6 +17,6 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = '2.18.6'
20
+ __version__ = '2.18.7'
21
21
  __author__ = 'Ansible, Inc.'
22
22
  __codename__ = "Fool in the Rain"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ansible-core
3
- Version: 2.18.6
3
+ Version: 2.18.7
4
4
  Summary: Radically simple IT automation
5
5
  Author: Ansible Project
6
6
  Project-URL: Homepage, https://ansible.com/
@@ -3,7 +3,7 @@ ansible/__main__.py,sha256=24j-7-YT4lZ2fmV80JD-VRoYBnxR7YoP_VP-orJtDt0,796
3
3
  ansible/constants.py,sha256=dSgbrzNsmhYc4GQOWZvRm4XKgf--_MUWcMa_9_7l5Pc,9757
4
4
  ansible/context.py,sha256=oKYyfjfWpy8vDeProtqfnqSmuij_t75_5e5t0U_hQ1g,1933
5
5
  ansible/keyword_desc.yml,sha256=xD-MRMB8mSRaj2ADwRnjIEbOwJKbc6BYadouGPfS0mI,7462
6
- ansible/release.py,sha256=ZMGvBhjIYBbu0PK-Af5w7Y0WXwn7OabfHLxEkLdE5X8,836
6
+ ansible/release.py,sha256=kgfpSlBEBVUVgXzK0QgAVlMKRmSJmSHoG-xAFkQPvQs,836
7
7
  ansible/_vendor/__init__.py,sha256=2QBeBwT7uG7M3Aw-pIdCpt6XPtHMCpbEKfACYKA7xIg,2033
8
8
  ansible/cli/__init__.py,sha256=e0KjeLfG1Ketbwl-uOmQ-zXoq3_El80LnHTGu80d1gs,28111
9
9
  ansible/cli/adhoc.py,sha256=quJ9WzRzf3dz_dtDGmahNMffqyNVy1jzQCMo21YL5Qg,8194
@@ -13,7 +13,7 @@ ansible/cli/doc.py,sha256=tcJfWPadUSnXPXjMwVyhtkPBhq1ELxMNnbuox36WRIo,70807
13
13
  ansible/cli/galaxy.py,sha256=KXTPM-hXtamDZUZXHRPGs2BPpIaf3HztlgyH9wOys7Q,95000
14
14
  ansible/cli/inventory.py,sha256=TTVyNM1G2IkTthmISmTGqlr4KjZKGrRVOh9gIJfjGtk,16765
15
15
  ansible/cli/playbook.py,sha256=d0x_X0BXjxYjPJ-qc6JcyGxR6IzxdvnSjoT4tUtaGKQ,10865
16
- ansible/cli/pull.py,sha256=g3PsUQ2UTj2L9IRKhHXRNzJ7X-uzwmk4plpRHxZrWtM,17287
16
+ ansible/cli/pull.py,sha256=JcoSGOz-VwBswNhW8txnQinQy3ujTlRGTdzQUH1jHKU,18345
17
17
  ansible/cli/vault.py,sha256=dICxhXQMRMTguu7gJW8qhGohiNdGn1Xxubt1kf2fRBc,23118
18
18
  ansible/cli/arguments/__init__.py,sha256=_4taT82hZKKTzhdXKmIgqxWwuG21XZxF874V2k1e3us,168
19
19
  ansible/cli/arguments/option_helpers.py,sha256=YiiGDtsXIwFg8mZPeQnYHsEUgsjUfeLCRrpks8hUc_Q,18488
@@ -141,7 +141,7 @@ ansible/inventory/host.py,sha256=PDb5OTplhfpUIvdHiP2BckUOB1gUl302N-3sW0_sTyg,503
141
141
  ansible/inventory/manager.py,sha256=45mHgZTAkQ3IjAtrgsNzJXvynC-HIEor-JJE-V3xXN4,29454
142
142
  ansible/module_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
143
  ansible/module_utils/_text.py,sha256=VkWgAnSNVCbTQqZgllUObBFsH3uM4EUW5srl1UR9t1g,544
144
- ansible/module_utils/ansible_release.py,sha256=ZMGvBhjIYBbu0PK-Af5w7Y0WXwn7OabfHLxEkLdE5X8,836
144
+ ansible/module_utils/ansible_release.py,sha256=kgfpSlBEBVUVgXzK0QgAVlMKRmSJmSHoG-xAFkQPvQs,836
145
145
  ansible/module_utils/api.py,sha256=r4wd6XZGhUnxMF416Ry6ebgq8BIhjCPSPOvO2ZtrYxE,5785
146
146
  ansible/module_utils/basic.py,sha256=fogfpo_l7JtS34WvgwwOebmPfMhFjQaJN5CwjKgUJVE,86291
147
147
  ansible/module_utils/connection.py,sha256=8TviwCucQ7d_JILwaUHE4tCuNfR3U1WFkmxLMxWa8Rw,7671
@@ -296,7 +296,7 @@ ansible/modules/deb822_repository.py,sha256=SLJM8bBLc70WYu3-OA67wd5hMft3pznYAMIi
296
296
  ansible/modules/debconf.py,sha256=Y49U5pM6UpKvYAvDbOhYe6kmQFAaxjl7YoYnPrOaGGU,9362
297
297
  ansible/modules/debug.py,sha256=BFbzrU_vl-Try5DuLV20_sLgqxEJlPV9uOrgAtby2e8,2908
298
298
  ansible/modules/dnf.py,sha256=rsb28kjMMnTu-rPW0Pdnbs2RPyvfdhWgXeUORUSgzEI,52288
299
- ansible/modules/dnf5.py,sha256=uM_5OdV_kXCJ0PvZVehsm4Ir59NDOtbB7OugLNimlZ0,30572
299
+ ansible/modules/dnf5.py,sha256=VZ5KpEO1lZScawgmnsrdd2FVW2vyRpg4dikXvWcD6pA,30288
300
300
  ansible/modules/dpkg_selections.py,sha256=lTWBhmVFrf6PsV4_BoR23wVTJOloCH1YNPcAn0m7DTY,2805
301
301
  ansible/modules/expect.py,sha256=O4emRoJ09i3OLmVX5j84WHkGKWg6bMytYpZlExOrSmc,9369
302
302
  ansible/modules/fail.py,sha256=95z8jFyVaizwwupSce04kj1wwnOmbM0ooUX7mXluoyU,1659
@@ -347,7 +347,7 @@ ansible/modules/tempfile.py,sha256=lA9e8lyFXf9J5ud0R6Jkt8sIFyRcOwzhc9Jz-5_HOZQ,3
347
347
  ansible/modules/template.py,sha256=D1sm36GB_mEimH0CfWq1cJ4w1eRvpcsHwZ-ufVzC_Gs,4537
348
348
  ansible/modules/unarchive.py,sha256=wdSOFKhZqbAFq5j_tBZtUSamfr_EEW6_cTZDw-erMjs,45405
349
349
  ansible/modules/uri.py,sha256=UCANRxecG45I4HGtj1AX9k0I01w8dfTplWksejLHrIg,27846
350
- ansible/modules/user.py,sha256=w0RVtz89EA2JpAhwav_J-2mGFKnEfW7MxCTKeug-r14,123301
350
+ ansible/modules/user.py,sha256=0lEGObBxw_SfjJGJGi2sk6-V8Rwkvt1VfhdfWhuWyrA,123562
351
351
  ansible/modules/validate_argument_spec.py,sha256=XbWlUr4ElgLfdxo3qCN7M-IES_X2iTl3AgawzCOMQpo,3042
352
352
  ansible/modules/wait_for.py,sha256=rsx_PR73-BRImLNErVUM1o9wRdPlXkGu5y6FhJ8wLcY,27355
353
353
  ansible/modules/wait_for_connection.py,sha256=8ySz5bhK7LGSaT_7Jzk3jvACcnngyR2g_ziyFLKk6Rk,3367
@@ -387,7 +387,7 @@ ansible/playbook/play_context.py,sha256=BEOXI3xfqFw5AD_reKbJulpxJGgwYG-jLvs8RY4S
387
387
  ansible/playbook/playbook_include.py,sha256=IqdVFE5F7eEnCtl7839c_rh9yuc4A4Oz5iIyG1DtptU,7492
388
388
  ansible/playbook/role_include.py,sha256=NCgDHtXlOltJ0XXSgGTTxDVrLC6IBe_d9SgNGXtsI20,7575
389
389
  ansible/playbook/taggable.py,sha256=PfbiQhDDafwKja2yIknJTEAHPspb7tPmCRDEO_8gmvY,3165
390
- ansible/playbook/task.py,sha256=j5TbfZ27IDr1sSJDps1SVZfDWznzNyYJCO9heIeEZSM,21756
390
+ ansible/playbook/task.py,sha256=wLJfDRBZIAU5d9lsYOL12MwEz7jr1yu00kBQh1OuasY,21742
391
391
  ansible/playbook/task_include.py,sha256=RHqzspHMA7wuIswDd6szZYCymXiVqWlF1Jil_2yRMz4,5244
392
392
  ansible/playbook/role/__init__.py,sha256=gzHFBXgGKpqims6ucK5CkxiLvHxQ9Kt2Wcc41RMeNhQ,29699
393
393
  ansible/playbook/role/definition.py,sha256=ZKs9FI3kqJETFHMh-8lOH6xGY_g2siuTxYgQj5VkcDk,9550
@@ -395,7 +395,7 @@ ansible/playbook/role/include.py,sha256=9e4IvnD3JXqJUV-hB7riGgq0SjrqQGQHDg-cuJ1v
395
395
  ansible/playbook/role/metadata.py,sha256=HUuR5wCKAw-6urkAR4DKxUeOVsqFflSDHjZuWdBCmxo,5074
396
396
  ansible/playbook/role/requirement.py,sha256=CNgLa0J6zZk2YQ_aeALnjQvehkkFXhrK8LQQZs7Ztzc,4173
397
397
  ansible/plugins/__init__.py,sha256=Duv86JIZPu6-ln-MPzBbq08Ex0s6OuK7nPzohm0cMPU,5803
398
- ansible/plugins/list.py,sha256=EsSx2WprH-0SsgAktUPBccNFD6VWFvz04d1hh089k08,8920
398
+ ansible/plugins/list.py,sha256=Ymy3NjZd8HJQU_yyZgjgHDFSYL9JxEI_pzdGocapflM,9055
399
399
  ansible/plugins/loader.py,sha256=musEPf-GJK7lpHugJQyaMOaIP5ls3zU90Qn20DBjnQc,75153
400
400
  ansible/plugins/action/__init__.py,sha256=SwQ7kbw9Z_KvruDnejEhlAvILGnYOjNjxGjDKMJ1bfw,69013
401
401
  ansible/plugins/action/add_host.py,sha256=GtwF4uEDrjcFluIi7ql7AkatYOboJGIp4sH10cqPPHo,3579
@@ -523,8 +523,8 @@ ansible/plugins/filter/subelements.yml,sha256=JKHy2GRpOi5zLXZVRtmZoIs_J8sDEuAR0q
523
523
  ansible/plugins/filter/symmetric_difference.yml,sha256=2eqzKo8ZCtAY6xxd5f74TEHNhZ6rVeQVimMSRO_DgnU,1094
524
524
  ansible/plugins/filter/ternary.yml,sha256=HXfaNHqsRc698BBAxIBK11vMJnlYXOf6cpNIky8H41g,1555
525
525
  ansible/plugins/filter/to_datetime.yml,sha256=xm6YuP9cCV-5OzRxO0y8YKZuOt0nBYZe2tJHqtDUzfM,2691
526
- ansible/plugins/filter/to_json.yml,sha256=hIz4ppnypmQ-w9bn4zz1eGlK8xQ0rVaPGB4TWz3D2P0,2756
527
- ansible/plugins/filter/to_nice_json.yml,sha256=70ebCkLGbAsWGvXkrwu7kbILlWxgXBUad_RqUC9vWeY,2530
526
+ ansible/plugins/filter/to_json.yml,sha256=83GtE5oGoimh6RzkkY7cuF4-hqolzoD46WCRAtXzkOI,2791
527
+ ansible/plugins/filter/to_nice_json.yml,sha256=ezx2wgb3SG_mQh_B7aRDeWZqg65YTuh1zUonCjhtsTQ,2532
528
528
  ansible/plugins/filter/to_nice_yaml.yml,sha256=VZzJX6wEB690Zrd38_FOWwYYM3BaRgx50c1r10JNEuM,1589
529
529
  ansible/plugins/filter/to_uuid.yml,sha256=bUQBkaXfpLXVmF6RbGG12FI7RNO01bWjIPhhdzV2KpM,785
530
530
  ansible/plugins/filter/to_yaml.yml,sha256=F4f1WmvPNrBtgG7JzrvW7WNP-uml_f_tAj7RXITSPtM,1672
@@ -567,7 +567,7 @@ ansible/plugins/lookup/items.py,sha256=J7I-m_oc1URCFhTcemTZez_UmK-u9PdJA0BArBzj-
567
567
  ansible/plugins/lookup/lines.py,sha256=cQpo5zAsmrToe5zqL74QdisHVpz3YhZdWjiV02lGS8Y,2254
568
568
  ansible/plugins/lookup/list.py,sha256=MlpQUjl9a039EKvEjXkEiiDOsgm-wkmo4aVzdxLJLA4,1058
569
569
  ansible/plugins/lookup/nested.py,sha256=TDnGQbV0hLXhzg7bjHcf6ENP_U55C9mucdo6wIBVDR0,2649
570
- ansible/plugins/lookup/password.py,sha256=1-4KrxZVUIXtxqjpKsKEpHXTGB2QkWAxWyRXzKOWa3E,17585
570
+ ansible/plugins/lookup/password.py,sha256=1z10ewVQOhwGPmngxa8kveGCV4SdGLVCGf5tuYkT_h0,17500
571
571
  ansible/plugins/lookup/pipe.py,sha256=EeAr5qxkeysvZ-cyzMDHjbY8iYiHrX3Jt6jDaSWSHto,3031
572
572
  ansible/plugins/lookup/random_choice.py,sha256=d7oKWfExsvHKA2tOs-8UWnWNlFxu3y3kDkhKaaaTOxo,1543
573
573
  ansible/plugins/lookup/sequence.py,sha256=_s7YxBu1Eo_mbPodFRg0hui1EeTsr2e-5sPqh3jkeMI,8120
@@ -687,17 +687,17 @@ ansible/vars/hostvars.py,sha256=o11xrzDVYn23renGbb3lx3R-nH9qOjLFju5IYJanDxg,5324
687
687
  ansible/vars/manager.py,sha256=JF2KTL4iYSbcdnFNjhQPktwH05YhWJhTWtjSlF0qg9E,31260
688
688
  ansible/vars/plugins.py,sha256=PocWZPMqFl1LoNgWlGFNxwg9nZnUzhQmlXO4g7bcP2A,4503
689
689
  ansible/vars/reserved.py,sha256=Tsc4m2UwVce3dOvSWrjT2wB3lpNJtUyNZn45zNhsW0I,2869
690
- ansible_core-2.18.6.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
691
- ansible_core-2.18.6.dist-info/licenses/licenses/Apache-License.txt,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325
692
- ansible_core-2.18.6.dist-info/licenses/licenses/MIT-license.txt,sha256=jLXp2XurnyZKbye40g9tfmLGtVlxh3pPD4n8xNqX8xc,1023
693
- ansible_core-2.18.6.dist-info/licenses/licenses/PSF-license.txt,sha256=g7BC_H1qyg8Q1o5F76Vrm8ChSWYI5-dyj-CdGlNKBUo,2484
694
- ansible_core-2.18.6.dist-info/licenses/licenses/simplified_bsd.txt,sha256=8R5R7R7sOa0h1Fi6RNgFgHowHBfun-OVOMzJ4rKAk2w,1237
690
+ ansible_core-2.18.7.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
691
+ ansible_core-2.18.7.dist-info/licenses/licenses/Apache-License.txt,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325
692
+ ansible_core-2.18.7.dist-info/licenses/licenses/MIT-license.txt,sha256=jLXp2XurnyZKbye40g9tfmLGtVlxh3pPD4n8xNqX8xc,1023
693
+ ansible_core-2.18.7.dist-info/licenses/licenses/PSF-license.txt,sha256=g7BC_H1qyg8Q1o5F76Vrm8ChSWYI5-dyj-CdGlNKBUo,2484
694
+ ansible_core-2.18.7.dist-info/licenses/licenses/simplified_bsd.txt,sha256=8R5R7R7sOa0h1Fi6RNgFgHowHBfun-OVOMzJ4rKAk2w,1237
695
695
  ansible_test/__init__.py,sha256=20VPOj11c6Ut1Av9RaurgwJvFhMqkWG3vAvcCbecNKw,66
696
696
  ansible_test/_data/ansible.cfg,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
697
697
  ansible_test/_data/coveragerc,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
698
698
  ansible_test/_data/completion/docker.txt,sha256=Z5pvUK4XUkJV5qBW8QuBPk8BzuEnvYFQU7W_ULwycGE,648
699
699
  ansible_test/_data/completion/network.txt,sha256=BxVN0UxlVkRUrPi9MBArQOe6nR8exaow0oCAznUdfKQ,100
700
- ansible_test/_data/completion/remote.txt,sha256=qnV9FcKHL9hETVB3iVMoSX_Lo560bN_9MrpAMotuxV4,921
700
+ ansible_test/_data/completion/remote.txt,sha256=GcYgad_3SBIcndWmWmmWKQ4697XmSiVxak26HSFQe50,980
701
701
  ansible_test/_data/completion/windows.txt,sha256=T67veSrF2tqHC1W6Ddsq3LCBwMCBUmp9LoZBy1QlXOo,238
702
702
  ansible_test/_data/playbooks/posix_coverage_setup.yml,sha256=PgQNVzVTsNmfnu0sT2SAYiWtkMSOppfmh0oVmAsb7TQ,594
703
703
  ansible_test/_data/playbooks/posix_coverage_teardown.yml,sha256=xHci5QllwJymFtig-hsOXm-Wdrxz063JH14aIyRXhyc,212
@@ -788,7 +788,7 @@ ansible_test/_internal/classification/__init__.py,sha256=LVyApjvPsofXjdDaHrXnWl7
788
788
  ansible_test/_internal/classification/common.py,sha256=jd5VLRegcOX-GNTZqN_7PBzwKF6akFQYsPEltfynGtU,894
789
789
  ansible_test/_internal/classification/csharp.py,sha256=3QpVZjamTTG7h86oeVm7d4UMbyojPbBALHVqCpxS1ic,3241
790
790
  ansible_test/_internal/classification/powershell.py,sha256=i8t8LxG_-wDPpz1VlnvqAPpRGgVJsuA_xglMtCpibCc,3053
791
- ansible_test/_internal/classification/python.py,sha256=pltDeMQEDbtjyG15vAizCvygU8MHrPcqWSobU6z_8YY,13532
791
+ ansible_test/_internal/classification/python.py,sha256=0jWx8x6_UirsPIdCqPiMZTBS8-DrIEsHHsX57l69q8I,13885
792
792
  ansible_test/_internal/cli/__init__.py,sha256=kTB7TfN12k_VJGMXEuOSlu3huruIUTb8UIFkaFyMr_I,1427
793
793
  ansible_test/_internal/cli/actions.py,sha256=D3z2FdpJC1dpQR9Vu1662wW28_iqPpWeAC3rizzjVAA,3366
794
794
  ansible_test/_internal/cli/compat.py,sha256=U0JGicJeKB7eA0RqX9P_P_P9CZ860u-1EjPtGKXCaqc,23101
@@ -964,7 +964,7 @@ ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py,sha256=vn
964
964
  ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py,sha256=A6HawT60Q8Bz0WWajO8AS-HcTpGtm_YxMNASwaYvVH0,1998
965
965
  ansible_test/_util/target/sanity/compile/compile.py,sha256=iTRgiZHNO8DwjSqHBw8gPBbFtWnr-Zbd_ybymeazdtA,1302
966
966
  ansible_test/_util/target/sanity/import/importer.py,sha256=SGIu5uHzbw7vTItX3fzOEnim5pgtM1tz6UFoZyNzqc8,25149
967
- ansible_test/_util/target/setup/bootstrap.sh,sha256=QjJcNCUBRMeBaYwQtO1Ue8Om79ANM_utzAMvpyJpS1Q,12286
967
+ ansible_test/_util/target/setup/bootstrap.sh,sha256=T7Yx32uT8rcxLM6yNfmlrozFzpYeU2aaNddQarjxy-A,12991
968
968
  ansible_test/_util/target/setup/check_systemd_cgroup_v1.sh,sha256=Aq0T62x_KLtkGaWzYqWjvhchTqYFflrTbQET3h6xrT0,395
969
969
  ansible_test/_util/target/setup/probe_cgroups.py,sha256=wUHvjW_GXpcyMGw308w26T09cOtBW5EU7i9WagGDQ7o,659
970
970
  ansible_test/_util/target/setup/quiet_pip.py,sha256=d3bvh9k2XI_z8-vb3ZoI4lwL8LaFkwvjJE7PpApBlcw,1979
@@ -985,8 +985,8 @@ ansible_test/config/cloud-config-vultr.ini.template,sha256=XLKHk3lg_8ReQMdWfZzhh
985
985
  ansible_test/config/config.yml,sha256=1zdGucnIl6nIecZA7ISIANvqXiHWqq6Dthsk_6MUwNc,2642
986
986
  ansible_test/config/inventory.networking.template,sha256=bFNSk8zNQOaZ_twaflrY0XZ9mLwUbRLuNT0BdIFwvn4,1335
987
987
  ansible_test/config/inventory.winrm.template,sha256=1QU8W-GFLnYEw8yY9bVIvUAVvJYPM3hyoijf6-M7T00,1098
988
- ansible_core-2.18.6.dist-info/METADATA,sha256=2nF3LE3VLSYch7xE1nVJoO-YOTInMMY218tJoHU6Oz0,7690
989
- ansible_core-2.18.6.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
990
- ansible_core-2.18.6.dist-info/entry_points.txt,sha256=S9yJij5Im6FgRQxzkqSCnPQokC7PcWrDW_NSygZczJU,451
991
- ansible_core-2.18.6.dist-info/top_level.txt,sha256=IFbRLjAvih1DYzJWg3_F6t4sCzEMxRO7TOMNs6GkYHo,21
992
- ansible_core-2.18.6.dist-info/RECORD,,
988
+ ansible_core-2.18.7.dist-info/METADATA,sha256=8YSHvmWidFwHESV6KMJkWz8GWMy4-KEfo7OeCYf0Lek,7690
989
+ ansible_core-2.18.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
990
+ ansible_core-2.18.7.dist-info/entry_points.txt,sha256=S9yJij5Im6FgRQxzkqSCnPQokC7PcWrDW_NSygZczJU,451
991
+ ansible_core-2.18.7.dist-info/top_level.txt,sha256=IFbRLjAvih1DYzJWg3_F6t4sCzEMxRO7TOMNs6GkYHo,21
992
+ ansible_core-2.18.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -8,6 +8,7 @@ freebsd python_dir=/usr/local/bin become=su_sudo provider=aws arch=x86_64
8
8
  macos/14.3 python=3.11 python_dir=/usr/local/bin become=sudo provider=parallels arch=x86_64
9
9
  macos python_dir=/usr/local/bin become=sudo provider=parallels arch=x86_64
10
10
  rhel/9.4 python=3.9,3.12 become=sudo provider=aws arch=x86_64
11
+ rhel/10.0 python=3.12 become=sudo provider=aws arch=x86_64
11
12
  rhel become=sudo provider=aws arch=x86_64
12
13
  ubuntu/22.04 python=3.10 become=sudo provider=aws arch=x86_64
13
14
  ubuntu/24.04 python=3.12 become=sudo provider=aws arch=x86_64
@@ -220,6 +220,12 @@ def relative_to_absolute(name: str, level: int, module: str, path: str, lineno:
220
220
  else:
221
221
  parts = module.split('.')
222
222
 
223
+ if path.endswith('/__init__.py'):
224
+ # Ensure the correct relative module is calculated for both not_init.py and __init__.py:
225
+ # a/b/not_init.py -> a.b.not_init # used as-is
226
+ # a/b/__init__.py -> a.b # needs "__init__" part appended to ensure relative imports work
227
+ parts.append('__init__')
228
+
223
229
  if level >= len(parts):
224
230
  display.warning('Cannot resolve relative import "%s%s" above module "%s" at %s:%d' % ('.' * level, name, module, path, lineno))
225
231
  absolute_name = 'relative.abovelevel'
@@ -292,10 +292,41 @@ bootstrap_remote_rhel_9()
292
292
  done
293
293
  }
294
294
 
295
+ bootstrap_remote_rhel_10()
296
+ {
297
+ py_pkg_prefix="python3"
298
+
299
+ packages="
300
+ gcc
301
+ ${py_pkg_prefix}-devel
302
+ ${py_pkg_prefix}-pip
303
+ "
304
+
305
+ if [ "${controller}" ]; then
306
+ packages="
307
+ ${packages}
308
+ ${py_pkg_prefix}-cryptography
309
+ ${py_pkg_prefix}-jinja2
310
+ ${py_pkg_prefix}-packaging
311
+ ${py_pkg_prefix}-pyyaml
312
+ ${py_pkg_prefix}-resolvelib
313
+ "
314
+ fi
315
+
316
+ while true; do
317
+ # shellcheck disable=SC2086
318
+ dnf install -q -y ${packages} \
319
+ && break
320
+ echo "Failed to install packages. Sleeping before trying again..."
321
+ sleep 10
322
+ done
323
+ }
324
+
295
325
  bootstrap_remote_rhel()
296
326
  {
297
327
  case "${platform_version}" in
298
328
  9.*) bootstrap_remote_rhel_9 ;;
329
+ 10.*) bootstrap_remote_rhel_10 ;;
299
330
  esac
300
331
  }
301
332