ansible-core 2.18.0rc2__py3-none-any.whl → 2.18.1rc1__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/executor/task_executor.py +1 -0
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/csharp/Ansible.AccessToken.cs +33 -18
- ansible/module_utils/csharp/Ansible.Become.cs +87 -17
- ansible/modules/command.py +6 -7
- ansible/modules/dnf5.py +18 -0
- ansible/plugins/lookup/varnames.py +10 -4
- ansible/plugins/lookup/vars.py +10 -3
- ansible/release.py +1 -1
- ansible/template/__init__.py +1 -30
- ansible/template/native_helpers.py +118 -4
- ansible/vars/hostvars.py +4 -2
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/METADATA +4 -4
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/RECORD +24 -24
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/WHEEL +1 -1
- ansible_test/_internal/containers.py +7 -4
- ansible_test/_internal/util.py +3 -3
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/COPYING +0 -0
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/simplified_bsd.txt +0 -0
- {ansible_core-2.18.0rc2.dist-info → ansible_core-2.18.1rc1.dist-info}/top_level.txt +0 -0
|
@@ -150,6 +150,7 @@ class TaskExecutor:
|
|
|
150
150
|
if 'unreachable' in item and item['unreachable']:
|
|
151
151
|
item_ignore_unreachable = item.pop('_ansible_ignore_unreachable')
|
|
152
152
|
if not res.get('unreachable'):
|
|
153
|
+
res['unreachable'] = True
|
|
153
154
|
self._task.ignore_unreachable = item_ignore_unreachable
|
|
154
155
|
elif self._task.ignore_unreachable and not item_ignore_unreachable:
|
|
155
156
|
self._task.ignore_unreachable = item_ignore_unreachable
|
|
@@ -339,19 +339,47 @@ namespace Ansible.AccessToken
|
|
|
339
339
|
public static IEnumerable<SafeNativeHandle> EnumerateUserTokens(SecurityIdentifier sid,
|
|
340
340
|
TokenAccessLevels access = TokenAccessLevels.Query)
|
|
341
341
|
{
|
|
342
|
+
return EnumerateUserTokens(sid, access, (p, h) => true);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
public static IEnumerable<SafeNativeHandle> EnumerateUserTokens(
|
|
346
|
+
SecurityIdentifier sid,
|
|
347
|
+
TokenAccessLevels access,
|
|
348
|
+
Func<System.Diagnostics.Process, SafeNativeHandle, bool> processFilter)
|
|
349
|
+
{
|
|
350
|
+
// We always need the Query access level so we can query the TokenUser
|
|
351
|
+
access |= TokenAccessLevels.Query;
|
|
352
|
+
|
|
342
353
|
foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses())
|
|
343
354
|
{
|
|
344
|
-
// We always need the Query access level so we can query the TokenUser
|
|
345
355
|
using (process)
|
|
346
|
-
using (SafeNativeHandle
|
|
356
|
+
using (SafeNativeHandle processHandle = NativeMethods.OpenProcess(ProcessAccessFlags.QueryInformation, false, (UInt32)process.Id))
|
|
347
357
|
{
|
|
348
|
-
if (
|
|
358
|
+
if (processHandle.IsInvalid)
|
|
359
|
+
{
|
|
349
360
|
continue;
|
|
361
|
+
}
|
|
350
362
|
|
|
351
|
-
if (!
|
|
363
|
+
if (!processFilter(process, processHandle))
|
|
364
|
+
{
|
|
352
365
|
continue;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
SafeNativeHandle accessToken;
|
|
369
|
+
if (!NativeMethods.OpenProcessToken(processHandle, access, out accessToken))
|
|
370
|
+
{
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
using (accessToken)
|
|
375
|
+
{
|
|
376
|
+
if (!sid.Equals(GetTokenUser(accessToken)))
|
|
377
|
+
{
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
353
380
|
|
|
354
|
-
|
|
381
|
+
yield return accessToken;
|
|
382
|
+
}
|
|
355
383
|
}
|
|
356
384
|
}
|
|
357
385
|
}
|
|
@@ -440,18 +468,5 @@ namespace Ansible.AccessToken
|
|
|
440
468
|
for (int i = 0; i < array.Length; i++, ptrOffset = IntPtr.Add(ptrOffset, Marshal.SizeOf(typeof(T))))
|
|
441
469
|
array[i] = (T)Marshal.PtrToStructure(ptrOffset, typeof(T));
|
|
442
470
|
}
|
|
443
|
-
|
|
444
|
-
private static SafeNativeHandle TryOpenAccessToken(System.Diagnostics.Process process, TokenAccessLevels access)
|
|
445
|
-
{
|
|
446
|
-
try
|
|
447
|
-
{
|
|
448
|
-
using (SafeNativeHandle hProcess = OpenProcess(process.Id, ProcessAccessFlags.QueryInformation, false))
|
|
449
|
-
return OpenProcessToken(hProcess, access);
|
|
450
|
-
}
|
|
451
|
-
catch (Win32Exception)
|
|
452
|
-
{
|
|
453
|
-
return null;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
471
|
}
|
|
457
472
|
}
|
|
@@ -93,10 +93,21 @@ namespace Ansible.Become
|
|
|
93
93
|
CachedRemoteInteractive,
|
|
94
94
|
CachedUnlock
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
[Flags]
|
|
98
|
+
public enum ProcessChildProcessPolicyFlags
|
|
99
|
+
{
|
|
100
|
+
None = 0x0,
|
|
101
|
+
NoChildProcessCreation = 0x1,
|
|
102
|
+
AuditNoChildProcessCreation = 0x2,
|
|
103
|
+
AllowSecureProcessCreation = 0x4,
|
|
104
|
+
}
|
|
96
105
|
}
|
|
97
106
|
|
|
98
107
|
internal class NativeMethods
|
|
99
108
|
{
|
|
109
|
+
public const int ProcessChildProcessPolicy = 13;
|
|
110
|
+
|
|
100
111
|
[DllImport("advapi32.dll", SetLastError = true)]
|
|
101
112
|
public static extern bool AllocateLocallyUniqueId(
|
|
102
113
|
out Luid Luid);
|
|
@@ -116,6 +127,13 @@ namespace Ansible.Become
|
|
|
116
127
|
[DllImport("kernel32.dll")]
|
|
117
128
|
public static extern UInt32 GetCurrentThreadId();
|
|
118
129
|
|
|
130
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
131
|
+
public static extern bool GetProcessMitigationPolicy(
|
|
132
|
+
SafeNativeHandle hProcess,
|
|
133
|
+
int MitigationPolicy,
|
|
134
|
+
ref NativeHelpers.ProcessChildProcessPolicyFlags lpBuffer,
|
|
135
|
+
IntPtr dwLength);
|
|
136
|
+
|
|
119
137
|
[DllImport("user32.dll", SetLastError = true)]
|
|
120
138
|
public static extern NoopSafeHandle GetProcessWindowStation();
|
|
121
139
|
|
|
@@ -217,6 +235,7 @@ namespace Ansible.Become
|
|
|
217
235
|
};
|
|
218
236
|
private static int WINDOWS_STATION_ALL_ACCESS = 0x000F037F;
|
|
219
237
|
private static int DESKTOP_RIGHTS_ALL_ACCESS = 0x000F01FF;
|
|
238
|
+
private static bool _getProcessMitigationPolicySupported = true;
|
|
220
239
|
|
|
221
240
|
public static Result CreateProcessAsUser(string username, string password, string command)
|
|
222
241
|
{
|
|
@@ -333,12 +352,13 @@ namespace Ansible.Become
|
|
|
333
352
|
// Grant access to the current Windows Station and Desktop to the become user
|
|
334
353
|
GrantAccessToWindowStationAndDesktop(account);
|
|
335
354
|
|
|
336
|
-
// Try and impersonate a SYSTEM token
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
//
|
|
355
|
+
// Try and impersonate a SYSTEM token, we need a SYSTEM token to either become a well known service
|
|
356
|
+
// account or have administrative rights on the become access token.
|
|
357
|
+
// If we ultimately are becoming the SYSTEM account we want the token with the most privileges available.
|
|
358
|
+
// https://github.com/ansible/ansible/issues/71453
|
|
359
|
+
bool usedForProcess = becomeSid == "S-1-5-18";
|
|
340
360
|
systemToken = GetPrimaryTokenForUser(new SecurityIdentifier("S-1-5-18"),
|
|
341
|
-
new List<string>() { "SeTcbPrivilege" });
|
|
361
|
+
new List<string>() { "SeTcbPrivilege" }, usedForProcess);
|
|
342
362
|
if (systemToken != null)
|
|
343
363
|
{
|
|
344
364
|
try
|
|
@@ -356,9 +376,11 @@ namespace Ansible.Become
|
|
|
356
376
|
|
|
357
377
|
try
|
|
358
378
|
{
|
|
379
|
+
if (becomeSid == "S-1-5-18")
|
|
380
|
+
userTokens.Add(systemToken);
|
|
359
381
|
// Cannot use String.IsEmptyOrNull() as an empty string is an account that doesn't have a pass.
|
|
360
382
|
// We only use S4U if no password was defined or it was null
|
|
361
|
-
if (!SERVICE_SIDS.Contains(becomeSid) && password == null && logonType != LogonType.NewCredentials)
|
|
383
|
+
else if (!SERVICE_SIDS.Contains(becomeSid) && password == null && logonType != LogonType.NewCredentials)
|
|
362
384
|
{
|
|
363
385
|
// If no password was specified, try and duplicate an existing token for that user or use S4U to
|
|
364
386
|
// generate one without network credentials
|
|
@@ -381,11 +403,6 @@ namespace Ansible.Become
|
|
|
381
403
|
string domain = null;
|
|
382
404
|
switch (becomeSid)
|
|
383
405
|
{
|
|
384
|
-
case "S-1-5-18":
|
|
385
|
-
logonType = LogonType.Service;
|
|
386
|
-
domain = "NT AUTHORITY";
|
|
387
|
-
username = "SYSTEM";
|
|
388
|
-
break;
|
|
389
406
|
case "S-1-5-19":
|
|
390
407
|
logonType = LogonType.Service;
|
|
391
408
|
domain = "NT AUTHORITY";
|
|
@@ -427,8 +444,10 @@ namespace Ansible.Become
|
|
|
427
444
|
return userTokens;
|
|
428
445
|
}
|
|
429
446
|
|
|
430
|
-
private static SafeNativeHandle GetPrimaryTokenForUser(
|
|
431
|
-
|
|
447
|
+
private static SafeNativeHandle GetPrimaryTokenForUser(
|
|
448
|
+
SecurityIdentifier sid,
|
|
449
|
+
List<string> requiredPrivileges = null,
|
|
450
|
+
bool usedForProcess = false)
|
|
432
451
|
{
|
|
433
452
|
// According to CreateProcessWithTokenW we require a token with
|
|
434
453
|
// TOKEN_QUERY, TOKEN_DUPLICATE and TOKEN_ASSIGN_PRIMARY
|
|
@@ -438,7 +457,19 @@ namespace Ansible.Become
|
|
|
438
457
|
TokenAccessLevels.AssignPrimary |
|
|
439
458
|
TokenAccessLevels.Impersonate;
|
|
440
459
|
|
|
441
|
-
|
|
460
|
+
SafeNativeHandle userToken = null;
|
|
461
|
+
int privilegeCount = 0;
|
|
462
|
+
|
|
463
|
+
// If we are using this token for the process, we need to check the
|
|
464
|
+
// process mitigation policy allows child processes to be created.
|
|
465
|
+
var processFilter = usedForProcess
|
|
466
|
+
? (Func<System.Diagnostics.Process, SafeNativeHandle, bool>)((p, t) =>
|
|
467
|
+
{
|
|
468
|
+
return GetProcessChildProcessPolicyFlags(t) == NativeHelpers.ProcessChildProcessPolicyFlags.None;
|
|
469
|
+
})
|
|
470
|
+
: ((p, t) => true);
|
|
471
|
+
|
|
472
|
+
foreach (SafeNativeHandle hToken in TokenUtil.EnumerateUserTokens(sid, dwAccess, processFilter))
|
|
442
473
|
{
|
|
443
474
|
// Filter out any Network logon tokens, using become with that is useless when S4U
|
|
444
475
|
// can give us a Batch logon
|
|
@@ -448,6 +479,10 @@ namespace Ansible.Become
|
|
|
448
479
|
|
|
449
480
|
List<string> actualPrivileges = TokenUtil.GetTokenPrivileges(hToken).Select(x => x.Name).ToList();
|
|
450
481
|
|
|
482
|
+
// If the token has less or the same number of privileges than the current token, skip it.
|
|
483
|
+
if (usedForProcess && privilegeCount >= actualPrivileges.Count)
|
|
484
|
+
continue;
|
|
485
|
+
|
|
451
486
|
// Check that the required privileges are on the token
|
|
452
487
|
if (requiredPrivileges != null)
|
|
453
488
|
{
|
|
@@ -459,16 +494,22 @@ namespace Ansible.Become
|
|
|
459
494
|
// Duplicate the token to convert it to a primary token with the access level required.
|
|
460
495
|
try
|
|
461
496
|
{
|
|
462
|
-
|
|
497
|
+
userToken = TokenUtil.DuplicateToken(hToken, TokenAccessLevels.MaximumAllowed,
|
|
463
498
|
SecurityImpersonationLevel.Anonymous, TokenType.Primary);
|
|
499
|
+
privilegeCount = actualPrivileges.Count;
|
|
464
500
|
}
|
|
465
501
|
catch (Process.Win32Exception)
|
|
466
502
|
{
|
|
467
503
|
continue;
|
|
468
504
|
}
|
|
505
|
+
|
|
506
|
+
// If we don't care about getting the token with the most privileges, escape the loop as we already
|
|
507
|
+
// have a token.
|
|
508
|
+
if (!usedForProcess)
|
|
509
|
+
break;
|
|
469
510
|
}
|
|
470
511
|
|
|
471
|
-
return
|
|
512
|
+
return userToken;
|
|
472
513
|
}
|
|
473
514
|
|
|
474
515
|
private static SafeNativeHandle GetS4UTokenForUser(SecurityIdentifier sid, LogonType logonType)
|
|
@@ -581,6 +622,35 @@ namespace Ansible.Become
|
|
|
581
622
|
return null;
|
|
582
623
|
}
|
|
583
624
|
|
|
625
|
+
private static NativeHelpers.ProcessChildProcessPolicyFlags GetProcessChildProcessPolicyFlags(SafeNativeHandle processHandle)
|
|
626
|
+
{
|
|
627
|
+
// Because this is only used to check the policy, we ignore any
|
|
628
|
+
// errors and pretend that the policy is None.
|
|
629
|
+
NativeHelpers.ProcessChildProcessPolicyFlags policy = NativeHelpers.ProcessChildProcessPolicyFlags.None;
|
|
630
|
+
|
|
631
|
+
if (_getProcessMitigationPolicySupported)
|
|
632
|
+
{
|
|
633
|
+
try
|
|
634
|
+
{
|
|
635
|
+
if (NativeMethods.GetProcessMitigationPolicy(
|
|
636
|
+
processHandle,
|
|
637
|
+
NativeMethods.ProcessChildProcessPolicy,
|
|
638
|
+
ref policy,
|
|
639
|
+
(IntPtr)4))
|
|
640
|
+
{
|
|
641
|
+
return policy;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
catch (EntryPointNotFoundException)
|
|
645
|
+
{
|
|
646
|
+
// If the function is not available, we won't try to call it again
|
|
647
|
+
_getProcessMitigationPolicySupported = false;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return policy;
|
|
652
|
+
}
|
|
653
|
+
|
|
584
654
|
private static NativeHelpers.SECURITY_LOGON_TYPE GetTokenLogonType(SafeNativeHandle hToken)
|
|
585
655
|
{
|
|
586
656
|
TokenStatistics stats = TokenUtil.GetTokenStatistics(hToken);
|
|
@@ -637,4 +707,4 @@ namespace Ansible.Become
|
|
|
637
707
|
{ }
|
|
638
708
|
}
|
|
639
709
|
}
|
|
640
|
-
}
|
|
710
|
+
}
|
ansible/modules/command.py
CHANGED
|
@@ -15,12 +15,11 @@ version_added: historical
|
|
|
15
15
|
description:
|
|
16
16
|
- The M(ansible.builtin.command) module takes the command name followed by a list of space-delimited arguments.
|
|
17
17
|
- The given command will be executed on all selected nodes.
|
|
18
|
-
- The command(s) will not be
|
|
19
|
-
|
|
20
|
-
like C("*"), C("<"), C(">"), C("|"), C(";") and C("&") will not work.
|
|
18
|
+
- The command(s) will not be processed through the shell, so operations like C("*"), C("<"), C(">"), C("|"), C(";") and C("&") will not work.
|
|
19
|
+
Also, environment variables are resolved via Python, not shell, see O(expand_argument_vars) and are left unchanged if not matched.
|
|
21
20
|
Use the M(ansible.builtin.shell) module if you need these features.
|
|
22
|
-
- To create C(command) tasks that are easier to read than the ones using space-delimited
|
|
23
|
-
|
|
21
|
+
- To create C(command) tasks that are easier to read than the ones using space-delimited arguments,
|
|
22
|
+
pass parameters using the C(args) L(task keyword,https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#task)
|
|
24
23
|
or use O(cmd) parameter.
|
|
25
24
|
- Either a free form command or O(cmd) parameter is required, see the examples.
|
|
26
25
|
- For Windows targets, use the M(ansible.windows.win_command) module instead.
|
|
@@ -41,8 +40,8 @@ attributes:
|
|
|
41
40
|
options:
|
|
42
41
|
expand_argument_vars:
|
|
43
42
|
description:
|
|
44
|
-
- Expands the arguments that are variables, for example C($HOME) will be expanded before being passed to the
|
|
45
|
-
|
|
43
|
+
- Expands the arguments that are variables, for example C($HOME) will be expanded before being passed to the command to run.
|
|
44
|
+
- If a variable is not matched, it is left unchanged, unlike shell substitution which would remove it.
|
|
46
45
|
- Set to V(false) to disable expansion and treat the value as a literal argument.
|
|
47
46
|
type: bool
|
|
48
47
|
default: true
|
ansible/modules/dnf5.py
CHANGED
|
@@ -358,6 +358,21 @@ libdnf5 = None
|
|
|
358
358
|
|
|
359
359
|
def is_installed(base, spec):
|
|
360
360
|
settings = libdnf5.base.ResolveSpecSettings()
|
|
361
|
+
try:
|
|
362
|
+
settings.set_group_with_name(True)
|
|
363
|
+
# Disable checking whether SPEC is a binary -> `/usr/(s)bin/<SPEC>`,
|
|
364
|
+
# this prevents scenarios like the following:
|
|
365
|
+
# * the `sssd-common` package is installed and provides `/usr/sbin/sssd` binary
|
|
366
|
+
# * the `sssd` package is NOT installed
|
|
367
|
+
# * due to `set_with_binaries(True)` being default `is_installed(base, "sssd")` would "unexpectedly" return True
|
|
368
|
+
# If users wish to target the `sssd` binary they can by specifying the full path `name=/usr/sbin/sssd` explicitly
|
|
369
|
+
# due to settings.set_with_filenames(True) being default.
|
|
370
|
+
settings.set_with_binaries(False)
|
|
371
|
+
except AttributeError:
|
|
372
|
+
# dnf5 < 5.2.0.0
|
|
373
|
+
settings.group_with_name = True
|
|
374
|
+
settings.with_binaries = False
|
|
375
|
+
|
|
361
376
|
installed_query = libdnf5.rpm.PackageQuery(base)
|
|
362
377
|
installed_query.filter_installed()
|
|
363
378
|
match, nevra = installed_query.resolve_pkg_spec(spec, settings, True)
|
|
@@ -646,9 +661,12 @@ class Dnf5Module(YumDnf):
|
|
|
646
661
|
settings = libdnf5.base.GoalJobSettings()
|
|
647
662
|
try:
|
|
648
663
|
settings.set_group_with_name(True)
|
|
664
|
+
settings.set_with_binaries(False)
|
|
649
665
|
except AttributeError:
|
|
650
666
|
# dnf5 < 5.2.0.0
|
|
651
667
|
settings.group_with_name = True
|
|
668
|
+
settings.with_binaries = False
|
|
669
|
+
|
|
652
670
|
if self.bugfix or self.security:
|
|
653
671
|
advisory_query = libdnf5.advisory.AdvisoryQuery(base)
|
|
654
672
|
types = []
|
|
@@ -13,11 +13,14 @@ DOCUMENTATION = """
|
|
|
13
13
|
_terms:
|
|
14
14
|
description: List of Python regex patterns to search for in variable names.
|
|
15
15
|
required: True
|
|
16
|
+
seealso:
|
|
17
|
+
- plugin_type: lookup
|
|
18
|
+
plugin: ansible.builtin.vars
|
|
16
19
|
"""
|
|
17
20
|
|
|
18
21
|
EXAMPLES = """
|
|
19
22
|
- name: List variables that start with qz_
|
|
20
|
-
ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', '^qz_.+')}}"
|
|
23
|
+
ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', '^qz_.+') }}"
|
|
21
24
|
vars:
|
|
22
25
|
qz_1: hello
|
|
23
26
|
qz_2: world
|
|
@@ -25,13 +28,16 @@ EXAMPLES = """
|
|
|
25
28
|
qz_: "I won't show either"
|
|
26
29
|
|
|
27
30
|
- name: Show all variables
|
|
28
|
-
ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', '.+')}}"
|
|
31
|
+
ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', '.+') }}"
|
|
29
32
|
|
|
30
33
|
- name: Show variables with 'hosts' in their names
|
|
31
|
-
ansible.builtin.debug: msg="{{
|
|
34
|
+
ansible.builtin.debug: msg="{{ q('varnames', 'hosts') }}"
|
|
32
35
|
|
|
33
36
|
- name: Find several related variables that end specific way
|
|
34
|
-
ansible.builtin.debug: msg="{{
|
|
37
|
+
ansible.builtin.debug: msg="{{ query('ansible.builtin.varnames', '.+_zone$', '.+_location$') }}"
|
|
38
|
+
|
|
39
|
+
- name: display values from variables found via varnames (note "*" is used to dereference the list to a 'list of arguments')
|
|
40
|
+
debug: msg="{{ lookup('vars', *lookup('varnames', 'ansible_play_.+')) }}"
|
|
35
41
|
|
|
36
42
|
"""
|
|
37
43
|
|
ansible/plugins/lookup/vars.py
CHANGED
|
@@ -17,6 +17,10 @@ DOCUMENTATION = """
|
|
|
17
17
|
description:
|
|
18
18
|
- What to return if a variable is undefined.
|
|
19
19
|
- If no default is set, it will result in an error if any of the variables is undefined.
|
|
20
|
+
seealso:
|
|
21
|
+
- plugin_type: lookup
|
|
22
|
+
plugin: ansible.builtin.varnames
|
|
23
|
+
|
|
20
24
|
"""
|
|
21
25
|
|
|
22
26
|
EXAMPLES = """
|
|
@@ -27,20 +31,23 @@ EXAMPLES = """
|
|
|
27
31
|
myvar: ename
|
|
28
32
|
|
|
29
33
|
- name: Show default empty since i dont have 'variablnotename'
|
|
30
|
-
ansible.builtin.debug: msg="{{ lookup('ansible.builtin.vars', 'variabl' + myvar, default='')}}"
|
|
34
|
+
ansible.builtin.debug: msg="{{ lookup('ansible.builtin.vars', 'variabl' + myvar, default='') }}"
|
|
31
35
|
vars:
|
|
32
36
|
variablename: hello
|
|
33
37
|
myvar: notename
|
|
34
38
|
|
|
35
39
|
- name: Produce an error since i dont have 'variablnotename'
|
|
36
|
-
ansible.builtin.debug: msg="{{
|
|
40
|
+
ansible.builtin.debug: msg="{{ q('vars', 'variabl' + myvar) }}"
|
|
37
41
|
ignore_errors: True
|
|
38
42
|
vars:
|
|
39
43
|
variablename: hello
|
|
40
44
|
myvar: notename
|
|
41
45
|
|
|
42
46
|
- name: find several related variables
|
|
43
|
-
ansible.builtin.debug: msg="{{
|
|
47
|
+
ansible.builtin.debug: msg="{{ query('ansible.builtin.vars', 'ansible_play_hosts', 'ansible_play_batch', 'ansible_play_hosts_all') }}"
|
|
48
|
+
|
|
49
|
+
- name: show values from variables found via varnames (note "*" is used to dereference the list to a 'list of arguments')
|
|
50
|
+
debug: msg="{{ q('vars', *q('varnames', 'ansible_play_.+')) }}"
|
|
44
51
|
|
|
45
52
|
- name: Access nested variables
|
|
46
53
|
ansible.builtin.debug: msg="{{ lookup('ansible.builtin.vars', 'variabl' + myvar).sub_var }}"
|
ansible/release.py
CHANGED
ansible/template/__init__.py
CHANGED
|
@@ -48,7 +48,7 @@ from ansible.module_utils.six import string_types
|
|
|
48
48
|
from ansible.module_utils.common.text.converters import to_native, to_text, to_bytes
|
|
49
49
|
from ansible.module_utils.common.collections import is_sequence
|
|
50
50
|
from ansible.plugins.loader import filter_loader, lookup_loader, test_loader
|
|
51
|
-
from ansible.template.native_helpers import ansible_native_concat, ansible_eval_concat, ansible_concat
|
|
51
|
+
from ansible.template.native_helpers import AnsibleUndefined, ansible_native_concat, ansible_eval_concat, ansible_concat
|
|
52
52
|
from ansible.template.template import AnsibleJ2Template
|
|
53
53
|
from ansible.template.vars import AnsibleJ2Vars
|
|
54
54
|
from ansible.utils.display import Display
|
|
@@ -312,35 +312,6 @@ def _wrap_native_text(func):
|
|
|
312
312
|
return functools.update_wrapper(wrapper, func)
|
|
313
313
|
|
|
314
314
|
|
|
315
|
-
class AnsibleUndefined(StrictUndefined):
|
|
316
|
-
'''
|
|
317
|
-
A custom Undefined class, which returns further Undefined objects on access,
|
|
318
|
-
rather than throwing an exception.
|
|
319
|
-
'''
|
|
320
|
-
def __getattr__(self, name):
|
|
321
|
-
if name == '__UNSAFE__':
|
|
322
|
-
# AnsibleUndefined should never be assumed to be unsafe
|
|
323
|
-
# This prevents ``hasattr(val, '__UNSAFE__')`` from evaluating to ``True``
|
|
324
|
-
raise AttributeError(name)
|
|
325
|
-
# Return original Undefined object to preserve the first failure context
|
|
326
|
-
return self
|
|
327
|
-
|
|
328
|
-
def __getitem__(self, key):
|
|
329
|
-
# Return original Undefined object to preserve the first failure context
|
|
330
|
-
return self
|
|
331
|
-
|
|
332
|
-
def __repr__(self):
|
|
333
|
-
return 'AnsibleUndefined(hint={0!r}, obj={1!r}, name={2!r})'.format(
|
|
334
|
-
self._undefined_hint,
|
|
335
|
-
self._undefined_obj,
|
|
336
|
-
self._undefined_name
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
-
def __contains__(self, item):
|
|
340
|
-
# Return original Undefined object to preserve the first failure context
|
|
341
|
-
return self
|
|
342
|
-
|
|
343
|
-
|
|
344
315
|
class AnsibleContext(Context):
|
|
345
316
|
'''
|
|
346
317
|
A custom context, which intercepts resolve_or_missing() calls and sets a flag
|
|
@@ -5,13 +5,19 @@ from __future__ import annotations
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
import ast
|
|
8
|
+
from collections.abc import Mapping
|
|
8
9
|
from itertools import islice, chain
|
|
9
10
|
from types import GeneratorType
|
|
10
11
|
|
|
12
|
+
from ansible.module_utils.common.collections import is_sequence
|
|
11
13
|
from ansible.module_utils.common.text.converters import to_text
|
|
12
14
|
from ansible.module_utils.six import string_types
|
|
13
15
|
from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
|
|
14
16
|
from ansible.utils.native_jinja import NativeJinjaText
|
|
17
|
+
from ansible.utils.unsafe_proxy import wrap_var
|
|
18
|
+
import ansible.module_utils.compat.typing as t
|
|
19
|
+
|
|
20
|
+
from jinja2.runtime import StrictUndefined
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
_JSON_MAP = {
|
|
@@ -28,6 +34,40 @@ class Json2Python(ast.NodeTransformer):
|
|
|
28
34
|
return ast.Constant(value=_JSON_MAP[node.id])
|
|
29
35
|
|
|
30
36
|
|
|
37
|
+
def _is_unsafe(value: t.Any) -> bool:
|
|
38
|
+
"""
|
|
39
|
+
Our helper function, which will also recursively check dict and
|
|
40
|
+
list entries due to the fact that they may be repr'd and contain
|
|
41
|
+
a key or value which contains jinja2 syntax and would otherwise
|
|
42
|
+
lose the AnsibleUnsafe value.
|
|
43
|
+
"""
|
|
44
|
+
to_check = [value]
|
|
45
|
+
seen = set()
|
|
46
|
+
|
|
47
|
+
while True:
|
|
48
|
+
if not to_check:
|
|
49
|
+
break
|
|
50
|
+
|
|
51
|
+
val = to_check.pop(0)
|
|
52
|
+
val_id = id(val)
|
|
53
|
+
|
|
54
|
+
if val_id in seen:
|
|
55
|
+
continue
|
|
56
|
+
seen.add(val_id)
|
|
57
|
+
|
|
58
|
+
if isinstance(val, AnsibleUndefined):
|
|
59
|
+
continue
|
|
60
|
+
if isinstance(val, Mapping):
|
|
61
|
+
to_check.extend(val.keys())
|
|
62
|
+
to_check.extend(val.values())
|
|
63
|
+
elif is_sequence(val):
|
|
64
|
+
to_check.extend(val)
|
|
65
|
+
elif getattr(val, '__UNSAFE__', False):
|
|
66
|
+
return True
|
|
67
|
+
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
|
|
31
71
|
def ansible_eval_concat(nodes):
|
|
32
72
|
"""Return a string of concatenated compiled nodes. Throw an undefined error
|
|
33
73
|
if any of the nodes is undefined.
|
|
@@ -43,17 +83,28 @@ def ansible_eval_concat(nodes):
|
|
|
43
83
|
if not head:
|
|
44
84
|
return ''
|
|
45
85
|
|
|
86
|
+
unsafe = False
|
|
87
|
+
|
|
46
88
|
if len(head) == 1:
|
|
47
89
|
out = head[0]
|
|
48
90
|
|
|
49
91
|
if isinstance(out, NativeJinjaText):
|
|
50
92
|
return out
|
|
51
93
|
|
|
94
|
+
unsafe = _is_unsafe(out)
|
|
52
95
|
out = to_text(out)
|
|
53
96
|
else:
|
|
54
97
|
if isinstance(nodes, GeneratorType):
|
|
55
98
|
nodes = chain(head, nodes)
|
|
56
|
-
|
|
99
|
+
|
|
100
|
+
out_values = []
|
|
101
|
+
for v in nodes:
|
|
102
|
+
if not unsafe and _is_unsafe(v):
|
|
103
|
+
unsafe = True
|
|
104
|
+
|
|
105
|
+
out_values.append(to_text(v))
|
|
106
|
+
|
|
107
|
+
out = ''.join(out_values)
|
|
57
108
|
|
|
58
109
|
# if this looks like a dictionary, list or bool, convert it to such
|
|
59
110
|
if out.startswith(('{', '[')) or out in ('True', 'False'):
|
|
@@ -68,6 +119,9 @@ def ansible_eval_concat(nodes):
|
|
|
68
119
|
except (TypeError, ValueError, SyntaxError, MemoryError):
|
|
69
120
|
pass
|
|
70
121
|
|
|
122
|
+
if unsafe:
|
|
123
|
+
out = wrap_var(out)
|
|
124
|
+
|
|
71
125
|
return out
|
|
72
126
|
|
|
73
127
|
|
|
@@ -78,7 +132,19 @@ def ansible_concat(nodes):
|
|
|
78
132
|
|
|
79
133
|
Used in Templar.template() when jinja2_native=False and convert_data=False.
|
|
80
134
|
"""
|
|
81
|
-
|
|
135
|
+
unsafe = False
|
|
136
|
+
values = []
|
|
137
|
+
for v in nodes:
|
|
138
|
+
if not unsafe and _is_unsafe(v):
|
|
139
|
+
unsafe = True
|
|
140
|
+
|
|
141
|
+
values.append(to_text(v))
|
|
142
|
+
|
|
143
|
+
out = ''.join(values)
|
|
144
|
+
if unsafe:
|
|
145
|
+
out = wrap_var(out)
|
|
146
|
+
|
|
147
|
+
return out
|
|
82
148
|
|
|
83
149
|
|
|
84
150
|
def ansible_native_concat(nodes):
|
|
@@ -95,6 +161,8 @@ def ansible_native_concat(nodes):
|
|
|
95
161
|
if not head:
|
|
96
162
|
return None
|
|
97
163
|
|
|
164
|
+
unsafe = False
|
|
165
|
+
|
|
98
166
|
if len(head) == 1:
|
|
99
167
|
out = head[0]
|
|
100
168
|
|
|
@@ -115,10 +183,21 @@ def ansible_native_concat(nodes):
|
|
|
115
183
|
# short-circuit literal_eval for anything other than strings
|
|
116
184
|
if not isinstance(out, string_types):
|
|
117
185
|
return out
|
|
186
|
+
|
|
187
|
+
unsafe = _is_unsafe(out)
|
|
188
|
+
|
|
118
189
|
else:
|
|
119
190
|
if isinstance(nodes, GeneratorType):
|
|
120
191
|
nodes = chain(head, nodes)
|
|
121
|
-
|
|
192
|
+
|
|
193
|
+
out_values = []
|
|
194
|
+
for v in nodes:
|
|
195
|
+
if not unsafe and _is_unsafe(v):
|
|
196
|
+
unsafe = True
|
|
197
|
+
|
|
198
|
+
out_values.append(to_text(v))
|
|
199
|
+
|
|
200
|
+
out = ''.join(out_values)
|
|
122
201
|
|
|
123
202
|
try:
|
|
124
203
|
evaled = ast.literal_eval(
|
|
@@ -128,10 +207,45 @@ def ansible_native_concat(nodes):
|
|
|
128
207
|
ast.parse(out, mode='eval')
|
|
129
208
|
)
|
|
130
209
|
except (TypeError, ValueError, SyntaxError, MemoryError):
|
|
210
|
+
if unsafe:
|
|
211
|
+
out = wrap_var(out)
|
|
212
|
+
|
|
131
213
|
return out
|
|
132
214
|
|
|
133
215
|
if isinstance(evaled, string_types):
|
|
134
216
|
quote = out[0]
|
|
135
|
-
|
|
217
|
+
evaled = f'{quote}{evaled}{quote}'
|
|
218
|
+
|
|
219
|
+
if unsafe:
|
|
220
|
+
evaled = wrap_var(evaled)
|
|
136
221
|
|
|
137
222
|
return evaled
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class AnsibleUndefined(StrictUndefined):
|
|
226
|
+
"""
|
|
227
|
+
A custom Undefined class, which returns further Undefined objects on access,
|
|
228
|
+
rather than throwing an exception.
|
|
229
|
+
"""
|
|
230
|
+
def __getattr__(self, name):
|
|
231
|
+
if name == '__UNSAFE__':
|
|
232
|
+
# AnsibleUndefined should never be assumed to be unsafe
|
|
233
|
+
# This prevents ``hasattr(val, '__UNSAFE__')`` from evaluating to ``True``
|
|
234
|
+
raise AttributeError(name)
|
|
235
|
+
# Return original Undefined object to preserve the first failure context
|
|
236
|
+
return self
|
|
237
|
+
|
|
238
|
+
def __getitem__(self, key):
|
|
239
|
+
# Return original Undefined object to preserve the first failure context
|
|
240
|
+
return self
|
|
241
|
+
|
|
242
|
+
def __repr__(self):
|
|
243
|
+
return 'AnsibleUndefined(hint={0!r}, obj={1!r}, name={2!r})'.format(
|
|
244
|
+
self._undefined_hint,
|
|
245
|
+
self._undefined_obj,
|
|
246
|
+
self._undefined_name
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def __contains__(self, item):
|
|
250
|
+
# Return original Undefined object to preserve the first failure context
|
|
251
|
+
return self
|
ansible/vars/hostvars.py
CHANGED
|
@@ -92,10 +92,12 @@ class HostVars(Mapping):
|
|
|
92
92
|
return self._find_host(host_name) is not None
|
|
93
93
|
|
|
94
94
|
def __iter__(self):
|
|
95
|
-
|
|
95
|
+
# include implicit localhost only if it has variables set
|
|
96
|
+
yield from self._inventory.hosts | {'localhost': self._inventory.localhost} if self._inventory.localhost else {}
|
|
96
97
|
|
|
97
98
|
def __len__(self):
|
|
98
|
-
|
|
99
|
+
# include implicit localhost only if it has variables set
|
|
100
|
+
return len(self._inventory.hosts) + (1 if self._inventory.localhost else 0)
|
|
99
101
|
|
|
100
102
|
def __repr__(self):
|
|
101
103
|
out = {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ansible-core
|
|
3
|
-
Version: 2.18.
|
|
3
|
+
Version: 2.18.1rc1
|
|
4
4
|
Summary: Radically simple IT automation
|
|
5
5
|
Author: Ansible Project
|
|
6
6
|
Project-URL: Homepage, https://ansible.com/
|
|
@@ -32,11 +32,11 @@ License-File: licenses/Apache-License.txt
|
|
|
32
32
|
License-File: licenses/MIT-license.txt
|
|
33
33
|
License-File: licenses/PSF-license.txt
|
|
34
34
|
License-File: licenses/simplified_bsd.txt
|
|
35
|
-
Requires-Dist: jinja2
|
|
36
|
-
Requires-Dist: PyYAML
|
|
35
|
+
Requires-Dist: jinja2>=3.0.0
|
|
36
|
+
Requires-Dist: PyYAML>=5.1
|
|
37
37
|
Requires-Dist: cryptography
|
|
38
38
|
Requires-Dist: packaging
|
|
39
|
-
Requires-Dist: resolvelib
|
|
39
|
+
Requires-Dist: resolvelib<1.1.0,>=0.5.3
|
|
40
40
|
|
|
41
41
|
[](https://pypi.org/project/ansible-core)
|
|
42
42
|
[](https://docs.ansible.com/ansible/latest/)
|
|
@@ -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=
|
|
6
|
+
ansible/release.py,sha256=0ZMgTOTRKMyYnQWknncQyldpI2t8HSHVuMmm_U-K_sE,839
|
|
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
|
|
@@ -37,7 +37,7 @@ ansible/executor/module_common.py,sha256=4pVfjMgCle9ttAZTeuwSx3Kdi0rljagyHC11i4V
|
|
|
37
37
|
ansible/executor/play_iterator.py,sha256=Oazd9aWy4zB67uy27sYg4BveFx_Uf_tIsbhD76hMc28,32496
|
|
38
38
|
ansible/executor/playbook_executor.py,sha256=qurZBiWjAWWRYcHb3ti4sBI8_WotOYvTRDar4JC3leE,14764
|
|
39
39
|
ansible/executor/stats.py,sha256=gcBhJQrZTgE95737d6lArJ3FpTlbAfVt6GMhEqs5ZPU,3180
|
|
40
|
-
ansible/executor/task_executor.py,sha256=
|
|
40
|
+
ansible/executor/task_executor.py,sha256=99oxT0B787aRpw7B8OssXWuzltcfiraGISnIpHTo7U4,61338
|
|
41
41
|
ansible/executor/task_queue_manager.py,sha256=fC404XkveICb7hRwIVu4PvRNgFkFLCNihsGsUDHVFzg,18640
|
|
42
42
|
ansible/executor/task_result.py,sha256=48zZWpxCiM0Z_MVG9zGQGCxHLNzs1horT68Qmfa-v_8,5696
|
|
43
43
|
ansible/executor/discovery/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -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=
|
|
144
|
+
ansible/module_utils/ansible_release.py,sha256=0ZMgTOTRKMyYnQWknncQyldpI2t8HSHVuMmm_U-K_sE,839
|
|
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
|
|
@@ -184,9 +184,9 @@ ansible/module_utils/compat/selectors.py,sha256=OcR8ACS6Cr9ShlFlv8sC3QQZ7qUaP5Wh
|
|
|
184
184
|
ansible/module_utils/compat/selinux.py,sha256=9bq2UMTE_PILEHdvUsXPk_84oWfKiMppyrZs7qH4jdI,3488
|
|
185
185
|
ansible/module_utils/compat/typing.py,sha256=J_K9Ru1-f0KSKO_WhWGRCh0WBNWl6jUmQK1_0yYYZOs,736
|
|
186
186
|
ansible/module_utils/compat/version.py,sha256=ifck3MH9LhxMENpZXOrntEqX6b7X8shknt3Fweg6AzQ,12734
|
|
187
|
-
ansible/module_utils/csharp/Ansible.AccessToken.cs,sha256=
|
|
187
|
+
ansible/module_utils/csharp/Ansible.AccessToken.cs,sha256=TIOpRx4lv9FlhMyWfHS30CIMRtM3uqR8-u6Rv0X1HWE,16390
|
|
188
188
|
ansible/module_utils/csharp/Ansible.Basic.cs,sha256=xp1pMZNhib3vhR3Wdc5JlDv1SORo4dIGjc17LmnLr1g,78845
|
|
189
|
-
ansible/module_utils/csharp/Ansible.Become.cs,sha256=
|
|
189
|
+
ansible/module_utils/csharp/Ansible.Become.cs,sha256=g0FyAMO3kl186IGhgACQhNAMP8o2UHNzXVUv0Enau2w,32793
|
|
190
190
|
ansible/module_utils/csharp/Ansible.Privilege.cs,sha256=7e46na6k6ygdRwN53bzfIS8O-IwfM1TF_q5DeFH2Z80,19398
|
|
191
191
|
ansible/module_utils/csharp/Ansible.Process.cs,sha256=bON6hExhSB-SR2p2ryFZj6kU3a5TxonFv498wg2Je98,19452
|
|
192
192
|
ansible/module_utils/csharp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -289,14 +289,14 @@ ansible/modules/assert.py,sha256=EAfJEQ21pgdKqhqQAI_pfJIQPyKX0XEP2BP6kJgLCgU,295
|
|
|
289
289
|
ansible/modules/async_status.py,sha256=iuNMObp1piLIaoO-7ZiueUNitk-5CDW93l9iVPqd53I,4574
|
|
290
290
|
ansible/modules/async_wrapper.py,sha256=OjA0E7lm8mvlxXA76-HVvjc_H1fHae0Euh25exY6gEc,11619
|
|
291
291
|
ansible/modules/blockinfile.py,sha256=A_6b-ZHKWIB8G5mgn6rFJeZfoUtqUO80orHx5j5TBPY,15451
|
|
292
|
-
ansible/modules/command.py,sha256=
|
|
292
|
+
ansible/modules/command.py,sha256=ItnYqvij_n4UOR344EetJ9xn_abCAj5_qklJ-rzlN8A,14155
|
|
293
293
|
ansible/modules/copy.py,sha256=2A1rh9Mpl8oFgTeS7xmVSUZ1v920I60jMEgrkwfBwyg,32106
|
|
294
294
|
ansible/modules/cron.py,sha256=qR5ePdI3GZQeBSCn9YqxTxWlNEblCaTFnBRZqLjtnPo,26353
|
|
295
295
|
ansible/modules/deb822_repository.py,sha256=SLJM8bBLc70WYu3-OA67wd5hMft3pznYAMIidYOtmUU,15791
|
|
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=
|
|
299
|
+
ansible/modules/dnf5.py,sha256=csebof_G-_9HPDRJw65bnWv492jXL5Om7O4adw5w0Xg,29128
|
|
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
|
|
@@ -576,8 +576,8 @@ ansible/plugins/lookup/template.py,sha256=xFYWKY808hHPj7nJbaLM2mZro79p6TjpFXyAcR
|
|
|
576
576
|
ansible/plugins/lookup/together.py,sha256=T4J2miqHTnrDP6-CrlJ3wgI0UgyZyYVRVrDTWx3olpY,2110
|
|
577
577
|
ansible/plugins/lookup/unvault.py,sha256=5LU8Lf7Gx0yRh8z0u1giSXkd93pkSZ34ibkoQnHCsyw,2049
|
|
578
578
|
ansible/plugins/lookup/url.py,sha256=8JzzKOuWNI4st--CwmJZx-16ykFZKhcZdj4wb1za0Tk,9583
|
|
579
|
-
ansible/plugins/lookup/varnames.py,sha256=
|
|
580
|
-
ansible/plugins/lookup/vars.py,sha256=
|
|
579
|
+
ansible/plugins/lookup/varnames.py,sha256=4WKSH-u0ZnQD47r20c5OenaG6Vlamp6nweIZSFOJ0b8,2595
|
|
580
|
+
ansible/plugins/lookup/vars.py,sha256=W9at2j3xBk6z4IXfSutTEHqdzbiTI1B1tuYOLdd1BMQ,3672
|
|
581
581
|
ansible/plugins/netconf/__init__.py,sha256=50w1g2rhUo6L-xtiMT20jbR8WyOnhwNSRd2IRNSjNX4,17094
|
|
582
582
|
ansible/plugins/shell/__init__.py,sha256=8pc3ab91OGbnvzk3oQ-sU8uXMXNoNbjtdCbdXmZYTWY,8985
|
|
583
583
|
ansible/plugins/shell/cmd.py,sha256=kPCSKrJJFH5XTkmteEI3P1Da6WfPSXxDnV39VFpgD-A,2170
|
|
@@ -645,8 +645,8 @@ ansible/plugins/test/version.yml,sha256=2d55HZGIniPu53z6_bV4C26_1sqRAHJqCwesOU3m
|
|
|
645
645
|
ansible/plugins/test/version_compare.yml,sha256=2d55HZGIniPu53z6_bV4C26_1sqRAHJqCwesOU3ma38,3283
|
|
646
646
|
ansible/plugins/vars/__init__.py,sha256=D3YwVKABesBwag9e7GsLOxlRWqEO5NgfHDmYSq0z_1k,1331
|
|
647
647
|
ansible/plugins/vars/host_group_vars.py,sha256=Qouyds_KOEuqaz4GlTYQnQUxXyTyyjFMj7maRnH8miU,6284
|
|
648
|
-
ansible/template/__init__.py,sha256=
|
|
649
|
-
ansible/template/native_helpers.py,sha256=
|
|
648
|
+
ansible/template/__init__.py,sha256=Raj_xvUtICZnReq0UhYTiJXQJVcC16Q9q2iQ4_KbUeo,39682
|
|
649
|
+
ansible/template/native_helpers.py,sha256=l-Jo2-ExemCheK-Yi-NRIUYkJyHqCGjRsW2ANTrqmuQ,7213
|
|
650
650
|
ansible/template/template.py,sha256=47dvX9AqSKlp6-n2QRPrHyhI3bboVyOpQekmQYryUB4,1583
|
|
651
651
|
ansible/template/vars.py,sha256=YUCVqNLS3wjYHACSei7f5uwZMZRBTwiyjGge09EP00E,2854
|
|
652
652
|
ansible/utils/__init__.py,sha256=mRvbCJPA-_veSG5ka3v04G5vsarLVDeB3EWFsu6geSI,749
|
|
@@ -683,7 +683,7 @@ ansible/utils/collection_loader/_collection_meta.py,sha256=L8NWlDs5KBMASIKRGoFTN
|
|
|
683
683
|
ansible/vars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
684
684
|
ansible/vars/clean.py,sha256=X2WMksJMWITQ9FsM-Fb_YxT_hAGDqJ3urSTJzYBEdAk,5999
|
|
685
685
|
ansible/vars/fact_cache.py,sha256=M57vMhkQ2DrzvNaZkfaCmKQJUqP1Rn_A31_X-5YBfzQ,1903
|
|
686
|
-
ansible/vars/hostvars.py,sha256=
|
|
686
|
+
ansible/vars/hostvars.py,sha256=o11xrzDVYn23renGbb3lx3R-nH9qOjLFju5IYJanDxg,5324
|
|
687
687
|
ansible/vars/manager.py,sha256=nFJcvbhanUQO7loAUiFHEnGCuRpxsmYXCj8e9XVJTYc,30972
|
|
688
688
|
ansible/vars/plugins.py,sha256=PocWZPMqFl1LoNgWlGFNxwg9nZnUzhQmlXO4g7bcP2A,4503
|
|
689
689
|
ansible/vars/reserved.py,sha256=kZiQMPvaFin35006gLwDpX16w-9xlu6EaL4LSTKP40U,2531
|
|
@@ -744,7 +744,7 @@ ansible_test/_internal/completion.py,sha256=G_4MfyNoISRBEM3Adgh66KBJH2e0mVRS8Ice
|
|
|
744
744
|
ansible_test/_internal/config.py,sha256=phNYKVGNOJKuzt0zWOpe2rLrqANlwwfNePPx3V2ZVEk,12131
|
|
745
745
|
ansible_test/_internal/connections.py,sha256=-gK9FqvmpsjENdYNkvWgFgqYHJSS_F2XkvQzH2_s86E,7855
|
|
746
746
|
ansible_test/_internal/constants.py,sha256=Zwgp8wtUuge_8xMPg0pDUt58fBd9KA7YEPTQqAQv8ac,1969
|
|
747
|
-
ansible_test/_internal/containers.py,sha256=
|
|
747
|
+
ansible_test/_internal/containers.py,sha256=TrkHL4ntmb7HrmD55BzSdqF35s7oFKu0vCywpWfRt-k,34137
|
|
748
748
|
ansible_test/_internal/content_config.py,sha256=QKR_XVBgYRNZL-XawF2pN2ERTZ6lSm1AJg9ZQRD6IHE,5588
|
|
749
749
|
ansible_test/_internal/core_ci.py,sha256=pyiwFG_TgDSQw34qW-PG8T2VYS6XxiF0zOEWGYXRRek,17309
|
|
750
750
|
ansible_test/_internal/coverage_util.py,sha256=_SPR0sqkgPoGw2bzuRS5gr4XOyIU8MQ4a9U8FgyWHho,9283
|
|
@@ -773,7 +773,7 @@ ansible_test/_internal/target.py,sha256=Whtb_n0jn4zbiMmX7je5jewgzsRczfXRm_ndYtjT
|
|
|
773
773
|
ansible_test/_internal/test.py,sha256=znQmGjKACqDU8T0EAPqcv2qyy0J7M2w4OmyYhwHLqT0,14515
|
|
774
774
|
ansible_test/_internal/thread.py,sha256=WQoZ2q2ljmEkKHRDkIqwxW7eZbkCKDrG3YZfcaxHzHw,2596
|
|
775
775
|
ansible_test/_internal/timeout.py,sha256=X8LxoMSU85lw4MszfEljaG6V7Aff4Btveg3r89Fe25U,4052
|
|
776
|
-
ansible_test/_internal/util.py,sha256=
|
|
776
|
+
ansible_test/_internal/util.py,sha256=o8efNGzuieD3mf3B7Ash1r25dEcePB7L-HOwu5EPFto,38908
|
|
777
777
|
ansible_test/_internal/util_common.py,sha256=wSygjQRWlkFNpqQnPSSXnz_3Cr0pWrPvCP-6lMdfuAk,17490
|
|
778
778
|
ansible_test/_internal/venv.py,sha256=k7L9_Ocpsdwp4kQFLF59BVguymd2nqJ-bLHH1NlMET0,5521
|
|
779
779
|
ansible_test/_internal/ci/__init__.py,sha256=QOaC_8_wUzqFEbsFCXYAnElWoUo6gB40CXvP9RJ-Iyo,7738
|
|
@@ -980,13 +980,13 @@ ansible_test/config/cloud-config-vultr.ini.template,sha256=XLKHk3lg_8ReQMdWfZzhh
|
|
|
980
980
|
ansible_test/config/config.yml,sha256=1zdGucnIl6nIecZA7ISIANvqXiHWqq6Dthsk_6MUwNc,2642
|
|
981
981
|
ansible_test/config/inventory.networking.template,sha256=bFNSk8zNQOaZ_twaflrY0XZ9mLwUbRLuNT0BdIFwvn4,1335
|
|
982
982
|
ansible_test/config/inventory.winrm.template,sha256=1QU8W-GFLnYEw8yY9bVIvUAVvJYPM3hyoijf6-M7T00,1098
|
|
983
|
-
ansible_core-2.18.
|
|
984
|
-
ansible_core-2.18.
|
|
985
|
-
ansible_core-2.18.
|
|
986
|
-
ansible_core-2.18.
|
|
987
|
-
ansible_core-2.18.
|
|
988
|
-
ansible_core-2.18.
|
|
989
|
-
ansible_core-2.18.
|
|
990
|
-
ansible_core-2.18.
|
|
991
|
-
ansible_core-2.18.
|
|
992
|
-
ansible_core-2.18.
|
|
983
|
+
ansible_core-2.18.1rc1.dist-info/Apache-License.txt,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325
|
|
984
|
+
ansible_core-2.18.1rc1.dist-info/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
985
|
+
ansible_core-2.18.1rc1.dist-info/METADATA,sha256=xerWczD5k1pQDFa0-MXY3saZd-FsBLqEmJDkPzkktsM,7671
|
|
986
|
+
ansible_core-2.18.1rc1.dist-info/MIT-license.txt,sha256=jLXp2XurnyZKbye40g9tfmLGtVlxh3pPD4n8xNqX8xc,1023
|
|
987
|
+
ansible_core-2.18.1rc1.dist-info/PSF-license.txt,sha256=g7BC_H1qyg8Q1o5F76Vrm8ChSWYI5-dyj-CdGlNKBUo,2484
|
|
988
|
+
ansible_core-2.18.1rc1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
989
|
+
ansible_core-2.18.1rc1.dist-info/entry_points.txt,sha256=S9yJij5Im6FgRQxzkqSCnPQokC7PcWrDW_NSygZczJU,451
|
|
990
|
+
ansible_core-2.18.1rc1.dist-info/simplified_bsd.txt,sha256=8R5R7R7sOa0h1Fi6RNgFgHowHBfun-OVOMzJ4rKAk2w,1237
|
|
991
|
+
ansible_core-2.18.1rc1.dist-info/top_level.txt,sha256=IFbRLjAvih1DYzJWg3_F6t4sCzEMxRO7TOMNs6GkYHo,21
|
|
992
|
+
ansible_core-2.18.1rc1.dist-info/RECORD,,
|
|
@@ -292,10 +292,13 @@ def get_docker_preferred_network_name(args: EnvironmentConfig) -> t.Optional[str
|
|
|
292
292
|
current_container_id = get_docker_container_id()
|
|
293
293
|
|
|
294
294
|
if current_container_id:
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
295
|
+
try:
|
|
296
|
+
# Make sure any additional containers we launch use the same network as the current container we're running in.
|
|
297
|
+
# This is needed when ansible-test is running in a container that is not connected to Docker's default network.
|
|
298
|
+
container = docker_inspect(args, current_container_id, always=True)
|
|
299
|
+
network = container.get_network_name()
|
|
300
|
+
except ContainerNotFoundError:
|
|
301
|
+
display.warning('Unable to detect the network for the current container. Use the `--docker-network` option if containers are unreachable.')
|
|
299
302
|
|
|
300
303
|
# The default docker behavior puts containers on the same network.
|
|
301
304
|
# The default podman behavior puts containers on isolated networks which don't allow communication between containers or network disconnect.
|
ansible_test/_internal/util.py
CHANGED
|
@@ -1014,15 +1014,15 @@ class HostConnectionError(ApplicationError):
|
|
|
1014
1014
|
self._callback()
|
|
1015
1015
|
|
|
1016
1016
|
|
|
1017
|
-
def format_command_output(stdout: str, stderr: str) -> str:
|
|
1017
|
+
def format_command_output(stdout: str | None, stderr: str | None) -> str:
|
|
1018
1018
|
"""Return a formatted string containing the given stdout and stderr (if any)."""
|
|
1019
1019
|
message = ''
|
|
1020
1020
|
|
|
1021
|
-
if stderr := stderr.strip():
|
|
1021
|
+
if stderr and (stderr := stderr.strip()):
|
|
1022
1022
|
message += '>>> Standard Error\n'
|
|
1023
1023
|
message += f'{stderr}{Display.clear}\n'
|
|
1024
1024
|
|
|
1025
|
-
if stdout := stdout.strip():
|
|
1025
|
+
if stdout and (stdout := stdout.strip()):
|
|
1026
1026
|
message += '>>> Standard Output\n'
|
|
1027
1027
|
message += f'{stdout}{Display.clear}\n'
|
|
1028
1028
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|