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).
This commit is contained in:
Goffi 2026-07-19 15:04:09 +02:00
commit 6119c37c0f

View file

@ -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),