ansible-core 2.19.0rc2__py3-none-any.whl → 2.19.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/_internal/_ansiballz/_builder.py +25 -14
- ansible/_internal/_templating/_engine.py +6 -4
- ansible/_internal/_templating/_jinja_bits.py +3 -1
- ansible/_internal/_templating/_jinja_plugins.py +7 -2
- ansible/_internal/_templating/_lazy_containers.py +5 -5
- ansible/config/base.yml +16 -6
- ansible/config/manager.py +7 -3
- ansible/executor/task_executor.py +4 -1
- ansible/executor/task_queue_manager.py +2 -2
- ansible/module_utils/_internal/_ansiballz/_extensions/_debugpy.py +97 -0
- ansible/module_utils/_internal/_ansiballz/_extensions/_pydevd.py +2 -4
- ansible/module_utils/_internal/_traceback.py +1 -1
- ansible/module_utils/ansible_release.py +1 -1
- ansible/module_utils/basic.py +10 -2
- ansible/module_utils/common/validation.py +4 -1
- ansible/modules/dnf.py +36 -50
- ansible/modules/dnf5.py +36 -29
- ansible/modules/meta.py +2 -1
- ansible/modules/service_facts.py +5 -1
- ansible/playbook/helpers.py +1 -0
- ansible/playbook/taggable.py +1 -2
- ansible/plugins/__init__.py +18 -10
- ansible/plugins/callback/__init__.py +6 -1
- ansible/plugins/lookup/template.py +6 -1
- ansible/release.py +1 -1
- ansible/utils/encrypt.py +2 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/METADATA +1 -1
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/RECORD +46 -45
- ansible_test/_internal/commands/integration/coverage.py +2 -2
- ansible_test/_internal/commands/shell/__init__.py +67 -28
- ansible_test/_internal/coverage_util.py +28 -25
- ansible_test/_internal/debugging.py +337 -49
- ansible_test/_internal/host_profiles.py +43 -43
- ansible_test/_internal/metadata.py +7 -42
- ansible_test/_internal/python_requirements.py +2 -2
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +1 -0
- ansible_test/_util/target/setup/bootstrap.sh +37 -16
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/WHEEL +0 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/COPYING +0 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/Apache-License.txt +0 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/BSD-3-Clause.txt +0 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/MIT-license.txt +0 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/PSF-license.txt +0 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/licenses/licenses/simplified_bsd.txt +0 -0
- {ansible_core-2.19.0rc2.dist-info → ansible_core-2.19.1rc1.dist-info}/top_level.txt +0 -0
|
@@ -167,7 +167,7 @@ class PosixCoverageHandler(CoverageHandler[PosixConfig]):
|
|
|
167
167
|
coverage_config_path = os.path.join(self.common_temp_path, COVERAGE_CONFIG_NAME)
|
|
168
168
|
coverage_output_path = os.path.join(self.common_temp_path, ResultType.COVERAGE.name)
|
|
169
169
|
|
|
170
|
-
coverage_config = generate_coverage_config(
|
|
170
|
+
coverage_config = generate_coverage_config()
|
|
171
171
|
|
|
172
172
|
write_text_file(coverage_config_path, coverage_config, create_directories=True)
|
|
173
173
|
|
|
@@ -260,7 +260,7 @@ class PosixCoverageHandler(CoverageHandler[PosixConfig]):
|
|
|
260
260
|
"""Return a dictionary of variables for setup and teardown of POSIX coverage."""
|
|
261
261
|
return dict(
|
|
262
262
|
common_temp_dir=self.common_temp_path,
|
|
263
|
-
coverage_config=generate_coverage_config(
|
|
263
|
+
coverage_config=generate_coverage_config(),
|
|
264
264
|
coverage_config_path=os.path.join(self.common_temp_path, COVERAGE_CONFIG_NAME),
|
|
265
265
|
coverage_output_path=os.path.join(self.common_temp_path, ResultType.COVERAGE.name),
|
|
266
266
|
mode_directory=f'{MODE_DIRECTORY:04o}',
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import contextlib
|
|
5
6
|
import dataclasses
|
|
6
7
|
import os
|
|
7
8
|
import sys
|
|
8
9
|
import typing as t
|
|
9
10
|
|
|
11
|
+
from ...data import (
|
|
12
|
+
data_context,
|
|
13
|
+
)
|
|
14
|
+
|
|
10
15
|
from ...util import (
|
|
11
16
|
ApplicationError,
|
|
12
17
|
OutputStream,
|
|
@@ -101,19 +106,33 @@ def command_shell(args: ShellConfig) -> None:
|
|
|
101
106
|
if args.export:
|
|
102
107
|
return
|
|
103
108
|
|
|
104
|
-
if args.cmd:
|
|
105
|
-
# Running a command is assumed to be non-interactive. Only a shell (no command) is interactive.
|
|
106
|
-
# If we want to support interactive commands in the future, we'll need an `--interactive` command line option.
|
|
107
|
-
# Command stderr output is allowed to mix with our own output, which is all sent to stderr.
|
|
108
|
-
con.run(args.cmd, capture=False, interactive=False, output_stream=OutputStream.ORIGINAL)
|
|
109
|
-
return
|
|
110
|
-
|
|
111
109
|
if isinstance(con, LocalConnection) and isinstance(target_profile, DebuggableProfile) and target_profile.debugging_enabled:
|
|
112
|
-
# HACK: ensure the
|
|
113
|
-
args.metadata.debugger_settings = dataclasses.replace(args.metadata.debugger_settings, port=target_profile.
|
|
110
|
+
# HACK: ensure the debugger port visible in the shell is the forwarded port, not the original
|
|
111
|
+
args.metadata.debugger_settings = dataclasses.replace(args.metadata.debugger_settings, port=target_profile.debugger_port)
|
|
114
112
|
|
|
115
|
-
with metadata_context(args):
|
|
116
|
-
|
|
113
|
+
with contextlib.nullcontext() if data_context().content.unsupported else metadata_context(args):
|
|
114
|
+
if args.cmd:
|
|
115
|
+
non_interactive_shell(args, target_profile, con)
|
|
116
|
+
else:
|
|
117
|
+
interactive_shell(args, target_profile, con)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def non_interactive_shell(
|
|
121
|
+
args: ShellConfig,
|
|
122
|
+
target_profile: SshTargetHostProfile,
|
|
123
|
+
con: Connection,
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Run a non-interactive shell command."""
|
|
126
|
+
if isinstance(target_profile, PosixProfile):
|
|
127
|
+
env = get_environment_variables(args, target_profile, con)
|
|
128
|
+
cmd = get_env_command(env) + args.cmd
|
|
129
|
+
else:
|
|
130
|
+
cmd = args.cmd
|
|
131
|
+
|
|
132
|
+
# Running a command is assumed to be non-interactive. Only a shell (no command) is interactive.
|
|
133
|
+
# If we want to support interactive commands in the future, we'll need an `--interactive` command line option.
|
|
134
|
+
# Command stderr output is allowed to mix with our own output, which is all sent to stderr.
|
|
135
|
+
con.run(cmd, capture=False, interactive=False, output_stream=OutputStream.ORIGINAL)
|
|
117
136
|
|
|
118
137
|
|
|
119
138
|
def interactive_shell(
|
|
@@ -135,23 +154,8 @@ def interactive_shell(
|
|
|
135
154
|
python = target_profile.python # make sure the python interpreter has been initialized before opening a shell
|
|
136
155
|
display.info(f'Target Python {python.version} is at: {python.path}')
|
|
137
156
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
env = {name: os.environ[name] for name in optional_vars if name in os.environ}
|
|
143
|
-
|
|
144
|
-
if isinstance(con, LocalConnection): # configure the controller environment
|
|
145
|
-
env.update(ansible_environment(args))
|
|
146
|
-
env.update(get_injector_env(target_profile.python, env))
|
|
147
|
-
env.update(ANSIBLE_TEST_METADATA_PATH=os.path.abspath(args.metadata_path))
|
|
148
|
-
|
|
149
|
-
if isinstance(target_profile, DebuggableProfile):
|
|
150
|
-
env.update(target_profile.get_ansiballz_environment_variables())
|
|
151
|
-
env.update(target_profile.get_ansible_cli_environment_variables())
|
|
152
|
-
|
|
153
|
-
if env:
|
|
154
|
-
cmd = ['/usr/bin/env'] + [f'{name}={value}' for name, value in env.items()]
|
|
157
|
+
env = get_environment_variables(args, target_profile, con)
|
|
158
|
+
cmd = get_env_command(env)
|
|
155
159
|
|
|
156
160
|
cmd += [shell, '-i']
|
|
157
161
|
else:
|
|
@@ -175,3 +179,38 @@ def interactive_shell(
|
|
|
175
179
|
raise HostConnectionError(f'SSH shell connection failed for host {target_profile.config}: {ex}', callback) from ex
|
|
176
180
|
|
|
177
181
|
raise
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def get_env_command(env: dict[str, str]) -> list[str]:
|
|
185
|
+
"""Get an `env` command to set the given environment variables, if any."""
|
|
186
|
+
if not env:
|
|
187
|
+
return []
|
|
188
|
+
|
|
189
|
+
return ['/usr/bin/env'] + [f'{name}={value}' for name, value in env.items()]
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def get_environment_variables(
|
|
193
|
+
args: ShellConfig,
|
|
194
|
+
target_profile: PosixProfile,
|
|
195
|
+
con: Connection,
|
|
196
|
+
) -> dict[str, str]:
|
|
197
|
+
"""Get the environment variables to expose to the shell."""
|
|
198
|
+
if data_context().content.unsupported:
|
|
199
|
+
return {}
|
|
200
|
+
|
|
201
|
+
optional_vars = (
|
|
202
|
+
'TERM', # keep backspace working
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
env = {name: os.environ[name] for name in optional_vars if name in os.environ}
|
|
206
|
+
|
|
207
|
+
if isinstance(con, LocalConnection): # configure the controller environment
|
|
208
|
+
env.update(ansible_environment(args))
|
|
209
|
+
env.update(get_injector_env(target_profile.python, env))
|
|
210
|
+
env.update(ANSIBLE_TEST_METADATA_PATH=os.path.abspath(args.metadata_path))
|
|
211
|
+
|
|
212
|
+
if isinstance(target_profile, DebuggableProfile):
|
|
213
|
+
env.update(target_profile.get_ansiballz_environment_variables())
|
|
214
|
+
env.update(target_profile.get_ansible_cli_environment_variables())
|
|
215
|
+
|
|
216
|
+
return env
|
|
@@ -6,11 +6,10 @@ import dataclasses
|
|
|
6
6
|
import os
|
|
7
7
|
import sqlite3
|
|
8
8
|
import tempfile
|
|
9
|
+
import textwrap
|
|
9
10
|
import typing as t
|
|
10
11
|
|
|
11
12
|
from .config import (
|
|
12
|
-
IntegrationConfig,
|
|
13
|
-
SanityConfig,
|
|
14
13
|
TestConfig,
|
|
15
14
|
)
|
|
16
15
|
|
|
@@ -217,7 +216,7 @@ def get_coverage_config(args: TestConfig) -> str:
|
|
|
217
216
|
except AttributeError:
|
|
218
217
|
pass
|
|
219
218
|
|
|
220
|
-
coverage_config = generate_coverage_config(
|
|
219
|
+
coverage_config = generate_coverage_config()
|
|
221
220
|
|
|
222
221
|
if args.explain:
|
|
223
222
|
temp_dir = '/tmp/coverage-temp-dir'
|
|
@@ -235,10 +234,10 @@ def get_coverage_config(args: TestConfig) -> str:
|
|
|
235
234
|
return path
|
|
236
235
|
|
|
237
236
|
|
|
238
|
-
def generate_coverage_config(
|
|
237
|
+
def generate_coverage_config() -> str:
|
|
239
238
|
"""Generate code coverage configuration for tests."""
|
|
240
239
|
if data_context().content.collection:
|
|
241
|
-
coverage_config = generate_collection_coverage_config(
|
|
240
|
+
coverage_config = generate_collection_coverage_config()
|
|
242
241
|
else:
|
|
243
242
|
coverage_config = generate_ansible_coverage_config()
|
|
244
243
|
|
|
@@ -265,12 +264,29 @@ omit =
|
|
|
265
264
|
*/test/results/*
|
|
266
265
|
"""
|
|
267
266
|
|
|
267
|
+
coverage_config = coverage_config.lstrip()
|
|
268
|
+
|
|
268
269
|
return coverage_config
|
|
269
270
|
|
|
270
271
|
|
|
271
|
-
def generate_collection_coverage_config(
|
|
272
|
+
def generate_collection_coverage_config() -> str:
|
|
272
273
|
"""Generate code coverage configuration for Ansible Collection tests."""
|
|
273
|
-
|
|
274
|
+
include_patterns = [
|
|
275
|
+
# {base}/ansible_collections/{ns}/{col}/*
|
|
276
|
+
os.path.join(data_context().content.root, '*'),
|
|
277
|
+
# */ansible_collections/{ns}/{col}/* (required to pick up AnsiballZ coverage)
|
|
278
|
+
os.path.join('*', data_context().content.collection.directory, '*'),
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
omit_patterns = [
|
|
282
|
+
# {base}/ansible_collections/{ns}/{col}/tests/output/*
|
|
283
|
+
os.path.join(data_context().content.root, data_context().content.results_path, '*'),
|
|
284
|
+
]
|
|
285
|
+
|
|
286
|
+
include = textwrap.indent('\n'.join(include_patterns), ' ' * 4)
|
|
287
|
+
omit = textwrap.indent('\n'.join(omit_patterns), ' ' * 4)
|
|
288
|
+
|
|
289
|
+
coverage_config = f"""
|
|
274
290
|
[run]
|
|
275
291
|
branch = True
|
|
276
292
|
concurrency =
|
|
@@ -279,28 +295,15 @@ concurrency =
|
|
|
279
295
|
parallel = True
|
|
280
296
|
disable_warnings =
|
|
281
297
|
no-data-collected
|
|
282
|
-
"""
|
|
283
298
|
|
|
284
|
-
if isinstance(args, IntegrationConfig):
|
|
285
|
-
coverage_config += """
|
|
286
|
-
include =
|
|
287
|
-
%s/*
|
|
288
|
-
*/%s/*
|
|
289
|
-
""" % (data_context().content.root, data_context().content.collection.directory)
|
|
290
|
-
elif isinstance(args, SanityConfig):
|
|
291
|
-
# temporary work-around for import sanity test
|
|
292
|
-
coverage_config += """
|
|
293
299
|
include =
|
|
294
|
-
|
|
300
|
+
{include}
|
|
295
301
|
|
|
296
302
|
omit =
|
|
297
|
-
|
|
298
|
-
"""
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
include =
|
|
302
|
-
%s/*
|
|
303
|
-
""" % data_context().content.root
|
|
303
|
+
{omit}
|
|
304
|
+
"""
|
|
305
|
+
|
|
306
|
+
coverage_config = coverage_config.lstrip()
|
|
304
307
|
|
|
305
308
|
return coverage_config
|
|
306
309
|
|