diff options
author | Matt Clay <mclay@redhat.com> | 2020-10-22 21:50:12 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-22 23:50:12 -0500 |
commit | 73b2199fa28fa68bcf3c514f3b30da579af7c14b (patch) | |
tree | 779a43593ad7ffcb5b71d9e0b913a67a33472850 | |
parent | d86d4285e1923eeda0749825feb4242f109fad71 (diff) | |
download | ansible-73b2199fa28fa68bcf3c514f3b30da579af7c14b.tar.gz |
[stable-2.8] [stable-2.9] [stable-2.10] Fix ansible-test handling of user-defined docker networks. (#72256) (#72310)
* Fix ansible-test docker container detection.
* Attach test containers to the correct network.
* Do not assume `localhost` for accesing Docker.
* Look for containers on current network.
* Always map /var/run/docker.sock into containers.
This fixes issues when using a remote Docker host.
* Support container IP lookup from networks list.
* Fix container network attachment.
* Remove redundant container detection messages.
* Limit DOCKER_HOST parsing to TCP.
* Restore docker socket existence check.
The check is skipped if the docker hostname is not localhost.
* Correct changelog entry..
(cherry picked from commit 3c2e8b99be4c001c9955bcee7baa12fd46147b90)
Co-authored-by: Matt Clay <mclay@redhat.com>.
(cherry picked from commit 6362232c304ae3e4588a3e5e14d89560c31fdb3d)
Co-authored-by: Matt Clay <mclay@redhat.com>.
(cherry picked from commit 7c83f1f045e51930eeeb988b987c44351c8cacd0)
Co-authored-by: Matt Clay <mclay@redhat.com>
-rw-r--r-- | changelogs/fragments/ansible-test-container-ip-lookup.yml | 2 | ||||
-rw-r--r-- | changelogs/fragments/ansible-test-docker-default-network.yml | 4 | ||||
-rw-r--r-- | changelogs/fragments/ansible-test-docker-detection-fix.yml | 2 | ||||
-rw-r--r-- | changelogs/fragments/ansible-test-docker-not-localhost.yml | 2 | ||||
-rw-r--r-- | changelogs/fragments/ansible-test-docker-socket.yml | 2 | ||||
-rw-r--r-- | changelogs/fragments/ansible-test-network-container-search.yml | 2 | ||||
-rw-r--r-- | test/runner/lib/cli.py | 3 | ||||
-rw-r--r-- | test/runner/lib/cloud/acme.py | 17 | ||||
-rw-r--r-- | test/runner/lib/cloud/cs.py | 21 | ||||
-rw-r--r-- | test/runner/lib/cloud/foreman.py | 23 | ||||
-rw-r--r-- | test/runner/lib/cloud/nios.py | 23 | ||||
-rw-r--r-- | test/runner/lib/cloud/openshift.py | 21 | ||||
-rw-r--r-- | test/runner/lib/cloud/vcenter.py | 17 | ||||
-rw-r--r-- | test/runner/lib/config.py | 1 | ||||
-rw-r--r-- | test/runner/lib/delegation.py | 13 | ||||
-rw-r--r-- | test/runner/lib/docker_util.py | 127 | ||||
-rw-r--r-- | test/runner/lib/executor.py | 16 |
17 files changed, 224 insertions, 72 deletions
diff --git a/changelogs/fragments/ansible-test-container-ip-lookup.yml b/changelogs/fragments/ansible-test-container-ip-lookup.yml new file mode 100644 index 0000000000..d5dbf7b874 --- /dev/null +++ b/changelogs/fragments/ansible-test-container-ip-lookup.yml @@ -0,0 +1,2 @@ +bugfixes: + - ansible-test - Prefer container IP at ``.NetworkSettings.Networks.{NetworkName}.IPAddress`` over ``.NetworkSettings.IPAddress``. diff --git a/changelogs/fragments/ansible-test-docker-default-network.yml b/changelogs/fragments/ansible-test-docker-default-network.yml new file mode 100644 index 0000000000..6279b39c54 --- /dev/null +++ b/changelogs/fragments/ansible-test-docker-default-network.yml @@ -0,0 +1,4 @@ +bugfixes: + - ansible-test - Always connect additional Docker containers to the network used by the current container (if any). +minor_changes: + - ansible-test - Add a ``--docker-network`` option to choose the network for running containers when using the ``--docker`` option. diff --git a/changelogs/fragments/ansible-test-docker-detection-fix.yml b/changelogs/fragments/ansible-test-docker-detection-fix.yml new file mode 100644 index 0000000000..fcd56277ff --- /dev/null +++ b/changelogs/fragments/ansible-test-docker-detection-fix.yml @@ -0,0 +1,2 @@ +bugfixes: + - ansible-test - Correctly detect running in a Docker container on Azure Pipelines. diff --git a/changelogs/fragments/ansible-test-docker-not-localhost.yml b/changelogs/fragments/ansible-test-docker-not-localhost.yml new file mode 100644 index 0000000000..4b801e3f44 --- /dev/null +++ b/changelogs/fragments/ansible-test-docker-not-localhost.yml @@ -0,0 +1,2 @@ +bugfixes: + - ansible-test - Attempt to detect the Docker hostname instead of assuming ``localhost``. diff --git a/changelogs/fragments/ansible-test-docker-socket.yml b/changelogs/fragments/ansible-test-docker-socket.yml new file mode 100644 index 0000000000..13b12c12c8 --- /dev/null +++ b/changelogs/fragments/ansible-test-docker-socket.yml @@ -0,0 +1,2 @@ +bugfixes: + - ansible-test - Always map ``/var/run/docker.sock`` into test containers created by the ``--docker`` option if the docker host is not ``localhost``. diff --git a/changelogs/fragments/ansible-test-network-container-search.yml b/changelogs/fragments/ansible-test-network-container-search.yml new file mode 100644 index 0000000000..b314541758 --- /dev/null +++ b/changelogs/fragments/ansible-test-network-container-search.yml @@ -0,0 +1,2 @@ +bugfixes: + - ansible-test - The ``cs`` and ``openshift`` test plugins now search for containers on the current network instead of assuming the ``bridge`` network. diff --git a/test/runner/lib/cli.py b/test/runner/lib/cli.py index cb49cacba4..aba146cdfc 100644 --- a/test/runner/lib/cli.py +++ b/test/runner/lib/cli.py @@ -757,6 +757,9 @@ def add_extra_docker_options(parser, integration=True): action='store_true', help='run docker container in privileged mode') + docker.add_argument('--docker-network', + help='run using the specified docker network') + docker.add_argument('--docker-memory', help='memory limit for docker in bytes', type=int) diff --git a/test/runner/lib/cloud/acme.py b/test/runner/lib/cloud/acme.py index 0a567a6e9a..233ad80178 100644 --- a/test/runner/lib/cloud/acme.py +++ b/test/runner/lib/cloud/acme.py @@ -27,6 +27,10 @@ from lib.docker_util import ( docker_inspect, docker_pull, get_docker_container_id, + get_docker_hostname, + get_docker_container_ip, + get_docker_preferred_network_name, + is_docker_user_defined_network, ) @@ -99,7 +103,9 @@ class ACMEProvider(CloudProvider): """Get any additional options needed when delegating tests to a docker container. :rtype: list[str] """ - if self.managed: + network = get_docker_preferred_network_name(self.args) + + if self.managed and not is_docker_user_defined_network(network): return ['--link', self.DOCKER_SIMULATOR_NAME] return [] @@ -115,9 +121,6 @@ class ACMEProvider(CloudProvider): """Create a ACME test container using docker.""" container_id = get_docker_container_id() - if container_id: - display.info('Running in docker container: %s' % container_id, verbosity=1) - self.container_name = self.DOCKER_SIMULATOR_NAME results = docker_inspect(self.args, self.container_name) @@ -157,7 +160,7 @@ class ACMEProvider(CloudProvider): acme_host_ip = acme_host display.info('Found ACME test container address: %s' % acme_host, verbosity=1) else: - acme_host = 'localhost' + acme_host = get_docker_hostname() acme_host_ip = acme_host self._set_cloud_config('acme_host', acme_host) @@ -166,9 +169,7 @@ class ACMEProvider(CloudProvider): self._wait_for_service('https', acme_host_ip, 14000, 'dir', 'ACME CA endpoint') def _get_simulator_address(self): - results = docker_inspect(self.args, self.container_name) - ipaddress = results[0]['NetworkSettings']['IPAddress'] - return ipaddress + return get_docker_container_ip(self.args, self.container_name) def _setup_static(self): raise NotImplementedError() diff --git a/test/runner/lib/cloud/cs.py b/test/runner/lib/cloud/cs.py index c64f17aaba..965a967b9a 100644 --- a/test/runner/lib/cloud/cs.py +++ b/test/runner/lib/cloud/cs.py @@ -34,6 +34,9 @@ from lib.docker_util import ( docker_network_inspect, docker_exec, get_docker_container_id, + get_docker_preferred_network_name, + get_docker_hostname, + is_docker_user_defined_network, ) @@ -89,7 +92,7 @@ class CsCloudProvider(CloudProvider): :rtype: list[str] """ if self.managed: - return ['-R', '8888:localhost:8888'] + return ['-R', '8888:%s:8888' % get_docker_hostname()] return [] @@ -97,7 +100,9 @@ class CsCloudProvider(CloudProvider): """Get any additional options needed when delegating tests to a docker container. :rtype: list[str] """ - if self.managed: + network = get_docker_preferred_network_name(self.args) + + if self.managed and not is_docker_user_defined_network(network): return ['--link', self.DOCKER_SIMULATOR_NAME] return [] @@ -168,11 +173,10 @@ class CsCloudProvider(CloudProvider): container_id = get_docker_container_id() if container_id: - display.info('Running in docker container: %s' % container_id, verbosity=1) self.host = self._get_simulator_address() display.info('Found CloudStack simulator container address: %s' % self.host, verbosity=1) else: - self.host = 'localhost' + self.host = get_docker_hostname() self.port = 8888 self.endpoint = 'http://%s:%d' % (self.host, self.port) @@ -189,6 +193,8 @@ class CsCloudProvider(CloudProvider): if self.args.docker: host = self.DOCKER_SIMULATOR_NAME + elif self.args.remote: + host = 'localhost' else: host = self.host @@ -206,11 +212,12 @@ class CsCloudProvider(CloudProvider): self._write_config(config) def _get_simulator_address(self): - networks = docker_network_inspect(self.args, 'bridge') + current_network = get_docker_preferred_network_name(self.args) + networks = docker_network_inspect(self.args, current_network) try: - bridge = [network for network in networks if network['Name'] == 'bridge'][0] - containers = bridge['Containers'] + network = [network for network in networks if network['Name'] == current_network][0] + containers = network['Containers'] container = [containers[container] for container in containers if containers[container]['Name'] == self.DOCKER_SIMULATOR_NAME][0] return re.sub(r'/[0-9]+$', '', container['IPv4Address']) except Exception: diff --git a/test/runner/lib/cloud/foreman.py b/test/runner/lib/cloud/foreman.py index 14b99c275a..0cc2c68e2b 100644 --- a/test/runner/lib/cloud/foreman.py +++ b/test/runner/lib/cloud/foreman.py @@ -21,6 +21,10 @@ from ..docker_util import ( docker_inspect, docker_pull, get_docker_container_id, + get_docker_hostname, + get_docker_container_ip, + get_docker_preferred_network_name, + is_docker_user_defined_network, ) @@ -96,7 +100,12 @@ class ForemanProvider(CloudProvider): :rtype: list[str] """ - return ['--link', self.DOCKER_SIMULATOR_NAME] if self.managed else [] + network = get_docker_preferred_network_name(self.args) + + if self.managed and not is_docker_user_defined_network(network): + return ['--link', self.DOCKER_SIMULATOR_NAME] + + return [] def cleanup(self): """Clean up the resource and temporary configs files after tests.""" @@ -110,12 +119,6 @@ class ForemanProvider(CloudProvider): foreman_port = 8080 container_id = get_docker_container_id() - if container_id: - display.info( - 'Running in docker container: %s' % container_id, - verbosity=1, - ) - self.container_name = self.DOCKER_SIMULATOR_NAME results = docker_inspect(self.args, self.container_name) @@ -157,15 +160,13 @@ class ForemanProvider(CloudProvider): % foreman_host, verbosity=1 ) else: - foreman_host = 'localhost' + foreman_host = get_docker_hostname() self._set_cloud_config('FOREMAN_HOST', foreman_host) self._set_cloud_config('FOREMAN_PORT', str(foreman_port)) def _get_simulator_address(self): - results = docker_inspect(self.args, self.container_name) - ip_address = results[0]['NetworkSettings']['IPAddress'] - return ip_address + return get_docker_container_ip(self.args, self.container_name) def _setup_static(self): raise NotImplementedError diff --git a/test/runner/lib/cloud/nios.py b/test/runner/lib/cloud/nios.py index 7d58631223..d13a2d9bc9 100644 --- a/test/runner/lib/cloud/nios.py +++ b/test/runner/lib/cloud/nios.py @@ -21,6 +21,10 @@ from ..docker_util import ( docker_inspect, docker_pull, get_docker_container_id, + get_docker_hostname, + get_docker_container_ip, + get_docker_preferred_network_name, + is_docker_user_defined_network, ) @@ -96,7 +100,12 @@ class NiosProvider(CloudProvider): :rtype: list[str] """ - return ['--link', self.DOCKER_SIMULATOR_NAME] if self.managed else [] + network = get_docker_preferred_network_name(self.args) + + if self.managed and not is_docker_user_defined_network(network): + return ['--link', self.DOCKER_SIMULATOR_NAME] + + return [] def cleanup(self): """Clean up the resource and temporary configs files after tests.""" @@ -110,12 +119,6 @@ class NiosProvider(CloudProvider): nios_port = 443 container_id = get_docker_container_id() - if container_id: - display.info( - 'Running in docker container: %s' % container_id, - verbosity=1, - ) - self.container_name = self.DOCKER_SIMULATOR_NAME results = docker_inspect(self.args, self.container_name) @@ -157,14 +160,12 @@ class NiosProvider(CloudProvider): % nios_host, verbosity=1 ) else: - nios_host = 'localhost' + nios_host = get_docker_hostname() self._set_cloud_config('NIOS_HOST', nios_host) def _get_simulator_address(self): - results = docker_inspect(self.args, self.container_name) - ip_address = results[0]['NetworkSettings']['IPAddress'] - return ip_address + return get_docker_container_ip(self.args, self.container_name) def _setup_static(self): raise NotImplementedError diff --git a/test/runner/lib/cloud/openshift.py b/test/runner/lib/cloud/openshift.py index 3e294ccde1..5d11ec4844 100644 --- a/test/runner/lib/cloud/openshift.py +++ b/test/runner/lib/cloud/openshift.py @@ -31,6 +31,9 @@ from lib.docker_util import ( docker_pull, docker_network_inspect, get_docker_container_id, + get_docker_preferred_network_name, + get_docker_hostname, + is_docker_user_defined_network, ) @@ -83,7 +86,7 @@ class OpenShiftCloudProvider(CloudProvider): :rtype: list[str] """ if self.managed: - return ['-R', '8443:localhost:8443'] + return ['-R', '8443:%s:8443' % get_docker_hostname()] return [] @@ -91,7 +94,9 @@ class OpenShiftCloudProvider(CloudProvider): """Get any additional options needed when delegating tests to a docker container. :rtype: list[str] """ - if self.managed: + network = get_docker_preferred_network_name(self.args) + + if self.managed and not is_docker_user_defined_network(network): return ['--link', self.DOCKER_CONTAINER_NAME] return [] @@ -137,11 +142,10 @@ class OpenShiftCloudProvider(CloudProvider): container_id = get_docker_container_id() if container_id: - display.info('Running in docker container: %s' % container_id, verbosity=1) host = self._get_container_address() display.info('Found OpenShift container address: %s' % host, verbosity=1) else: - host = 'localhost' + host = get_docker_hostname() port = 8443 endpoint = 'https://%s:%s/' % (host, port) @@ -153,6 +157,8 @@ class OpenShiftCloudProvider(CloudProvider): else: if self.args.docker: host = self.DOCKER_CONTAINER_NAME + elif self.args.remote: + host = 'localhost' server = 'https://%s:%s' % (host, port) config = self._get_config(server) @@ -160,11 +166,12 @@ class OpenShiftCloudProvider(CloudProvider): self._write_config(config) def _get_container_address(self): - networks = docker_network_inspect(self.args, 'bridge') + current_network = get_docker_preferred_network_name(self.args) + networks = docker_network_inspect(self.args, current_network) try: - bridge = [network for network in networks if network['Name'] == 'bridge'][0] - containers = bridge['Containers'] + network = [network for network in networks if network['Name'] == current_network][0] + containers = network['Containers'] container = [containers[container] for container in containers if containers[container]['Name'] == self.DOCKER_CONTAINER_NAME][0] return re.sub(r'/[0-9]+$', '', container['IPv4Address']) except Exception: diff --git a/test/runner/lib/cloud/vcenter.py b/test/runner/lib/cloud/vcenter.py index 2dd9dc05d9..0e74a21f44 100644 --- a/test/runner/lib/cloud/vcenter.py +++ b/test/runner/lib/cloud/vcenter.py @@ -20,6 +20,10 @@ from lib.docker_util import ( docker_inspect, docker_pull, get_docker_container_id, + get_docker_hostname, + get_docker_container_ip, + get_docker_preferred_network_name, + is_docker_user_defined_network, ) @@ -71,7 +75,9 @@ class VcenterProvider(CloudProvider): """Get any additional options needed when delegating tests to a docker container. :rtype: list[str] """ - if self.managed: + network = get_docker_preferred_network_name(self.args) + + if self.managed and not is_docker_user_defined_network(network): return ['--link', self.DOCKER_SIMULATOR_NAME] return [] @@ -87,9 +93,6 @@ class VcenterProvider(CloudProvider): """Create a vcenter simulator using docker.""" container_id = get_docker_container_id() - if container_id: - display.info('Running in docker container: %s' % container_id, verbosity=1) - self.container_name = self.DOCKER_SIMULATOR_NAME results = docker_inspect(self.args, self.container_name) @@ -130,14 +133,12 @@ class VcenterProvider(CloudProvider): vcenter_host = self._get_simulator_address() display.info('Found vCenter simulator container address: %s' % vcenter_host, verbosity=1) else: - vcenter_host = 'localhost' + vcenter_host = get_docker_hostname() self._set_cloud_config('vcenter_host', vcenter_host) def _get_simulator_address(self): - results = docker_inspect(self.args, self.container_name) - ipaddress = results[0]['NetworkSettings']['IPAddress'] - return ipaddress + return get_docker_container_ip(self.args, self.container_name) def _setup_static(self): raise NotImplementedError() diff --git a/test/runner/lib/config.py b/test/runner/lib/config.py index 95b059f982..08ef098bbc 100644 --- a/test/runner/lib/config.py +++ b/test/runner/lib/config.py @@ -49,6 +49,7 @@ class EnvironmentConfig(CommonConfig): self.docker_keep_git = args.docker_keep_git if 'docker_keep_git' in args else False # type: bool self.docker_seccomp = args.docker_seccomp if 'docker_seccomp' in args else None # type: str self.docker_memory = args.docker_memory if 'docker_memory' in args else None + self.docker_network = args.docker_network if 'docker_network' in args else None # type: str if self.docker_seccomp is None: self.docker_seccomp = get_docker_completion().get(self.docker_raw, {}).get('seccomp', 'default') diff --git a/test/runner/lib/delegation.py b/test/runner/lib/delegation.py index b3caf4c210..65bf45222b 100644 --- a/test/runner/lib/delegation.py +++ b/test/runner/lib/delegation.py @@ -58,6 +58,9 @@ from lib.docker_util import ( docker_available, docker_network_disconnect, get_docker_networks, + get_docker_preferred_network_name, + get_docker_hostname, + is_docker_user_defined_network, ) from lib.cloud import ( @@ -268,14 +271,18 @@ def delegate_docker(args, exclude, require, integration_targets): if args.docker_seccomp != 'default': test_options += ['--security-opt', 'seccomp=%s' % args.docker_seccomp] - if os.path.exists(docker_socket): + if get_docker_hostname() != 'localhost' or os.path.exists(docker_socket): test_options += ['--volume', '%s:%s' % (docker_socket, docker_socket)] if httptester_id: test_options += ['--env', 'HTTPTESTER=1'] - for host in HTTPTESTER_HOSTS: - test_options += ['--link', '%s:%s' % (httptester_id, host)] + network = get_docker_preferred_network_name(args) + + if not is_docker_user_defined_network(network): + # legacy links are required when using the default bridge network instead of user-defined networks + for host in HTTPTESTER_HOSTS: + test_options += ['--link', '%s:%s' % (httptester_id, host)] if isinstance(args, IntegrationConfig): cloud_platforms = get_cloud_providers(args) diff --git a/test/runner/lib/docker_util.py b/test/runner/lib/docker_util.py index 118a1929d2..722a33d9bb 100644 --- a/test/runner/lib/docker_util.py +++ b/test/runner/lib/docker_util.py @@ -18,6 +18,10 @@ from lib.util import ( find_executable, ) +from lib.http import ( + urlparse, +) + from lib.config import ( EnvironmentConfig, ) @@ -32,28 +36,63 @@ def docker_available(): return find_executable('docker', required=False) +def get_docker_hostname(): # type: () -> str + """Return the hostname of the Docker service.""" + try: + return get_docker_hostname.hostname + except AttributeError: + pass + + docker_host = os.environ.get('DOCKER_HOST') + + if docker_host and docker_host.startswith('tcp://'): + try: + hostname = urlparse(docker_host)[1].split(':')[0] + display.info('Detected Docker host: %s' % hostname, verbosity=1) + except ValueError: + hostname = 'localhost' + display.warning('Could not parse DOCKER_HOST environment variable "%s", falling back to localhost.' % docker_host) + else: + hostname = 'localhost' + display.info('Assuming Docker is available on localhost.', verbosity=1) + + get_docker_hostname.hostname = hostname + + return hostname + + def get_docker_container_id(): """ :rtype: str | None """ - path = '/proc/self/cgroup' + try: + return get_docker_container_id.container_id + except AttributeError: + pass - if not os.path.exists(path): - return None + path = '/proc/self/cpuset' + container_id = None - with open(path) as cgroup_fd: - contents = cgroup_fd.read() + if os.path.exists(path): + # File content varies based on the environment: + # No Container: / + # Docker: /docker/c86f3732b5ba3d28bb83b6e14af767ab96abbc52de31313dcb1176a62d91a507 + # Azure Pipelines (Docker): /azpl_job/0f2edfed602dd6ec9f2e42c867f4d5ee640ebf4c058e6d3196d4393bb8fd0891 + # Podman: /../../../../../.. + with open(path) as cgroup_fd: + contents = cgroup_fd.read() - paths = [line.split(':')[2] for line in contents.splitlines()] - container_ids = set(path.split('/')[2] for path in paths if path.startswith('/docker/')) + cgroup_path, cgroup_name = os.path.split(contents.strip()) - if not container_ids: - return None + if cgroup_path in ('/docker', '/azpl_job'): + container_id = cgroup_name - if len(container_ids) == 1: - return container_ids.pop() + get_docker_container_id.container_id = container_id - raise ApplicationError('Found multiple container_id candidates: %s\n%s' % (sorted(container_ids), contents)) + if container_id: + display.info('Detected execution in Docker container: %s' % container_id, verbosity=1) + + return container_id def get_docker_container_ip(args, container_id): @@ -63,10 +102,65 @@ def get_docker_container_ip(args, container_id): :rtype: str """ results = docker_inspect(args, container_id) - ipaddress = results[0]['NetworkSettings']['IPAddress'] + network_settings = results[0]['NetworkSettings'] + networks = network_settings.get('Networks') + + if networks: + network_name = get_docker_preferred_network_name(args) + ipaddress = networks[network_name]['IPAddress'] + else: + # podman doesn't provide Networks, fall back to using IPAddress + ipaddress = network_settings['IPAddress'] + + if not ipaddress: + raise ApplicationError('Cannot retrieve IP address for container: %s' % container_id) + return ipaddress +def get_docker_network_name(args, container_id): # type: (EnvironmentConfig, str) -> str + """ + Return the network name of the specified container. + Raises an exception if zero or more than one network is found. + """ + networks = get_docker_networks(args, container_id) + + if not networks: + raise ApplicationError('No network found for Docker container: %s.' % container_id) + + if len(networks) > 1: + raise ApplicationError('Found multiple networks for Docker container %s instead of only one: %s' % (container_id, ', '.join(networks))) + + return networks[0] + + +def get_docker_preferred_network_name(args): # type: (EnvironmentConfig) -> str + """ + Return the preferred network name for use with Docker. The selection logic is: + - the network selected by the user with `--docker-network` + - the network of the currently running docker container (if any) + - the default docker network (returns None) + """ + network = None + + if args.docker_network: + network = args.docker_network + else: + current_container_id = get_docker_container_id() + + if current_container_id: + # Make sure any additional containers we launch use the same network as the current container we're running in. + # This is needed when ansible-test is running in a container that is not connected to Docker's default network. + network = get_docker_network_name(args, current_container_id) + + return network + + +def is_docker_user_defined_network(network): # type: (str) -> bool + """Return True if the network being used is a user-defined network.""" + return network and network != 'bridge' + + def get_docker_networks(args, container_id): """ :param args: EnvironmentConfig @@ -142,6 +236,13 @@ def docker_run(args, image, options, cmd=None): if not cmd: cmd = [] + network = get_docker_preferred_network_name(args) + + if is_docker_user_defined_network(network): + # Only when the network is not the default bridge network. + # Using this with the default bridge network results in an error when using --link: links are only supported for user-defined networks + options.extend(['--network', network]) + for _ in range(1, 3): try: return docker_command(args, ['run'] + options + [image] + cmd, capture=True) diff --git a/test/runner/lib/executor.py b/test/runner/lib/executor.py index 305ce64083..680963f7e2 100644 --- a/test/runner/lib/executor.py +++ b/test/runner/lib/executor.py @@ -68,6 +68,9 @@ from lib.docker_util import ( docker_rm, get_docker_container_id, get_docker_container_ip, + get_docker_hostname, + get_docker_preferred_network_name, + is_docker_user_defined_network, ) from lib.ansible_util import ( @@ -986,9 +989,7 @@ def start_httptester(args): container_id = get_docker_container_id() - if container_id: - display.info('Running in docker container: %s' % container_id, verbosity=1) - else: + if not container_id: for item in ports: item['localhost'] = get_available_port() @@ -1000,7 +1001,7 @@ def start_httptester(args): container_host = get_docker_container_ip(args, httptester_id) display.info('Found httptester container address: %s' % container_host, verbosity=1) else: - container_host = 'localhost' + container_host = get_docker_hostname() ssh_options = [] @@ -1024,6 +1025,13 @@ def run_httptester(args, ports=None): for localhost_port, container_port in ports.items(): options += ['-p', '%d:%d' % (localhost_port, container_port)] + network = get_docker_preferred_network_name(args) + + if is_docker_user_defined_network(network): + # network-scoped aliases are only supported for containers in user defined networks + for alias in HTTPTESTER_HOSTS: + options.extend(['--network-alias', alias]) + httptester_id, _ = docker_run(args, args.httptester, options=options) if args.explain: |