Support podman-remote in ansible-test (#75753)

pull/77254/head
Matt Martz 3 years ago committed by GitHub
parent 1ba3ead0a0
commit 7cb581ed2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,3 @@
minor_changes:
- ansible-test - Add support for running container tests with ``podman remote``
(https://github.com/ansible/ansible/pull/75753)

@ -15,7 +15,6 @@ from .util import (
ApplicationError, ApplicationError,
SubprocessError, SubprocessError,
display, display,
get_host_ip,
sanitize_host_name, sanitize_host_name,
) )
@ -43,6 +42,7 @@ from .docker_util import (
docker_start, docker_start,
get_docker_container_id, get_docker_container_id,
get_docker_host_ip, get_docker_host_ip,
get_podman_host_ip,
require_docker, require_docker,
) )
@ -350,8 +350,12 @@ def create_container_database(args): # type: (EnvironmentConfig) -> ContainerDa
for name, container in support_containers.items(): for name, container in support_containers.items():
if container.details.published_ports: if container.details.published_ports:
if require_docker().command == 'podman':
host_ip_func = get_podman_host_ip
else:
host_ip_func = get_docker_host_ip
published_access = ContainerAccess( published_access = ContainerAccess(
host_ip=get_docker_host_ip(), host_ip=host_ip_func(),
names=container.aliases, names=container.aliases,
ports=None, ports=None,
forwards=dict((port, published_port) for port, published_port in container.details.published_ports.items()), forwards=dict((port, published_port) for port, published_port in container.details.published_ports.items()),
@ -370,7 +374,7 @@ def create_container_database(args): # type: (EnvironmentConfig) -> ContainerDa
elif require_docker().command == 'podman': elif require_docker().command == 'podman':
# published ports for rootless podman containers should be accessible from the host's IP # published ports for rootless podman containers should be accessible from the host's IP
container_access = ContainerAccess( container_access = ContainerAccess(
host_ip=get_host_ip(), host_ip=get_podman_host_ip(),
names=container.aliases, names=container.aliases,
ports=None, ports=None,
forwards=dict((port, published_port) for port, published_port in container.details.published_ports.items()), forwards=dict((port, published_port) for port, published_port in container.details.published_ports.items()),

@ -121,6 +121,75 @@ def get_docker_hostname(): # type: () -> str
return hostname return hostname
@cache
def get_podman_host_ip(): # type: () -> str
"""Return the IP of the Podman host."""
podman_host_ip = socket.gethostbyname(get_podman_hostname())
display.info('Detected Podman host IP: %s' % podman_host_ip, verbosity=1)
return podman_host_ip
@cache
def get_podman_default_hostname(): # type: () -> str
"""Return the default hostname of the Podman service.
--format was added in podman 3.3.0, this functionality depends on it's availability
"""
try:
stdout = raw_command(['podman', 'system', 'connection', 'list', '--format=json'], capture=True)[0]
except SubprocessError:
stdout = '[]'
connections = json.loads(stdout)
for connection in connections:
# A trailing indicates the default
if connection['Name'][-1] == '*':
hostname = connection['URI']
break
else:
hostname = None
return hostname
@cache
def _get_podman_remote(): # type: () -> t.Optional[str]
# URL value resolution precedence:
# - command line value
# - environment variable CONTAINER_HOST
# - containers.conf
# - unix://run/podman/podman.sock
hostname = None
podman_host = os.environ.get('CONTAINER_HOST')
if not podman_host:
podman_host = get_podman_default_hostname()
if podman_host and podman_host.startswith('ssh://'):
try:
hostname = urllib.parse.urlparse(podman_host).hostname
except ValueError:
display.warning('Could not parse podman URI "%s"' % podman_host)
else:
display.info('Detected Podman remote: %s' % hostname, verbosity=1)
return hostname
@cache
def get_podman_hostname(): # type: () -> str
"""Return the hostname of the Podman service."""
hostname = _get_podman_remote()
if not hostname:
hostname = 'localhost'
display.info('Assuming Podman is available on localhost.', verbosity=1)
return hostname
@cache @cache
def get_docker_container_id(): # type: () -> t.Optional[str] def get_docker_container_id(): # type: () -> t.Optional[str]
"""Return the current container ID if running in a container, otherwise return None.""" """Return the current container ID if running in a container, otherwise return None."""
@ -478,12 +547,14 @@ def docker_command(
): # type: (...) -> t.Tuple[t.Optional[str], t.Optional[str]] ): # type: (...) -> t.Tuple[t.Optional[str], t.Optional[str]]
"""Run the specified docker command.""" """Run the specified docker command."""
env = docker_environment() env = docker_environment()
command = require_docker().command command = [require_docker().command]
return run_command(args, [command] + cmd, env=env, capture=capture, stdin=stdin, stdout=stdout, always=always, data=data) if command[0] == 'podman' and _get_podman_remote():
command.append('--remote')
return run_command(args, command + cmd, env=env, capture=capture, stdin=stdin, stdout=stdout, always=always, data=data)
def docker_environment(): # type: () -> t.Dict[str, str] def docker_environment(): # type: () -> t.Dict[str, str]
"""Return a dictionary of docker related environment variables found in the current environment.""" """Return a dictionary of docker related environment variables found in the current environment."""
env = common_environment() env = common_environment()
env.update(dict((key, os.environ[key]) for key in os.environ if key.startswith('DOCKER_'))) env.update(dict((key, os.environ[key]) for key in os.environ if key.startswith('DOCKER_') or key.startswith('CONTAINER_')))
return env return env

@ -11,7 +11,6 @@ import pkgutil
import random import random
import re import re
import shutil import shutil
import socket
import stat import stat
import string import string
import subprocess import subprocess
@ -782,18 +781,6 @@ def sanitize_host_name(name):
return re.sub('[^A-Za-z0-9]+', '-', name)[:63].strip('-') return re.sub('[^A-Za-z0-9]+', '-', name)[:63].strip('-')
@cache
def get_host_ip():
"""Return the host's IP address."""
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.connect(('10.255.255.255', 22))
host_ip = get_host_ip.ip = sock.getsockname()[0]
display.info('Detected host IP: %s' % host_ip, verbosity=1)
return host_ip
def get_generic_type(base_type, generic_base_type): # type: (t.Type, t.Type[TType]) -> t.Optional[t.Type[TType]] def get_generic_type(base_type, generic_base_type): # type: (t.Type, t.Type[TType]) -> t.Optional[t.Type[TType]]
"""Return the generic type arg derived from the generic_base_type type that is associated with the base_type type, if any, otherwise return None.""" """Return the generic type arg derived from the generic_base_type type that is associated with the base_type type, if any, otherwise return None."""
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences

Loading…
Cancel
Save