Support podman-remote in ansible-test (#75753)
This commit is contained in:
3
changelogs/fragments/ansible-test-podman-remote.yaml
Normal file
3
changelogs/fragments/ansible-test-podman-remote.yaml
Normal file
@ -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,
|
||||
SubprocessError,
|
||||
display,
|
||||
get_host_ip,
|
||||
sanitize_host_name,
|
||||
)
|
||||
|
||||
@ -43,6 +42,7 @@ from .docker_util import (
|
||||
docker_start,
|
||||
get_docker_container_id,
|
||||
get_docker_host_ip,
|
||||
get_podman_host_ip,
|
||||
require_docker,
|
||||
)
|
||||
|
||||
@ -350,8 +350,12 @@ def create_container_database(args): # type: (EnvironmentConfig) -> ContainerDa
|
||||
|
||||
for name, container in support_containers.items():
|
||||
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(
|
||||
host_ip=get_docker_host_ip(),
|
||||
host_ip=host_ip_func(),
|
||||
names=container.aliases,
|
||||
ports=None,
|
||||
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':
|
||||
# published ports for rootless podman containers should be accessible from the host's IP
|
||||
container_access = ContainerAccess(
|
||||
host_ip=get_host_ip(),
|
||||
host_ip=get_podman_host_ip(),
|
||||
names=container.aliases,
|
||||
ports=None,
|
||||
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
|
||||
|
||||
|
||||
@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
|
||||
def get_docker_container_id(): # type: () -> t.Optional[str]
|
||||
"""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]]
|
||||
"""Run the specified docker command."""
|
||||
env = docker_environment()
|
||||
command = require_docker().command
|
||||
return run_command(args, [command] + cmd, env=env, capture=capture, stdin=stdin, stdout=stdout, always=always, data=data)
|
||||
command = [require_docker().command]
|
||||
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]
|
||||
"""Return a dictionary of docker related environment variables found in the current 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
|
||||
|
||||
@ -11,7 +11,6 @@ import pkgutil
|
||||
import random
|
||||
import re
|
||||
import shutil
|
||||
import socket
|
||||
import stat
|
||||
import string
|
||||
import subprocess
|
||||
@ -782,18 +781,6 @@ def sanitize_host_name(name):
|
||||
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]]
|
||||
"""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
|
||||
|
||||
Reference in New Issue
Block a user