* Fix ansible-test units requirements install.
* Run unit tests as unprivileged user under Docker.
(cherry picked from commit 379a7f4f5a0491964c7896834f3f326412888585)
... | ... |
@@ -237,6 +237,13 @@ class UnitsConfig(TestConfig): |
237 | 237 |
|
238 | 238 |
self.collect_only = args.collect_only # type: bool |
239 | 239 |
|
240 |
+ self.requirements_mode = args.requirements_mode if 'requirements_mode' in args else '' |
|
241 |
+ |
|
242 |
+ if self.requirements_mode == 'only': |
|
243 |
+ self.requirements = True |
|
244 |
+ elif self.requirements_mode == 'skip': |
|
245 |
+ self.requirements = False |
|
246 |
+ |
|
240 | 247 |
|
241 | 248 |
class CoverageConfig(EnvironmentConfig): |
242 | 249 |
"""Configuration for the coverage command.""" |
... | ... |
@@ -275,6 +275,29 @@ def delegate_docker(args, exclude, require, integration_targets): |
275 | 275 |
if isinstance(args, UnitsConfig) and not args.python: |
276 | 276 |
cmd += ['--python', 'default'] |
277 | 277 |
|
278 |
+ # run unit tests unprivileged to prevent stray writes to the source tree |
|
279 |
+ if isinstance(args, UnitsConfig): |
|
280 |
+ writable_dirs = [ |
|
281 |
+ '/root/ansible/lib/ansible.egg-info', |
|
282 |
+ '/root/ansible/.pytest_cache', |
|
283 |
+ ] |
|
284 |
+ |
|
285 |
+ docker_exec(args, test_id, ['mkdir', '-p'] + writable_dirs) |
|
286 |
+ docker_exec(args, test_id, ['chmod', '777'] + writable_dirs) |
|
287 |
+ |
|
288 |
+ docker_exec(args, test_id, ['find', '/root/ansible/test/results/', '-type', 'd', '-exec', 'chmod', '777', '{}', '+']) |
|
289 |
+ |
|
290 |
+ docker_exec(args, test_id, ['chmod', '755', '/root']) |
|
291 |
+ docker_exec(args, test_id, ['chmod', '644', '/root/ansible/%s' % args.metadata_path]) |
|
292 |
+ |
|
293 |
+ docker_exec(args, test_id, ['useradd', 'pytest', '--create-home']) |
|
294 |
+ |
|
295 |
+ docker_exec(args, test_id, cmd + ['--requirements-mode', 'only'], options=cmd_options) |
|
296 |
+ |
|
297 |
+ cmd += ['--requirements-mode', 'skip'] |
|
298 |
+ |
|
299 |
+ cmd_options += ['--user', 'pytest'] |
|
300 |
+ |
|
278 | 301 |
try: |
279 | 302 |
docker_exec(args, test_id, cmd, options=cmd_options) |
280 | 303 |
finally: |
... | ... |
@@ -12,6 +12,7 @@ import time |
12 | 12 |
import textwrap |
13 | 13 |
import functools |
14 | 14 |
import pipes |
15 |
+import sys |
|
15 | 16 |
import hashlib |
16 | 17 |
|
17 | 18 |
import lib.pytar |
... | ... |
@@ -49,6 +50,8 @@ from lib.util import ( |
49 | 49 |
raw_command, |
50 | 50 |
get_coverage_path, |
51 | 51 |
get_available_port, |
52 |
+ generate_pip_command, |
|
53 |
+ find_python, |
|
52 | 54 |
) |
53 | 55 |
|
54 | 56 |
from lib.docker_util import ( |
... | ... |
@@ -148,9 +151,10 @@ def create_shell_command(command): |
148 | 148 |
return cmd |
149 | 149 |
|
150 | 150 |
|
151 |
-def install_command_requirements(args): |
|
151 |
+def install_command_requirements(args, python_version=None): |
|
152 | 152 |
""" |
153 | 153 |
:type args: EnvironmentConfig |
154 |
+ :type python_version: str | None |
|
154 | 155 |
""" |
155 | 156 |
generate_egg_info(args) |
156 | 157 |
|
... | ... |
@@ -168,7 +172,10 @@ def install_command_requirements(args): |
168 | 168 |
if args.junit: |
169 | 169 |
packages.append('junit-xml') |
170 | 170 |
|
171 |
- pip = args.pip_command |
|
171 |
+ if not python_version: |
|
172 |
+ python_version = args.python_version |
|
173 |
+ |
|
174 |
+ pip = generate_pip_command(find_python(python_version)) |
|
172 | 175 |
|
173 | 176 |
commands = [generate_pip_install(pip, args.command, packages=packages)] |
174 | 177 |
|
... | ... |
@@ -1133,8 +1140,6 @@ def command_units(args): |
1133 | 1133 |
if args.delegate: |
1134 | 1134 |
raise Delegate(require=changes) |
1135 | 1135 |
|
1136 |
- install_command_requirements(args) |
|
1137 |
- |
|
1138 | 1136 |
version_commands = [] |
1139 | 1137 |
|
1140 | 1138 |
for version in SUPPORTED_PYTHON_VERSIONS: |
... | ... |
@@ -1142,6 +1147,9 @@ def command_units(args): |
1142 | 1142 |
if args.python and version != args.python_version: |
1143 | 1143 |
continue |
1144 | 1144 |
|
1145 |
+ if args.requirements_mode != 'skip': |
|
1146 |
+ install_command_requirements(args, version) |
|
1147 |
+ |
|
1145 | 1148 |
env = ansible_environment(args) |
1146 | 1149 |
|
1147 | 1150 |
cmd = [ |
... | ... |
@@ -1167,6 +1175,9 @@ def command_units(args): |
1167 | 1167 |
|
1168 | 1168 |
version_commands.append((version, cmd, env)) |
1169 | 1169 |
|
1170 |
+ if args.requirements_mode == 'only': |
|
1171 |
+ sys.exit() |
|
1172 |
+ |
|
1170 | 1173 |
for version, command, env in version_commands: |
1171 | 1174 |
display.info('Unit test with Python %s' % version) |
1172 | 1175 |
|
... | ... |
@@ -335,6 +335,10 @@ def parse_args(): |
335 | 335 |
action='store_true', |
336 | 336 |
help='collect tests but do not execute them') |
337 | 337 |
|
338 |
+ units.add_argument('--requirements-mode', |
|
339 |
+ choices=('only', 'skip'), |
|
340 |
+ help=argparse.SUPPRESS) |
|
341 |
+ |
|
338 | 342 |
add_extra_docker_options(units, integration=False) |
339 | 343 |
|
340 | 344 |
sanity = subparsers.add_parser('sanity', |