Skip to content

Commit

Permalink
ansible-test - Add --prime-containers option.
Browse files Browse the repository at this point in the history
Resolves ansible#75320

The option `--prime-containers` was chosen over `--docker-pull-only` to match the recently added `--prime-venvs` option for sanity tests.
It would also fit well with a future `--prime-requirements` option for pre-installing requirements for unit and integration tests.
  • Loading branch information
mattclay committed Sep 23, 2021
1 parent 28a094c commit e3fd9b0
Show file tree
Hide file tree
Showing 12 changed files with 55 additions and 4 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/ansible-test-prime-containers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- ansible-test - Added a ``--prime-containers`` option to support downloading containers without running tests.
6 changes: 6 additions & 0 deletions test/lib/ansible_test/_internal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
parse_args,
)

from .provisioning import (
PrimeContainers,
)


def main():
"""Main program function."""
Expand All @@ -64,6 +68,8 @@ def main():

try:
args.func(config)
except PrimeContainers:
pass
except ListTargets as ex:
# save target_names for use once we exit the exception handler
target_names = ex.target_names
Expand Down
7 changes: 7 additions & 0 deletions test/lib/ansible_test/_internal/cli/environments.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ def add_global_docker(
docker_no_pull=False,
docker_network=None,
docker_terminate=None,
prime_containers=False,
)

return
Expand All @@ -410,6 +411,12 @@ def add_global_docker(
help='terminate the container: %(choices)s (default: %(default)s)',
)

parser.add_argument(
'--prime-containers',
action='store_true',
help='download containers without running tests',
)


def add_environment_docker(
exclusive_parser, # type: argparse.ArgumentParser
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ def cloud_init(args, targets): # type: (IntegrationConfig, t.Tuple[IntegrationT

results = {}

for provider in get_cloud_providers(args, targets):
for provider in get_cloud_providers(args, targets): # type: CloudProvider
if args.prime_containers and not provider.uses_docker:
continue

args.metadata.cloud_config[provider.platform] = {}

start_time = time.time()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def _setup_dynamic(self): # type: () -> None
self.port,
]

run_support_container(
descriptor = run_support_container(
self.args,
self.platform,
self.image,
Expand All @@ -101,6 +101,9 @@ def _setup_dynamic(self): # type: () -> None
cleanup=CleanupMode.YES,
)

if not descriptor:
return

# apply work-around for OverlayFS issue
# https://github.com/docker/for-linux/issues/72#issuecomment-319904698
docker_exec(self.args, self.DOCKER_SIMULATOR_NAME, ['find', '/var/lib/mysql', '-type', 'f', '-exec', 'touch', '{}', ';'])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ def setup(self): # type: () -> None
allow_existing=True,
)

if not descriptor:
return

if not descriptor.running:
pulp_id = descriptor.container_id

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ def setup(self): # type: () -> None
},
)

if not descriptor:
return

# Read the password from the container environment.
# This allows the tests to work when re-using an existing container.
# The password is marked as sensitive, since it may differ from the one we generated.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def _setup_dynamic(self): # type: () -> None

cmd = ['start', 'master', '--listen', 'https://0.0.0.0:%d' % port]

run_support_container(
descriptor = run_support_container(
self.args,
self.platform,
self.image,
Expand All @@ -80,6 +80,9 @@ def _setup_dynamic(self): # type: () -> None
cmd=cmd,
)

if not descriptor:
return

if self.args.explain:
config = '# Unknown'
else:
Expand Down
2 changes: 2 additions & 0 deletions test/lib/ansible_test/_internal/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ def __init__(self, args, command): # type: (t.Any, str) -> None
self.remote_stage = args.remote_stage # type: t.Optional[str]
self.remote_terminate = args.remote_terminate # type: t.Optional[TerminateMode]

self.prime_containers = args.prime_containers # type: bool

self.requirements = args.requirements # type: bool

self.delegate_args = [] # type: t.List[str]
Expand Down
6 changes: 5 additions & 1 deletion test/lib/ansible_test/_internal/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,15 @@ def run_support_container(
env=None, # type: t.Optional[t.Dict[str, str]]
options=None, # type: t.Optional[t.List[str]]
publish_ports=True, # type: bool
): # type: (...) -> ContainerDescriptor
): # type: (...) -> t.Optional[ContainerDescriptor]
"""
Start a container used to support tests, but not run them.
Containers created this way will be accessible from tests.
"""
if args.prime_containers:
docker_pull(args, image)
return None

# SSH is required for publishing ports, as well as modifying the hosts file.
# Initializing the SSH key here makes sure it is available for use after delegation.
SshKey(args)
Expand Down
3 changes: 3 additions & 0 deletions test/lib/ansible_test/_internal/host_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@ def provision(self): # type: () -> None
cleanup=CleanupMode.NO,
)

if not container:
return

self.container_name = container.name

def setup(self): # type: () -> None
Expand Down
12 changes: 12 additions & 0 deletions test/lib/ansible_test/_internal/provisioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

from .host_profiles import (
ControllerHostProfile,
DockerProfile,
HostProfile,
SshConnection,
SshTargetHostProfile,
Expand All @@ -44,6 +45,10 @@
TEnvironmentConfig = t.TypeVar('TEnvironmentConfig', bound=EnvironmentConfig)


class PrimeContainers(ApplicationError):
"""Exception raised to end execution early after priming containers."""


@dataclasses.dataclass(frozen=True)
class HostState:
"""State of hosts and profiles to be passed to ansible-test during delegation."""
Expand Down Expand Up @@ -109,6 +114,13 @@ def prepare_profiles(
target_profiles=[create_host_profile(args, target, False) for target in args.targets],
)

if args.prime_containers:
for host_profile in host_state.profiles:
if isinstance(host_profile, DockerProfile):
host_profile.provision()

raise PrimeContainers()

atexit.register(functools.partial(cleanup_profiles, host_state))

def provision(profile): # type: (HostProfile) -> None
Expand Down

0 comments on commit e3fd9b0

Please sign in to comment.