tests/docker: add podman support
-----BEGIN PGP SIGNATURE----- iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAl1enMscHG1hcmNhbmRy ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5QpyEACGNi/hlJz/tqhM2jqu fn1hMwI2qi5/G3WSlF9MRKt6ZrDe/ZnjyHM7IsZ+PywmOnKpSuaK1vuChY4cFGGy q+PZxir2C+KEdde7acs/XyNaE60B8bNBWfM1v/vC0toZC9YY4Pw+Pu3w1SV7hheY 5hc6OSg9NsJnhiZGaM+DIfC0MazU8j43qiEVmv/beYmX/E3yBo4MKkoH++Rkvgrz VkPcycNXowT8XhzvqTMlHnwUtjORrCqjGolCR248cx16h7e5vIhDxNBw2Yap6yt2 KWpeaqchB4b1hhKQBZNbFyQyZaBEUqvCp7W3A3/j/9wW+vXjfFdgH+bDWF50B268 H7frAJlIEWjUaX4ySDJikemxYP6yC4zvkF59+78fYwDHx4OAL8Ry7vTNT/ZeAZKr 8erI1qK8MELNY0nVFCROV/PpLrwDdPycQqCpVDb/QBfst1gYIvyeviYeHaI92oUU O+TDPoZPBhOxGEZ7SVEQq20EZIw5V7vZZlb2BG+mBonHmIFK9e7oELCWCbkPXIAx SKDSWg327+bKaKw0lFgMels7qxxcewrZ/zI2Fk18f7Nlp+tcNUh9w9WhWp/GGvSO z5/Y5Rt5I4PYuvq9NBy9uoxr0a7F7TVBMKm8DRz3CQrW9tD9S+07xNkLNRuKQE1q sHl8b9ZqSLnWDV6Rxkb9ybmCbQ== =AbsR -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/elmarco/tags/podman-pull-request' into staging tests/docker: add podman support # gpg: Signature made Thu 22 Aug 2019 14:46:51 BST # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: issuer "marcandre.lureau@redhat.com" # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * remotes/elmarco/tags/podman-pull-request: test: skip tests if socket_check_protocol_support() failed test-char: skip tcp tests if ipv4 check failed tests: specify the address family when checking bind tests/docker: add podman support docker.py: add podman support docker.py: add --run-as-current-user Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
61146e9cb4
2
Makefile
2
Makefile
@ -1157,7 +1157,7 @@ endif
|
||||
@echo ''
|
||||
@echo 'Test targets:'
|
||||
@echo ' check - Run all tests (check-help for details)'
|
||||
@echo ' docker - Help about targets running tests inside Docker containers'
|
||||
@echo ' docker - Help about targets running tests inside containers'
|
||||
@echo ' vm-help - Help about targets running tests inside VM'
|
||||
@echo ''
|
||||
@echo 'Documentation targets:'
|
||||
|
@ -525,7 +525,7 @@ tests/check-qlit$(EXESUF): tests/check-qlit.o $(test-util-obj-y)
|
||||
tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y)
|
||||
tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
|
||||
|
||||
tests/test-char$(EXESUF): tests/test-char.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y) $(chardev-obj-y)
|
||||
tests/test-char$(EXESUF): tests/test-char.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y) $(chardev-obj-y) tests/socket-helpers.o
|
||||
tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
|
||||
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
|
||||
tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
|
||||
|
@ -17,7 +17,9 @@ DOCKER_TESTS := $(notdir $(shell \
|
||||
|
||||
DOCKER_TOOLS := travis
|
||||
|
||||
DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py
|
||||
ENGINE := auto
|
||||
|
||||
DOCKER_SCRIPT=$(SRC_PATH)/tests/docker/docker.py --engine $(ENGINE)
|
||||
|
||||
TESTS ?= %
|
||||
IMAGES ?= %
|
||||
@ -146,7 +148,7 @@ $(foreach i,$(filter-out $(DOCKER_PARTIAL_IMAGES),$(DOCKER_IMAGES) $(DOCKER_DEPR
|
||||
)
|
||||
|
||||
docker:
|
||||
@echo 'Build QEMU and run tests inside Docker containers'
|
||||
@echo 'Build QEMU and run tests inside Docker or Podman containers'
|
||||
@echo
|
||||
@echo 'Available targets:'
|
||||
@echo
|
||||
@ -193,6 +195,8 @@ endif
|
||||
@echo ' EXECUTABLE=<path> Include executable in image.'
|
||||
@echo ' EXTRA_FILES="<path> [... <path>]"'
|
||||
@echo ' Include extra files in image.'
|
||||
@echo ' ENGINE=auto/docker/podman'
|
||||
@echo ' Specify which container engine to run.'
|
||||
|
||||
# This rule if for directly running against an arbitrary docker target.
|
||||
# It is called by the expanded docker targets (e.g. make
|
||||
@ -212,7 +216,7 @@ docker-run: docker-qemu-src
|
||||
" COPYING $(EXECUTABLE) to $(IMAGE)"))
|
||||
$(call quiet-command, \
|
||||
$(DOCKER_SCRIPT) run \
|
||||
$(if $(NOUSER),,-u $(shell id -u)) \
|
||||
$(if $(NOUSER),,--run-as-current-user) \
|
||||
--security-opt seccomp=unconfined \
|
||||
$(if $V,,--rm) \
|
||||
$(if $(DEBUG),-ti,) \
|
||||
|
@ -20,6 +20,7 @@ import hashlib
|
||||
import atexit
|
||||
import uuid
|
||||
import argparse
|
||||
import enum
|
||||
import tempfile
|
||||
import re
|
||||
import signal
|
||||
@ -38,6 +39,26 @@ FILTERED_ENV_NAMES = ['ftp_proxy', 'http_proxy', 'https_proxy']
|
||||
|
||||
DEVNULL = open(os.devnull, 'wb')
|
||||
|
||||
class EngineEnum(enum.IntEnum):
|
||||
AUTO = 1
|
||||
DOCKER = 2
|
||||
PODMAN = 3
|
||||
|
||||
def __str__(self):
|
||||
return self.name.lower()
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
@staticmethod
|
||||
def argparse(s):
|
||||
try:
|
||||
return EngineEnum[s.upper()]
|
||||
except KeyError:
|
||||
return s
|
||||
|
||||
|
||||
USE_ENGINE = EngineEnum.AUTO
|
||||
|
||||
def _text_checksum(text):
|
||||
"""Calculate a digest string unique to the text content"""
|
||||
@ -48,9 +69,14 @@ def _file_checksum(filename):
|
||||
return _text_checksum(open(filename, 'rb').read())
|
||||
|
||||
|
||||
def _guess_docker_command():
|
||||
""" Guess a working docker command or raise exception if not found"""
|
||||
commands = [["docker"], ["sudo", "-n", "docker"]]
|
||||
def _guess_engine_command():
|
||||
""" Guess a working engine command or raise exception if not found"""
|
||||
commands = []
|
||||
|
||||
if USE_ENGINE in [EngineEnum.AUTO, EngineEnum.PODMAN]:
|
||||
commands += [["podman"]]
|
||||
if USE_ENGINE in [EngineEnum.AUTO, EngineEnum.DOCKER]:
|
||||
commands += [["docker"], ["sudo", "-n", "docker"]]
|
||||
for cmd in commands:
|
||||
try:
|
||||
# docker version will return the client details in stdout
|
||||
@ -61,7 +87,7 @@ def _guess_docker_command():
|
||||
except OSError:
|
||||
pass
|
||||
commands_txt = "\n".join([" " + " ".join(x) for x in commands])
|
||||
raise Exception("Cannot find working docker command. Tried:\n%s" %
|
||||
raise Exception("Cannot find working engine command. Tried:\n%s" %
|
||||
commands_txt)
|
||||
|
||||
|
||||
@ -190,7 +216,7 @@ def _dockerfile_preprocess(df):
|
||||
class Docker(object):
|
||||
""" Running Docker commands """
|
||||
def __init__(self):
|
||||
self._command = _guess_docker_command()
|
||||
self._command = _guess_engine_command()
|
||||
self._instances = []
|
||||
atexit.register(self._kill_instances)
|
||||
signal.signal(signal.SIGTERM, self._kill_instances)
|
||||
@ -333,8 +359,18 @@ class RunCommand(SubCommand):
|
||||
def args(self, parser):
|
||||
parser.add_argument("--keep", action="store_true",
|
||||
help="Don't remove image when command completes")
|
||||
parser.add_argument("--run-as-current-user", action="store_true",
|
||||
help="Run container using the current user's uid")
|
||||
|
||||
def run(self, args, argv):
|
||||
if args.run_as_current_user:
|
||||
uid = os.getuid()
|
||||
argv = [ "-u", str(uid) ] + argv
|
||||
docker = Docker()
|
||||
if docker._command[0] == "podman":
|
||||
argv = [ "--uidmap", "%d:0:1" % uid,
|
||||
"--uidmap", "0:1:%d" % uid,
|
||||
"--uidmap", "%d:%d:64536" % (uid + 1, uid + 1)] + argv
|
||||
return Docker().run(argv, args.keep, quiet=args.quiet)
|
||||
|
||||
|
||||
@ -502,6 +538,8 @@ class ProbeCommand(SubCommand):
|
||||
print("yes")
|
||||
elif docker._command[0] == "sudo":
|
||||
print("sudo")
|
||||
elif docker._command[0] == "podman":
|
||||
print("podman")
|
||||
except Exception:
|
||||
print("no")
|
||||
|
||||
@ -597,9 +635,13 @@ class CheckCommand(SubCommand):
|
||||
|
||||
|
||||
def main():
|
||||
global USE_ENGINE
|
||||
|
||||
parser = argparse.ArgumentParser(description="A Docker helper",
|
||||
usage="%s <subcommand> ..." %
|
||||
os.path.basename(sys.argv[0]))
|
||||
parser.add_argument("--engine", type=EngineEnum.argparse, choices=list(EngineEnum),
|
||||
help="specify which container engine to use")
|
||||
subparsers = parser.add_subparsers(title="subcommands", help=None)
|
||||
for cls in SubCommand.__subclasses__():
|
||||
cmd = cls()
|
||||
@ -608,6 +650,7 @@ def main():
|
||||
cmd.args(subp)
|
||||
subp.set_defaults(cmdobj=cmd)
|
||||
args, argv = parser.parse_known_args()
|
||||
USE_ENGINE = args.engine
|
||||
return args.cmdobj.run(args, argv)
|
||||
|
||||
|
||||
|
@ -30,7 +30,16 @@
|
||||
# define EAI_ADDRFAMILY 0
|
||||
#endif
|
||||
|
||||
int socket_can_bind_connect(const char *hostname)
|
||||
/*
|
||||
* @hostname: a DNS name or numeric IP address
|
||||
*
|
||||
* Check whether it is possible to bind & connect to ports
|
||||
* on the DNS name or IP address @hostname. If an IP address
|
||||
* is used, it must not be a wildcard address.
|
||||
*
|
||||
* Returns 0 on success, -1 on error with errno set
|
||||
*/
|
||||
static int socket_can_bind_connect(const char *hostname, int family)
|
||||
{
|
||||
int lfd = -1, cfd = -1, afd = -1;
|
||||
struct addrinfo ai, *res = NULL;
|
||||
@ -44,7 +53,7 @@ int socket_can_bind_connect(const char *hostname)
|
||||
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
|
||||
ai.ai_family = AF_UNSPEC;
|
||||
ai.ai_family = family;
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
|
||||
/* lookup */
|
||||
@ -129,7 +138,7 @@ int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6)
|
||||
{
|
||||
*has_ipv4 = *has_ipv6 = false;
|
||||
|
||||
if (socket_can_bind_connect("127.0.0.1") < 0) {
|
||||
if (socket_can_bind_connect("127.0.0.1", PF_INET) < 0) {
|
||||
if (errno != EADDRNOTAVAIL) {
|
||||
return -1;
|
||||
}
|
||||
@ -137,7 +146,7 @@ int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6)
|
||||
*has_ipv4 = true;
|
||||
}
|
||||
|
||||
if (socket_can_bind_connect("::1") < 0) {
|
||||
if (socket_can_bind_connect("::1", PF_INET6) < 0) {
|
||||
if (errno != EADDRNOTAVAIL) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -20,17 +20,6 @@
|
||||
#ifndef TESTS_SOCKET_HELPERS_H
|
||||
#define TESTS_SOCKET_HELPERS_H
|
||||
|
||||
/*
|
||||
* @hostname: a DNS name or numeric IP address
|
||||
*
|
||||
* Check whether it is possible to bind & connect to ports
|
||||
* on the DNS name or IP address @hostname. If an IP address
|
||||
* is used, it must not be a wildcard address.
|
||||
*
|
||||
* Returns 0 on success, -1 on error with errno set
|
||||
*/
|
||||
int socket_can_bind_connect(const char *hostname);
|
||||
|
||||
/*
|
||||
* @has_ipv4: set to true on return if IPv4 is available
|
||||
* @has_ipv6: set to true on return if IPv6 is available
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "io/channel-socket.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/qapi-visit-sockets.h"
|
||||
#include "socket-helpers.h"
|
||||
|
||||
static bool quit;
|
||||
|
||||
@ -1356,11 +1357,18 @@ static void char_hotswap_test(void)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool has_ipv4, has_ipv6;
|
||||
|
||||
qemu_init_main_loop(&error_abort);
|
||||
socket_init();
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
|
||||
g_printerr("socket_check_protocol_support() failed\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
module_call_init(MODULE_INIT_QOM);
|
||||
qemu_add_opts(&qemu_chardev_opts);
|
||||
|
||||
@ -1438,10 +1446,12 @@ int main(int argc, char **argv)
|
||||
g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
|
||||
&client6 ##name, char_socket_client_test)
|
||||
|
||||
SOCKET_SERVER_TEST(tcp, &tcpaddr);
|
||||
SOCKET_CLIENT_TEST(tcp, &tcpaddr);
|
||||
g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr,
|
||||
char_socket_server_two_clients_test);
|
||||
if (has_ipv4) {
|
||||
SOCKET_SERVER_TEST(tcp, &tcpaddr);
|
||||
SOCKET_CLIENT_TEST(tcp, &tcpaddr);
|
||||
g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr,
|
||||
char_socket_server_two_clients_test);
|
||||
}
|
||||
#ifndef WIN32
|
||||
SOCKET_SERVER_TEST(unix, &unixaddr);
|
||||
SOCKET_CLIENT_TEST(unix, &unixaddr);
|
||||
@ -1456,5 +1466,6 @@ int main(int argc, char **argv)
|
||||
g_test_add_func("/char/hotswap", char_hotswap_test);
|
||||
g_test_add_func("/char/websocket", char_websock_test);
|
||||
|
||||
end:
|
||||
return g_test_run();
|
||||
}
|
||||
|
@ -566,7 +566,8 @@ int main(int argc, char **argv)
|
||||
* with either IPv4 or IPv6 disabled.
|
||||
*/
|
||||
if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
|
||||
return 1;
|
||||
g_printerr("socket_check_protocol_support() failed\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (has_ipv4) {
|
||||
@ -595,5 +596,6 @@ int main(int argc, char **argv)
|
||||
test_io_channel_unix_listen_cleanup);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
end:
|
||||
return g_test_run();
|
||||
}
|
||||
|
@ -242,7 +242,8 @@ int main(int argc, char **argv)
|
||||
* with either IPv4 or IPv6 disabled.
|
||||
*/
|
||||
if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
|
||||
return 1;
|
||||
g_printerr("socket_check_protocol_support() failed\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (has_ipv4) {
|
||||
@ -264,5 +265,6 @@ int main(int argc, char **argv)
|
||||
test_socket_fd_pass_num_nocli);
|
||||
}
|
||||
|
||||
end:
|
||||
return g_test_run();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user