{
lib,
pkgs,
config,
...
}: let
cfg = config.dr460nixed.compose-runner;
in {
options.dr460nixed.compose-runner = lib.mkOption (with lib; {
type = types.attrsOf (types.submodule {
options = {
source = mkOption {
default = null;
description = "Folder containing a compose file.";
type = types.path;
};
envfile = mkOption {
default = null;
description = "Direct path to a valid .env file";
type = types.nullOr types.path;
};
};
});
default = {};
});
config = {
systemd.services =
lib.mapAttrs'
(name: value:
lib.nameValuePair ("compose-runner-" + name) (
let
output = derivation {
builder = pkgs.writeShellScript "build" ''
PATH="${pkgs.rsync}/bin:${pkgs.coreutils}/bin:${pkgs.gnused}/bin"
set -e
mkdir "$out"
sed -r 's/(^\s+restart:\s*)(unless-stopped|always)(\s*($|#))/\1on-failure\3/g' "$src/compose.yml" > "$out/compose.yml"
rsync -a "$src/" "$out"
'';
name = "compose-runner-" + name;
src = value.source;
inherit (pkgs.hostPlatform) system;
};
statepath = "/var/compose-runner/${name}";
in {
description = "Compose runner for ${name}";
path = with pkgs; [rsync docker-compose podman bash];
serviceConfig = {
ExecStart = pkgs.writeShellScript ("execstart-compose-runner-" + name) ''
set -e
mkdir -p "${statepath}"
rsync -a --no-owner --size-only "${output}/" "${statepath}"
${lib.optionalString (value.envfile != null) ''
cp "${value.envfile}" "${statepath}/.env"
chmod 600 "${statepath}/.env"
''}
cd "${statepath}"
docker-compose up
'';
ExecStopPost = pkgs.writeShellScript ("execstop-compose-runner-" + name) ''
set -e
cd "${statepath}"
docker-compose down
'';
};
unitConfig = {
After = "podman.socket";
Requisite = "podman.socket";
StopPropagatedFrom = "podman.socket";
};
wantedBy = ["multi-user.target"];
}
))
cfg;
environment.systemPackages = lib.mkIf (cfg != {}) [pkgs.docker-compose];
virtualisation.podman.enable = lib.mkIf (cfg != {}) true;
networking.firewall.interfaces."podman1".allowedUDPPorts = lib.mkIf (cfg != {}) [53];
virtualisation.podman.defaultNetwork.settings = {dns_enabled = true;};
};
}