summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Martz <matt@sivel.net>2022-03-09 15:59:29 -0600
committerGitHub <noreply@github.com>2022-03-09 15:59:29 -0600
commit7cb581ed2cb1d4591d094df37a40c9155ea446da (patch)
tree67899ac51fd64f64e44a09b746995743727ba695
parent1ba3ead0a02d982563a5108f837eaadb11bd6018 (diff)
downloadansible-7cb581ed2cb1d4591d094df37a40c9155ea446da.tar.gz
Support podman-remote in ansible-test (#75753)
-rw-r--r--changelogs/fragments/ansible-test-podman-remote.yaml3
-rw-r--r--test/lib/ansible_test/_internal/containers.py10
-rw-r--r--test/lib/ansible_test/_internal/docker_util.py77
-rw-r--r--test/lib/ansible_test/_internal/util.py13
4 files changed, 84 insertions, 19 deletions
diff --git a/changelogs/fragments/ansible-test-podman-remote.yaml b/changelogs/fragments/ansible-test-podman-remote.yaml
new file mode 100644
index 0000000000..7eb38e110e
--- /dev/null
+++ b/changelogs/fragments/ansible-test-podman-remote.yaml
@@ -0,0 +1,3 @@
+minor_changes:
+- ansible-test - Add support for running container tests with ``podman remote``
+ (https://github.com/ansible/ansible/pull/75753)
diff --git a/test/lib/ansible_test/_internal/containers.py b/test/lib/ansible_test/_internal/containers.py
index 5f84890010..5e29c6ac05 100644
--- a/test/lib/ansible_test/_internal/containers.py
+++ b/test/lib/ansible_test/_internal/containers.py
@@ -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()),
diff --git a/test/lib/ansible_test/_internal/docker_util.py b/test/lib/ansible_test/_internal/docker_util.py
index 0934b892c0..1e10f5ff58 100644
--- a/test/lib/ansible_test/_internal/docker_util.py
+++ b/test/lib/ansible_test/_internal/docker_util.py
@@ -122,6 +122,75 @@ def get_docker_hostname(): # type: () -> str
@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."""
path = '/proc/self/cpuset'
@@ -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
diff --git a/test/lib/ansible_test/_internal/util.py b/test/lib/ansible_test/_internal/util.py
index 8d1b7eb498..0ad78882de 100644
--- a/test/lib/ansible_test/_internal/util.py
+++ b/test/lib/ansible_test/_internal/util.py
@@ -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