From 6119c37c0f4d0c286de12db2e880f70ea2f8cf2e Mon Sep 17 00:00:00 2001 From: Goffi Date: Sun, 19 Jul 2026 15:04:09 +0200 Subject: [PATCH] plugin app manager docker: add support for Podman: Podman can be used as a drop-in replacement for Docker, and it doesn't need root permissions. The plugin now has a settings to use Podman, and use `auto` by default which will choose the first found on the device (Podman is tested first). --- .../plugin_app_manager_docker/__init__.py | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/libervia/backend/plugins/plugin_app_manager_docker/__init__.py b/libervia/backend/plugins/plugin_app_manager_docker/__init__.py index e241068f..3e83415b 100644 --- a/libervia/backend/plugins/plugin_app_manager_docker/__init__.py +++ b/libervia/backend/plugins/plugin_app_manager_docker/__init__.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# SàT plugin to manage Docker +# Libervia plugin to manage container-based applications # Copyright (C) 2009-2026 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify @@ -24,35 +24,59 @@ from libervia.backend.core import exceptions from libervia.backend.core.log import getLogger from libervia.backend.plugins.plugin_misc_app_manager.models import AppManagerBackend from libervia.backend.tools.common import async_process +from libervia.backend.tools.config import PluginSettings log = getLogger(__name__) PLUGIN_INFO = { - C.PI_NAME: "Docker Applications Manager", - C.PI_IMPORT_NAME: "APP_MANAGER_DOCKER", + C.PI_NAME: "Container Applications Manager", + C.PI_IMPORT_NAME: "APP_MANAGER_CONTAINER", C.PI_TYPE: C.PLUG_TYPE_MISC, C.PI_MODES: C.PLUG_MODE_BOTH, C.PI_DEPENDENCIES: ["APP_MANAGER"], C.PI_MAIN: "AppManagerDocker", C.PI_HANDLER: "no", - C.PI_DESCRIPTION: _("""Applications Manager for Docker"""), + C.PI_DESCRIPTION: _("""Applications Manager for container-based apps"""), } +class AppManagerContainerSettings(PluginSettings, plugin_info=PLUGIN_INFO): + engine: Literal["auto", "docker", "podman"] = Field( + default="auto", + description="Container engine to use", + ) + + class AppManagerDocker(AppManagerBackend): name = "docker-compose" discover_path = Path(__file__).parent def __init__(self, host): - log.info(_("Docker App Manager initialization")) - try: - self.docker_compose_path = which("docker-compose")[0] - except IndexError: - raise exceptions.NotFound( - '"docker-compose" executable not found, Docker can\'t be used with ' - "application manager" - ) + log.info(f"plugin {PLUGIN_INFO[C.PI_NAME]!r} initialization") + self.settings = G.config.get_settings(AppManagerContainerSettings) + engine = self.settings.engine + if engine == "auto": + for cmd in ("podman", "docker"): + try: + self.runner_path = which(cmd)[0] + log.info(f"Using {cmd} compose for container management") + break + except IndexError: + continue + else: + raise exceptions.NotFound( + 'Neither "podman" nor "docker" executable found, container-based ' + "applications can't be used" + ) + else: + try: + self.runner_path = which(engine)[0] + except IndexError: + raise exceptions.NotFound( + f"{engine!r} executable not found, container-based applications " + "can't be used" + ) super().__init__(host) async def start(self, app_data: dict) -> None: @@ -68,7 +92,8 @@ class AppManagerDocker(AppManagerBackend): with override_path.open("w") as f: self._am.dump(override, f) await async_process.run( - self.docker_compose_path, + self.runner_path, + "compose", "up", "--detach", path=str(working_dir), @@ -77,7 +102,8 @@ class AppManagerDocker(AppManagerBackend): async def stop(self, app_data: dict) -> None: working_dir = app_data["_instance_dir_path"] await async_process.run( - self.docker_compose_path, + self.runner_path, + "compose", "down", path=str(working_dir), ) @@ -97,7 +123,8 @@ class AppManagerDocker(AppManagerBackend): ) continue exposed_port = await async_process.run( - self.docker_compose_path, + self.runner_path, + "compose", "port", service, str(private),