From ff80b64648d68fe7f687c5350b2ca34a3b33acaa Mon Sep 17 00:00:00 2001 From: Damien Goutte-Gattat Date: Wed, 7 Oct 2026 21:14:48 +0100 Subject: [PATCH 1/2] Add the Podman backend. Add another backend to run containers through Podman [1]. This is another backend that is very much similar to the Docker backend, in that the command to start the container process (`podman run`) is identical to the command one would use with Docker. Therefore, as for the Apple Container backend, this backend is reusing the logic from the Docker backend to build the command line. Still, even though calling the `odk_backend_docker_build_command()` function avoids duplicating most of the code, there is still a sizeable amount of almost "boilerplate" code that is duplicated between the Docker, Apple Container, and Podman backends. This is still fine for now, but one or two more backends like that and we should seriously consider refactoring the whole backend system to account for the fact that several backends are in fact almost identical. [1] https://podman.io/ --- Makefile.am | 1 + README.md | 29 ++++++---- configure.ac | 3 +- doc/odkrun.1.in | 5 ++ src/backend-podman.c | 132 +++++++++++++++++++++++++++++++++++++++++++ src/backend-podman.h | 52 +++++++++++++++++ src/odkrun.c | 14 ++++- 7 files changed, 221 insertions(+), 15 deletions(-) create mode 100644 src/backend-podman.c create mode 100644 src/backend-podman.h diff --git a/Makefile.am b/Makefile.am index 23781ed..509349e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,7 @@ odkrun_SOURCES = src/odkrun.c \ src/backend.h \ src/backend-docker.c src/backend-docker.h \ src/backend-singularity.c src/backend-singularity.h \ + src/backend-podman.c src/backend-podman.h \ src/backend-native.c src/backend-native.h \ src/backend-apple.c src/backend-apple.h \ src/owlapi.c src/owlapi.h src/owlapi-options.h \ diff --git a/README.md b/README.md index d1a7611..924980f 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ by the ODK workflows. Currently, four different backends are supported: Docker, Singularity, Apple Container, and “native” environments. -### Docker, Singularity, and Apple Container +### Docker, Singularity, Podman, and Apple Container Docker is the primary backend, and the most well supported. Unless configured otherwise at build time (option `--with-default-backend`), @@ -118,17 +118,22 @@ in an ephemeral container based on that image. The exact image used may be specified using the `--image` (`-i`) and `--tag` (`-t`) option; the default is `obolibrary/odkfull:latest`. -The Singularity and Apple Container backends rely on the same Docker -images, but used through the [Singularity container -platform](https://docs.sylabs.io/guides/latest/user-guide/#) or the -[Apple `container` tool](https://github.com/apple/container), -respectively. As its name may imply, the Apple Container backend is only -available on macOS. - -Use the `--singularity` (`-s`) option to select the Singularity backend, -and the `--apple` (`-a`) option to select the Apple Container backend. -The image to use may be selected using the same `-i` and `-t` options as -for the Docker backend. +Several other backends are available, that rely on the same Docker +images, but used through other containerization tools. The table below +lists the available backends along with the command-line options that +select them: + +| Backend | Option | +| ------- | ------ | +| [Singularity](https://docs.sylabs.io/guides/latest/user-guide/#) | `--singularity` (`-s`) | +| [Podman](https://podman.io/) | `--podman` (`-p`) | +| [Apple Container](https://github.com/apple/container) | `--apple` (`a`) | + +As its name may imply, the Apple Container backend is only available on +macOS. + +With all those backends, the image to use may be selected using the same +`-i` and `-t` options as for the Docker backend. ### Native backend diff --git a/configure.ac b/configure.ac index 25984c2..ccc336b 100644 --- a/configure.ac +++ b/configure.ac @@ -46,12 +46,13 @@ AC_DEFINE_UNQUOTED([ODK_EXECUTABLE], ["$with_odk_executable"], [Name or path of dnl Default backend AC_ARG_WITH([default-backend], [AS_HELP_STRING([--with-default-backend], - [Name of the backend to use by default. One of docker, singularity, apple, native, or none.])], + [Name of the backend to use by default. One of docker, singularity, podman, apple, native, or none.])], [], [with_default_backend=docker]) AS_CASE([$with_default_backend], [docker], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_docker_init], [Docker backend])], [singularity], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_singularity_init], [Singularity backend])], + [podman], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_podman_init], [Podman backend])], [apple], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_apple_init], [Apple Container backend])], [native], [AC_DEFINE([ODK_DEFAULT_BACKEND], [odk_backend_native_init], [Native backend])], [none], [AC_DEFINE([ODK_DEFAULT_BACKEND], [NULL], [No default backend])], diff --git a/doc/odkrun.1.in b/doc/odkrun.1.in index db18ba2..319827a 100644 --- a/doc/odkrun.1.in +++ b/doc/odkrun.1.in @@ -15,6 +15,7 @@ odkrun - ODK Runner tool .RB [ -l | --lite ] .RB [ -D | --docker ] .RB [ -s | --singulary ] +.RB [ -p | --podman ] .RB [ -a | --apple ] .RB [ -n | --native ] .RB [ --root ] @@ -71,6 +72,10 @@ backend, unless specified otherwise at configure time. Run the container with Singularity rather than Docker. This is experimental but should mostly work. .TP +.BR -p ", " --podman +Run the container with Podman rather than Docker. This is +experimental but should mostly work. +.TP .BR -a ", " --apple Run the container with Apple Container rather than Docker. This is only available on macOS. This is experimental but diff --git a/src/backend-podman.c b/src/backend-podman.c new file mode 100644 index 0000000..bdf3fea --- /dev/null +++ b/src/backend-podman.c @@ -0,0 +1,132 @@ +/* + * ODK Runner + * Copyright (C) 2026 Damien Goutte-Gattat + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "backend-podman.h" + +#include +#include +#include + +#if defined(ODK_RUNNER_LINUX) +#include /* for getuid/getgid */ +#endif + +#include "util.h" +#include "backend-docker.h" + +#define PODMAN_SSH_SOCKET "/run/host-services/ssh-auth.sock" + +static int +prepare(odk_backend_t *backend, odk_run_config_t *cfg) +{ + int ret = 0; + char *ssh_socket; + + if ( (cfg->flags & ODK_FLAG_RUNASROOT) == 0 ) { +#if defined(ODK_RUNNER_LINUX) + char *user_id = mr_sprintf(NULL, "%u", getuid()); + char *group_id = mr_sprintf(NULL, "%u", getgid()); +#else + char *user_id = "1000"; + char *group_id = "1000"; +#endif + + odk_add_env_var(cfg, "ODK_USER_ID", user_id, 0); + odk_add_env_var(cfg, "ODK_GROUP_ID", group_id, 0); + } + + if ( (ssh_socket = getenv("SSH_AUTH_SOCK")) && + file_exists(ssh_socket) == 0 ) { + odk_add_env_var(cfg, "SSH_AUTH_SOCK", PODMAN_SSH_SOCKET, 0); + ret = odk_add_binding(cfg, ssh_socket, PODMAN_SSH_SOCKET, 0); + } + + return ret; +} + +static int +run(odk_backend_t *backend, odk_run_config_t *cfg, char **command) +{ + int rc; + char **argv; + mem_registry_t mr = { 0 }; + + (void) backend; + + argv = odk_backend_docker_build_command(&mr, cfg, command); + argv[0] = "podman"; + rc = spawn_process(argv); + mr_free(&mr); + + return rc; +} + +static int +close_backend(odk_backend_t *backend) +{ + (void) backend; + + return 0; +} + +static int +get_total_memory(odk_backend_info_t *info) +{ + FILE *p; + int ret = -1; + + if ( (p = popen("podman info --format={{.Host.MemTotal}}", "r")) != NULL ) { + if ( fscanf(p, "%lu", &(info->total_memory)) == 1 ) + ret = 0; + else + errno = ESRCH; + pclose(p); + } + + return ret; +} + +int +odk_backend_podman_init(odk_backend_t *backend) +{ + int ret; + + backend->prepare = prepare; + backend->run = run; + backend->close = close_backend; + + ret = get_total_memory(&(backend->info)); + + return ret; +} diff --git a/src/backend-podman.h b/src/backend-podman.h new file mode 100644 index 0000000..e2b12e3 --- /dev/null +++ b/src/backend-podman.h @@ -0,0 +1,52 @@ +/* + * ODK Runner + * Copyright (C) 2026 Damien Goutte-Gattat + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ICP20261007_BACKEND_PODMAN_H +#define ICP20261007_BACKEND_PODMAN_H + +#include + +#include "backend.h" +#include "procutil.h" + +#ifdef __cpluscplus +extern "C" { +#endif + +int +odk_backend_podman_init(odk_backend_t *); + +#define odk_backend_podman_available() check_process("podman", "--version") + +#ifdef __cpluscplus +} +#endif + +#endif /* !ICP20261007_BACKEND_PODMAN_H */ diff --git a/src/odkrun.c b/src/odkrun.c index ff19043..15b2f79 100644 --- a/src/odkrun.c +++ b/src/odkrun.c @@ -47,8 +47,9 @@ #include "util.h" #include "backend-docker.h" #include "backend-singularity.h" -#include "backend-native.h" +#include "backend-podman.h" #include "backend-apple.h" +#include "backend-native.h" #include "oaklib.h" #include "owlapi.h" #include "runconf.h" @@ -85,6 +86,8 @@ Start a ODK container.\n"); -D, --docker Run the container with Docker. This is normally\n\ the default.\n\ -s, --singularity Run the container with Singularity rather\n\ + than Docker (experimental).\n\ + -p, --podman Run the container with Podman rather than\n\ than Docker (experimental)."); #if defined(ODK_RUNNER_MACOS) puts("\ @@ -462,6 +465,7 @@ main(int argc, char **argv) { "lite", 0, NULL, 'l' }, { "docker", 0, NULL, 'D' }, { "singularity", 0, NULL, 's' }, + { "podman", 0, NULL, 'p' }, #if defined (ODK_RUNNER_MACOS) { "apple", 0, NULL, 'a' }, #endif @@ -484,7 +488,7 @@ main(int argc, char **argv) odk_init_config(&cfg); - while ( (c = getopt_long(argc, argv, "+hvdi:t:lse:k:Km:D" BACKEND_OPTS, + while ( (c = getopt_long(argc, argv, "+hvdi:t:lse:k:Km:Dp" BACKEND_OPTS, options, NULL)) != -1 ) { switch ( c ) { case 'h': @@ -524,6 +528,10 @@ main(int argc, char **argv) backend_init = odk_backend_singularity_init; break; + case 'p': + backend_init = odk_backend_podman_init; + break; + #if !defined(ODK_RUNNER_WINDOWS) case 'n': backend_init = odk_backend_native_init; @@ -597,6 +605,8 @@ main(int argc, char **argv) backend_init = odk_backend_docker_init; else if ( odk_backend_singularity_available() ) backend_init = odk_backend_singularity_init; + else if ( odk_backend_podman_available() ) + backend_init = odk_backend_podman_init; else if ( odk_backend_apple_available() ) backend_init = odk_backend_apple_init; else if ( odk_backend_native_available() ) From e468c756c96b2c63470fc8a22a8b3a1a05794ed4 Mon Sep 17 00:00:00 2001 From: Damien Goutte-Gattat Date: Thu, 8 Oct 2026 10:53:55 +0100 Subject: [PATCH 2/2] podman: Remove socket forwarding. It seems that Podman does not support binding a socket from the host into the container. I have no time to investigate that for now, so we'll just skip SSH socket forwarding on Podman for the time being. (That is not a big loss. In fact, I am not sure anyone except me has ever used the SSH socket forwarding feature of odkrun.) --- src/backend-podman.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/backend-podman.c b/src/backend-podman.c index bdf3fea..de6a664 100644 --- a/src/backend-podman.c +++ b/src/backend-podman.c @@ -42,16 +42,12 @@ #include /* for getuid/getgid */ #endif -#include "util.h" #include "backend-docker.h" -#define PODMAN_SSH_SOCKET "/run/host-services/ssh-auth.sock" - static int prepare(odk_backend_t *backend, odk_run_config_t *cfg) { - int ret = 0; - char *ssh_socket; + (void) backend; if ( (cfg->flags & ODK_FLAG_RUNASROOT) == 0 ) { #if defined(ODK_RUNNER_LINUX) @@ -66,13 +62,7 @@ prepare(odk_backend_t *backend, odk_run_config_t *cfg) odk_add_env_var(cfg, "ODK_GROUP_ID", group_id, 0); } - if ( (ssh_socket = getenv("SSH_AUTH_SOCK")) && - file_exists(ssh_socket) == 0 ) { - odk_add_env_var(cfg, "SSH_AUTH_SOCK", PODMAN_SSH_SOCKET, 0); - ret = odk_add_binding(cfg, ssh_socket, PODMAN_SSH_SOCKET, 0); - } - - return ret; + return 0; } static int