mirror of
https://github.com/nix-community/home-manager
synced 2025-01-30 21:05:02 +01:00
podman: added volume, image, and build quadlets
This commit is contained in:
parent
f8ef4541bb
commit
cc9881c1fb
21 changed files with 996 additions and 32 deletions
|
@ -18,6 +18,7 @@
|
||||||
local manifestFile="${config.xdg.configHome}/podman/$2"
|
local manifestFile="${config.xdg.configHome}/podman/$2"
|
||||||
local extraListCommands="''${3:-}"
|
local extraListCommands="''${3:-}"
|
||||||
[[ $resourceType = "container" ]] && extraListCommands+=" -a"
|
[[ $resourceType = "container" ]] && extraListCommands+=" -a"
|
||||||
|
[[ $resourceType = "volume" ]] && extraListCommands+=" --filter label=nix.home-manager.preserve=false"
|
||||||
|
|
||||||
[ ! -f "$manifestFile" ] && VERBOSE_ENABLED && echo "Manifest does not exist: $manifestFile" && return 0
|
[ ! -f "$manifestFile" ] && VERBOSE_ENABLED && echo "Manifest does not exist: $manifestFile" && return 0
|
||||||
|
|
||||||
|
@ -69,19 +70,20 @@
|
||||||
commands=()
|
commands=()
|
||||||
case "$resourceType" in
|
case "$resourceType" in
|
||||||
"container")
|
"container")
|
||||||
commands+="${config.services.podman.package}/bin/podman $resourceType stop $resource"
|
commands+=("${config.services.podman.package}/bin/podman $resourceType stop $resource")
|
||||||
commands+="${config.services.podman.package}/bin/podman $resourceType rm -f $resource"
|
commands+=("${config.services.podman.package}/bin/podman $resourceType rm -f $resource")
|
||||||
;;
|
;;
|
||||||
"network")
|
"image" | "network" | "volume")
|
||||||
commands+="${config.services.podman.package}/bin/podman $resourceType rm $resource"
|
commands+=("${config.services.podman.package}/bin/podman $resourceType rm $resource")
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
for command in "''${commands[@]}"; do
|
for command in "''${commands[@]}"; do
|
||||||
command=$(echo $command | tr -d ';&|`')
|
command=$(echo $command | tr -d ';&|`')
|
||||||
DRYRUN_ENABLED && echo "Would run: $command" && continue || true
|
DRYRUN_ENABLED && echo "Would run: $command" && continue || true
|
||||||
VERBOSE_ENABLED && echo "Running: $command" || true
|
VERBOSE_ENABLED && echo "Running: $command" || true
|
||||||
if [[ "$(eval "$command")" != "$resource" ]]; then
|
if [[ "$(eval "$command")" != *"$resource" ]]; then
|
||||||
echo -e "\tCommand failed: ''${command}"
|
echo -e "\tCommand failed: ''${command}"
|
||||||
|
[ "$resourceType" == "image" ] && resourceType="ancestor"
|
||||||
usedByContainers=$(${config.services.podman.package}/bin/podman container ls -a --filter "$resourceType=$resource" --format "{{.Names}}")
|
usedByContainers=$(${config.services.podman.package}/bin/podman container ls -a --filter "$resourceType=$resource" --format "{{.Names}}")
|
||||||
echo -e "\t$resource in use by containers: $usedByContainers"
|
echo -e "\t$resource in use by containers: $usedByContainers"
|
||||||
fi
|
fi
|
||||||
|
@ -92,7 +94,7 @@
|
||||||
[[ "$@" == *"--verbose"* ]] && VERBOSE="true"
|
[[ "$@" == *"--verbose"* ]] && VERBOSE="true"
|
||||||
[[ "$@" == *"--dry-run"* ]] && DRY_RUN="true"
|
[[ "$@" == *"--dry-run"* ]] && DRY_RUN="true"
|
||||||
|
|
||||||
for type in "container" "network"; do
|
for type in "container" "image" "network" "volume"; do
|
||||||
cleanup "$type" "''${type}s.manifest"
|
cleanup "$type" "''${type}s.manifest"
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
|
|
168
modules/services/podman-linux/builds.nix
Normal file
168
modules/services/podman-linux/builds.nix
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.podman;
|
||||||
|
|
||||||
|
podman-lib = import ./podman-lib.nix { inherit lib config; };
|
||||||
|
|
||||||
|
createQuadletSource = name: buildDef:
|
||||||
|
let
|
||||||
|
buildConfig = podman-lib.deepMerge {
|
||||||
|
Build = {
|
||||||
|
AuthFile = buildDef.authFile;
|
||||||
|
Environment = buildDef.environment;
|
||||||
|
File = buildDef.file;
|
||||||
|
ImageTag = [ "homemanager/${name}" ] ++ buildDef.tags;
|
||||||
|
Label = buildDef.labels // { "nix.home-manager.managed" = true; };
|
||||||
|
PodmanArgs = buildDef.extraPodmanArgs;
|
||||||
|
SetWorkingDirectory = buildDef.workingDirectory;
|
||||||
|
TLSVerify = buildDef.tlsVerify;
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
WantedBy = optionals buildDef.autoStart [
|
||||||
|
"default.target"
|
||||||
|
"multi-user.target"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
TimeoutStartSec = 300;
|
||||||
|
RemainAfterExit = "yes";
|
||||||
|
};
|
||||||
|
Unit = { Description = buildDef.description; };
|
||||||
|
} buildDef.extraConfig;
|
||||||
|
in ''
|
||||||
|
# Automatically generated by home-manager for podman build configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# ${name}.build
|
||||||
|
${podman-lib.toQuadletIni buildConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
toQuadletInternal = name: buildDef: {
|
||||||
|
assertions = podman-lib.buildConfigAsserts name buildDef.extraConfig;
|
||||||
|
serviceName =
|
||||||
|
"podman-${name}"; # quadlet service name: 'podman-<name>-build.service
|
||||||
|
source = podman-lib.removeBlankLines (createQuadletSource name buildDef);
|
||||||
|
resourceType = "build";
|
||||||
|
};
|
||||||
|
in let
|
||||||
|
buildDefinitionType = types.submodule ({ name, ... }: {
|
||||||
|
options = {
|
||||||
|
|
||||||
|
autoStart = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description =
|
||||||
|
"Whether to start the build on boot. Requires user lingering.";
|
||||||
|
};
|
||||||
|
|
||||||
|
authFile = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = null;
|
||||||
|
description = "Path of the authentication file.";
|
||||||
|
};
|
||||||
|
|
||||||
|
description = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = "Service for build ${name}";
|
||||||
|
defaultText = "Service for build \${name}";
|
||||||
|
example = "My Build";
|
||||||
|
description = "The description of the build.";
|
||||||
|
};
|
||||||
|
|
||||||
|
environment = mkOption {
|
||||||
|
type = podman-lib.primitiveAttrs;
|
||||||
|
default = { };
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
VAR1 = "0:100";
|
||||||
|
VAR2 = true;
|
||||||
|
VAR3 = 5;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = "Environment variables to set in the build.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = podman-lib.extraConfigType;
|
||||||
|
default = { };
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
Build = {
|
||||||
|
Arch = "aarch64";
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
TimeoutStartSec = 15;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = "INI sections and values to populate the Build Quadlet.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraPodmanArgs = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "--retries 5" ];
|
||||||
|
description = "Extra arguments to pass to the podman build command.";
|
||||||
|
};
|
||||||
|
|
||||||
|
file = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = literalExpression ''
|
||||||
|
`"xdg.configFile."containerfiles/my-img/Containerfile"`
|
||||||
|
or
|
||||||
|
`"https://github.com/.../my-img/Containerfile"`
|
||||||
|
'';
|
||||||
|
description =
|
||||||
|
"Path to a Containerfile which contains instructions to build the image.";
|
||||||
|
};
|
||||||
|
|
||||||
|
tags = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Name associated with the build.
|
||||||
|
First tag will always be "homemanager/<name>".
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
labels = mkOption {
|
||||||
|
type = with types; attrsOf str;
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
app = "myapp";
|
||||||
|
some-label = "somelabel";
|
||||||
|
};
|
||||||
|
description = "The labels to apply to the build.";
|
||||||
|
};
|
||||||
|
|
||||||
|
tlsVerify = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description =
|
||||||
|
"Require HTTPS and verification of certificates when contacting registries.";
|
||||||
|
};
|
||||||
|
|
||||||
|
workingDirectory = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = null;
|
||||||
|
description = "WorkingDirectory of the systemd unit file.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
options.services.podman.builds = mkOption {
|
||||||
|
type = types.attrsOf buildDefinitionType;
|
||||||
|
default = { };
|
||||||
|
description = "Defines Podman build quadlet configurations.";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = let buildQuadlets = mapAttrsToList toQuadletInternal cfg.builds;
|
||||||
|
in mkIf cfg.enable {
|
||||||
|
services.podman.internal.quadletDefinitions = buildQuadlets;
|
||||||
|
assertions = flatten (map (build: build.assertions) buildQuadlets);
|
||||||
|
|
||||||
|
xdg.configFile."/podman/images.manifest".text =
|
||||||
|
podman-lib.generateManifestText buildQuadlets;
|
||||||
|
};
|
||||||
|
}
|
|
@ -9,19 +9,66 @@ let
|
||||||
|
|
||||||
createQuadletSource = name: containerDef:
|
createQuadletSource = name: containerDef:
|
||||||
let
|
let
|
||||||
mapHmNetworks = network:
|
makeServiceName = name: type:
|
||||||
if builtins.hasAttr network cfg.networks then
|
let
|
||||||
"podman-${network}-network.service"
|
typeName = (if lib.strings.hasSuffix "s" type then
|
||||||
else
|
(lib.strings.substring 0 (builtins.stringLength type - 1) type)
|
||||||
null;
|
else
|
||||||
|
type);
|
||||||
|
in "podman-${name}-${typeName}.service";
|
||||||
|
|
||||||
|
extractVolumeName = resource: builtins.head (builtins.split ":" resource);
|
||||||
|
|
||||||
|
standardizeResource = res:
|
||||||
|
let
|
||||||
|
lst = if lib.isList res then
|
||||||
|
res
|
||||||
|
else if res != null then
|
||||||
|
[ res ]
|
||||||
|
else
|
||||||
|
[ ];
|
||||||
|
in map extractVolumeName lst;
|
||||||
|
|
||||||
|
filterManagedResources = resource: definedResources:
|
||||||
|
builtins.filter (x: builtins.elem x definedResources)
|
||||||
|
(standardizeResource resource);
|
||||||
|
|
||||||
|
getDefinedResourceNames = type:
|
||||||
|
let
|
||||||
|
typeName =
|
||||||
|
if lib.strings.hasSuffix "s" type then type else "${type}s";
|
||||||
|
in builtins.attrNames cfg."${typeName}";
|
||||||
|
|
||||||
|
findDefinedImageType = if (builtins.elem containerDef.image
|
||||||
|
(getDefinedResourceNames "builds")) then
|
||||||
|
"builds"
|
||||||
|
else
|
||||||
|
"images";
|
||||||
|
|
||||||
|
getManagedResourceNames = type:
|
||||||
|
let
|
||||||
|
resourceType = if type == "image" then findDefinedImageType else type;
|
||||||
|
in (filterManagedResources (builtins.getAttr type containerDef)
|
||||||
|
(getDefinedResourceNames resourceType));
|
||||||
|
|
||||||
|
getServiceNames = type:
|
||||||
|
let
|
||||||
|
resourceType = if type == "image" then findDefinedImageType else type;
|
||||||
|
in map (name: makeServiceName name resourceType)
|
||||||
|
(getManagedResourceNames type);
|
||||||
|
|
||||||
finalConfig = let
|
finalConfig = let
|
||||||
managedNetworks = if lib.isList containerDef.network then
|
managedServices = builtins.concatLists
|
||||||
map mapHmNetworks containerDef.network
|
(map (type: getServiceNames type) [ "image" "network" "volumes" ]);
|
||||||
else if containerDef.network != null then
|
|
||||||
map mapHmNetworks [ containerDef.network ]
|
getActualImage =
|
||||||
else
|
if (builtins.hasAttr containerDef.image cfg.images) then
|
||||||
[ ];
|
cfg.images."${containerDef.image}".image
|
||||||
|
else if (builtins.hasAttr containerDef.image cfg.builds) then
|
||||||
|
"localhost/homemanager/${containerDef.image}"
|
||||||
|
else
|
||||||
|
containerDef.image;
|
||||||
|
|
||||||
in (podman-lib.deepMerge {
|
in (podman-lib.deepMerge {
|
||||||
Container = {
|
Container = {
|
||||||
AddCapability = containerDef.addCapabilities;
|
AddCapability = containerDef.addCapabilities;
|
||||||
|
@ -34,7 +81,7 @@ let
|
||||||
EnvironmentFile = containerDef.environmentFile;
|
EnvironmentFile = containerDef.environmentFile;
|
||||||
Exec = containerDef.exec;
|
Exec = containerDef.exec;
|
||||||
Group = containerDef.group;
|
Group = containerDef.group;
|
||||||
Image = containerDef.image;
|
Image = getActualImage;
|
||||||
IP = containerDef.ip4;
|
IP = containerDef.ip4;
|
||||||
IP6 = containerDef.ip6;
|
IP6 = containerDef.ip6;
|
||||||
Label =
|
Label =
|
||||||
|
@ -66,8 +113,8 @@ let
|
||||||
TimeoutStopSec = 30;
|
TimeoutStopSec = 30;
|
||||||
};
|
};
|
||||||
Unit = {
|
Unit = {
|
||||||
After = [ "network.target" ] ++ managedNetworks;
|
After = [ "network.target" ] ++ managedServices;
|
||||||
Requires = managedNetworks;
|
Requires = managedServices;
|
||||||
Description = (if (builtins.isString containerDef.description) then
|
Description = (if (builtins.isString containerDef.description) then
|
||||||
containerDef.description
|
containerDef.description
|
||||||
else
|
else
|
||||||
|
|
|
@ -5,8 +5,15 @@ let
|
||||||
in {
|
in {
|
||||||
meta.maintainers = with lib.hm.maintainers; [ bamhm182 n-hass ];
|
meta.maintainers = with lib.hm.maintainers; [ bamhm182 n-hass ];
|
||||||
|
|
||||||
imports =
|
imports = [
|
||||||
[ ./containers.nix ./install-quadlet.nix ./networks.nix ./services.nix ];
|
./builds.nix
|
||||||
|
./containers.nix
|
||||||
|
./images.nix
|
||||||
|
./install-quadlet.nix
|
||||||
|
./networks.nix
|
||||||
|
./services.nix
|
||||||
|
./volumes.nix
|
||||||
|
];
|
||||||
|
|
||||||
options.services.podman = {
|
options.services.podman = {
|
||||||
enable = lib.mkEnableOption "Podman, a daemonless container engine";
|
enable = lib.mkEnableOption "Podman, a daemonless container engine";
|
||||||
|
|
168
modules/services/podman-linux/images.nix
Normal file
168
modules/services/podman-linux/images.nix
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.podman;
|
||||||
|
|
||||||
|
podman-lib = import ./podman-lib.nix { inherit lib config; };
|
||||||
|
|
||||||
|
awaitPodmanUnshare = pkgs.writeShellScript "await-podman-unshare" ''
|
||||||
|
until ${cfg.package}/bin/podman unshare ${pkgs.coreutils}/bin/true; do
|
||||||
|
${pkgs.coreutils}/bin/sleep 1
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
createQuadletSource = name: imageDef:
|
||||||
|
let
|
||||||
|
credsString =
|
||||||
|
(if imageDef.username != null then imageDef.username else "")
|
||||||
|
+ (if imageDef.password != null then ":${imageDef.password}" else "");
|
||||||
|
|
||||||
|
imageConfig = podman-lib.deepMerge {
|
||||||
|
Image = {
|
||||||
|
AuthFile = imageDef.authFile;
|
||||||
|
CertDir = imageDef.certDir;
|
||||||
|
Creds = (if credsString != "" then credsString else null);
|
||||||
|
DecryptionKey = imageDef.decryptionKeyFile;
|
||||||
|
Image = imageDef.image;
|
||||||
|
ImageTag = imageDef.tag;
|
||||||
|
PodmanArgs = imageDef.extraPodmanArgs;
|
||||||
|
TLSVerify = imageDef.tlsVerify;
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
WantedBy = optionals imageDef.autoStart [
|
||||||
|
"default.target"
|
||||||
|
"multi-user.target"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
ExecStartPre = [ "${awaitPodmanUnshare}" ];
|
||||||
|
TimeoutStartSec = 300;
|
||||||
|
RemainAfterExit = "yes";
|
||||||
|
};
|
||||||
|
Unit = { Description = imageDef.description; };
|
||||||
|
} imageDef.extraConfig;
|
||||||
|
in ''
|
||||||
|
# Automatically generated by home-manager for podman image configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# ${name}.image
|
||||||
|
${podman-lib.toQuadletIni imageConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
toQuadletInternal = name: imageDef: {
|
||||||
|
assertions = podman-lib.buildConfigAsserts name imageDef.extraConfig;
|
||||||
|
serviceName =
|
||||||
|
"podman-${name}"; # quadlet service name: 'podman-<name>-image.service
|
||||||
|
source = podman-lib.removeBlankLines (createQuadletSource name imageDef);
|
||||||
|
resourceType = "image";
|
||||||
|
};
|
||||||
|
in let
|
||||||
|
imageDefinitionType = types.submodule ({ name, ... }: {
|
||||||
|
options = {
|
||||||
|
autoStart = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description =
|
||||||
|
"Whether to pull the image on boot. Requires user lingering.";
|
||||||
|
};
|
||||||
|
|
||||||
|
authFile = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = null;
|
||||||
|
description =
|
||||||
|
"Path of the authentication file used to connect to registry.";
|
||||||
|
};
|
||||||
|
|
||||||
|
certDir = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = null;
|
||||||
|
description =
|
||||||
|
"Path of certificates (*.{crt,cert,key}) used to connect to registry.";
|
||||||
|
};
|
||||||
|
|
||||||
|
decryptionKeyFile = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = null;
|
||||||
|
description = "Path to key used for decrpytion of images.";
|
||||||
|
};
|
||||||
|
|
||||||
|
description = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = "Service for image ${name}";
|
||||||
|
defaultText = "Service for image \${name}";
|
||||||
|
example = "My Image";
|
||||||
|
description = "The description of the image.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = podman-lib.extraConfigType;
|
||||||
|
default = { };
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
Image = {
|
||||||
|
ContainersConfModule = "/etc/nvd.conf";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = "INI sections and values to populate the Image Quadlet.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraPodmanArgs = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "--os=linux" ];
|
||||||
|
description =
|
||||||
|
"Extra arguments to pass to the podman image pull command.";
|
||||||
|
};
|
||||||
|
|
||||||
|
image = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "quay.io/centos/centos:latest";
|
||||||
|
description = "Image to pull.";
|
||||||
|
};
|
||||||
|
|
||||||
|
password = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "P@ssw0rd";
|
||||||
|
description =
|
||||||
|
"Password used to connect to registry. (Will be visible in nix store)";
|
||||||
|
};
|
||||||
|
|
||||||
|
tag = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "quay.io/centos/centos:latest";
|
||||||
|
description =
|
||||||
|
"FQIN of referenced Image when source is a file or directory archive.";
|
||||||
|
};
|
||||||
|
|
||||||
|
tlsVerify = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description =
|
||||||
|
"Require HTTPS and verification of certificates when contacting registries.";
|
||||||
|
};
|
||||||
|
|
||||||
|
username = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "bob";
|
||||||
|
description = "Username used to connect to registry.";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
options.services.podman.images = mkOption {
|
||||||
|
type = types.attrsOf imageDefinitionType;
|
||||||
|
default = { };
|
||||||
|
description = "Defines Podman image quadlet configurations.";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = let imageQuadlets = mapAttrsToList toQuadletInternal cfg.images;
|
||||||
|
in mkIf cfg.enable {
|
||||||
|
services.podman.internal.quadletDefinitions = imageQuadlets;
|
||||||
|
assertions = flatten (map (image: image.assertions) imageQuadlets);
|
||||||
|
};
|
||||||
|
}
|
|
@ -63,8 +63,10 @@ in {
|
||||||
buildConfigAsserts = quadletName: extraConfig:
|
buildConfigAsserts = quadletName: extraConfig:
|
||||||
let
|
let
|
||||||
configRules = {
|
configRules = {
|
||||||
|
Build = { ImageTag = (with types; listOf str); };
|
||||||
Container = { ContainerName = types.enum [ quadletName ]; };
|
Container = { ContainerName = types.enum [ quadletName ]; };
|
||||||
Network = { NetworkName = types.enum [ quadletName ]; };
|
Network = { NetworkName = types.enum [ quadletName ]; };
|
||||||
|
Volume = { VolumeName = types.enum [ quadletName ]; };
|
||||||
};
|
};
|
||||||
|
|
||||||
# Function to build assertions for a specific section and its attributes.
|
# Function to build assertions for a specific section and its attributes.
|
||||||
|
@ -83,8 +85,23 @@ in {
|
||||||
else
|
else
|
||||||
[ ];
|
[ ];
|
||||||
|
|
||||||
|
checkImageTag = extraConfig:
|
||||||
|
let
|
||||||
|
imageTags = (extraConfig.Build or { }).ImageTag or [ ];
|
||||||
|
containsRequiredTag =
|
||||||
|
builtins.elem "homemanager/${quadletName}" imageTags;
|
||||||
|
imageTagsStr = concatMapStringsSep ''" "'' toString imageTags;
|
||||||
|
in [{
|
||||||
|
assertion = imageTags == [ ] || containsRequiredTag;
|
||||||
|
message = ''
|
||||||
|
In '${quadletName}' config. Build.ImageTag: '[ "${imageTagsStr}" ]' does not contain 'homemanager/${quadletName}'.'';
|
||||||
|
}];
|
||||||
|
|
||||||
# Flatten assertions from all sections in `extraConfig`.
|
# Flatten assertions from all sections in `extraConfig`.
|
||||||
in flatten (mapAttrsToList buildSectionAsserts extraConfig);
|
in flatten (concatLists [
|
||||||
|
(mapAttrsToList buildSectionAsserts extraConfig)
|
||||||
|
(checkImageTag extraConfig)
|
||||||
|
]);
|
||||||
|
|
||||||
extraConfigType = with types;
|
extraConfigType = with types;
|
||||||
attrsOf (attrsOf (oneOf [ primitiveAttrs primitiveList primitive ]));
|
attrsOf (attrsOf (oneOf [ primitiveAttrs primitiveList primitive ]));
|
||||||
|
@ -107,8 +124,11 @@ in {
|
||||||
# specific logic for writing the unit name goes here. It should be
|
# specific logic for writing the unit name goes here. It should be
|
||||||
# identical to what `podman <resource> ls` shows
|
# identical to what `podman <resource> ls` shows
|
||||||
in {
|
in {
|
||||||
|
"build" = strippedName;
|
||||||
"container" = strippedName;
|
"container" = strippedName;
|
||||||
|
"image" = strippedName;
|
||||||
"network" = strippedName;
|
"network" = strippedName;
|
||||||
|
"volume" = strippedName;
|
||||||
}."${quadlet.resourceType}";
|
}."${quadlet.resourceType}";
|
||||||
in if allQuadletsSameType then ''
|
in if allQuadletsSameType then ''
|
||||||
${concatStringsSep "\n"
|
${concatStringsSep "\n"
|
||||||
|
|
|
@ -42,8 +42,8 @@ in {
|
||||||
"${config.home.homeDirectory}/.nix-profile/bin"
|
"${config.home.homeDirectory}/.nix-profile/bin"
|
||||||
]
|
]
|
||||||
}";
|
}";
|
||||||
ExecStart = "${pkgs.podman}/bin/podman auto-update";
|
ExecStart = "${cfg.package}/bin/podman auto-update";
|
||||||
ExecStartPost = "${pkgs.podman}/bin/podman image prune -f";
|
ExecStartPost = "${cfg.package}/bin/podman image prune -f";
|
||||||
TimeoutStartSec = "300s";
|
TimeoutStartSec = "300s";
|
||||||
TimeoutStopSec = "10s";
|
TimeoutStopSec = "10s";
|
||||||
};
|
};
|
||||||
|
|
192
modules/services/podman-linux/volumes.nix
Normal file
192
modules/services/podman-linux/volumes.nix
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.podman;
|
||||||
|
|
||||||
|
podman-lib = import ./podman-lib.nix { inherit lib config; };
|
||||||
|
|
||||||
|
awaitPodmanUnshare = pkgs.writeShellScript "await-podman-unshare" ''
|
||||||
|
until ${cfg.package}/bin/podman unshare ${pkgs.coreutils}/bin/true; do
|
||||||
|
${pkgs.coreutils}/bin/sleep 1
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
createQuadletSource = name: volumeDef:
|
||||||
|
let
|
||||||
|
volumeConfig = podman-lib.deepMerge {
|
||||||
|
Install = {
|
||||||
|
WantedBy = optionals volumeDef.autoStart [
|
||||||
|
"default.target"
|
||||||
|
"multi-user.target"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Environment = {
|
||||||
|
PATH = (builtins.concatStringsSep ":" [
|
||||||
|
"${podman-lib.newuidmapPaths}"
|
||||||
|
"${makeBinPath [ pkgs.su pkgs.coreutils ]}"
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
ExecStartPre = [ "${awaitPodmanUnshare}" ];
|
||||||
|
TimeoutStartSec = 15;
|
||||||
|
RemainAfterExit = "yes";
|
||||||
|
};
|
||||||
|
Unit = { Description = volumeDef.description; };
|
||||||
|
Volume = {
|
||||||
|
Copy = volumeDef.copy;
|
||||||
|
Device = volumeDef.device;
|
||||||
|
Driver = volumeDef.driver;
|
||||||
|
Group = volumeDef.group;
|
||||||
|
Image = volumeDef.image;
|
||||||
|
Label = volumeDef.labels // {
|
||||||
|
"nix.home-manager.managed" = true;
|
||||||
|
"nix.home-manager.preserve" = volumeDef.preserve;
|
||||||
|
};
|
||||||
|
PodmanArgs = volumeDef.extraPodmanArgs;
|
||||||
|
Type = volumeDef.type;
|
||||||
|
User = volumeDef.user;
|
||||||
|
VolumeName = name;
|
||||||
|
};
|
||||||
|
} volumeDef.extraConfig;
|
||||||
|
in ''
|
||||||
|
# Automatically generated by home-manager for podman volume configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# ${name}.volume
|
||||||
|
${podman-lib.toQuadletIni volumeConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
toQuadletInternal = name: volumeDef: {
|
||||||
|
assertions = podman-lib.buildConfigAsserts name volumeDef.extraConfig;
|
||||||
|
serviceName =
|
||||||
|
"podman-${name}"; # quadlet service name: 'podman-<name>-volume.service'
|
||||||
|
source = podman-lib.removeBlankLines (createQuadletSource name volumeDef);
|
||||||
|
resourceType = "volume";
|
||||||
|
};
|
||||||
|
|
||||||
|
in let
|
||||||
|
volumeDefinitionType = types.submodule ({ name, ... }: {
|
||||||
|
options = {
|
||||||
|
|
||||||
|
autoStart = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to create the volume on boot.";
|
||||||
|
};
|
||||||
|
|
||||||
|
copy = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description =
|
||||||
|
"Copy content of the image located at the mountpoint of the volume on first run.";
|
||||||
|
};
|
||||||
|
|
||||||
|
description = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = "Service for volume ${name}";
|
||||||
|
defaultText = "Service for volume \${name}";
|
||||||
|
example = "My Volume";
|
||||||
|
description = "The description of the volume.";
|
||||||
|
};
|
||||||
|
|
||||||
|
device = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "tmpfs";
|
||||||
|
description = "The path of a device which is mounted for the volume.";
|
||||||
|
};
|
||||||
|
|
||||||
|
driver = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "image";
|
||||||
|
description = "The volume driver to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = podman-lib.extraConfigType;
|
||||||
|
default = { };
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
Volume = {
|
||||||
|
ContainerConfModule = "/etc/nvd.conf";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = "INI sections and values to populate the Volume Quadlet.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraPodmanArgs = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "--opt copy" ];
|
||||||
|
description =
|
||||||
|
"Extra arguments to pass to the podman volume create command.";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = with types; nullOr (either int str);
|
||||||
|
default = null;
|
||||||
|
description = "The group ID owning the volume inside the container.";
|
||||||
|
};
|
||||||
|
|
||||||
|
image = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "quay.io/centos/centos:latest";
|
||||||
|
description =
|
||||||
|
"Specifies the image the volume is based on when Driver is set to the image.";
|
||||||
|
};
|
||||||
|
|
||||||
|
labels = mkOption {
|
||||||
|
type = with types; attrsOf str;
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
app = "myapp";
|
||||||
|
some-label = "somelabel";
|
||||||
|
};
|
||||||
|
description = "The labels to apply to the volume.";
|
||||||
|
};
|
||||||
|
|
||||||
|
preserve = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether the volume should be preserved if it is removed from the configuration.
|
||||||
|
Setting this to false will cause the volume to be deleted if the volume is removed from the configuration
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
type = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "tmpfs";
|
||||||
|
description =
|
||||||
|
"Filesystem type of Device. (used as -t in mount commands)";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = with types; nullOr (either int str);
|
||||||
|
default = null;
|
||||||
|
description = "The user ID owning the volume inside the container.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
options.services.podman.volumes = mkOption {
|
||||||
|
type = types.attrsOf volumeDefinitionType;
|
||||||
|
default = { };
|
||||||
|
description = "Defines Podman volume quadlet configurations.";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = let volumeQuadlets = mapAttrsToList toQuadletInternal cfg.volumes;
|
||||||
|
in mkIf cfg.enable {
|
||||||
|
services.podman.internal.quadletDefinitions = volumeQuadlets;
|
||||||
|
assertions = flatten (map (volume: volume.assertions) volumeQuadlets);
|
||||||
|
|
||||||
|
xdg.configFile."/podman/volumes.manifest".text =
|
||||||
|
podman-lib.generateManifestText volumeQuadlets;
|
||||||
|
};
|
||||||
|
}
|
30
tests/modules/services/podman-linux/build-expected.service
Normal file
30
tests/modules/services/podman-linux/build-expected.service
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator
|
||||||
|
#
|
||||||
|
# Automatically generated by home-manager for podman build configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# my-bld.build
|
||||||
|
[X-Build]
|
||||||
|
Environment=
|
||||||
|
File=/nix/store/00000000000000000000000000000000-Containerfile
|
||||||
|
ImageTag=homemanager/my-bld
|
||||||
|
Label=nix.home-manager.managed=true
|
||||||
|
TLSVerify=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
RemainAfterExit=yes
|
||||||
|
TimeoutStartSec=300
|
||||||
|
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman build --tls-verify --tag homemanager/my-bld --label nix.home-manager.managed=true --file /nix/store/00000000000000000000000000000000-Containerfile
|
||||||
|
SyslogIdentifier=%N
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Wants=podman-user-wait-network-online.service
|
||||||
|
After=podman-user-wait-network-online.service
|
||||||
|
Description=Service for build my-bld
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
SourcePath=/nix/store/00000000000000000000000000000000-home-build-podman-my-bld/quadlets/podman-my-bld.build
|
40
tests/modules/services/podman-linux/build.nix
Normal file
40
tests/modules/services/podman-linux/build.nix
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
containerFile = pkgs.writeTextFile {
|
||||||
|
name = "Containerfile";
|
||||||
|
text = ''
|
||||||
|
FROM docker.io/alpine:latest
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
services.podman = {
|
||||||
|
enable = true;
|
||||||
|
builds = {
|
||||||
|
"my-bld" = { file = "${containerFile}"; };
|
||||||
|
|
||||||
|
"my-bld-2" = {
|
||||||
|
file = "https://www.github.com/././Containerfile";
|
||||||
|
extraConfig = {
|
||||||
|
Build.ImageTag = [ "locahost/somethingelse" "localhost/anothertag" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test.asserts.assertions.expected = [
|
||||||
|
''
|
||||||
|
In 'my-bld-2' config. Build.ImageTag: '[ "locahost/somethingelse" "localhost/anothertag" ]' does not contain 'homemanager/my-bld-2'.''
|
||||||
|
];
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
configPath=home-files/.config/systemd/user
|
||||||
|
buildFile=$configPath/podman-my-bld-build.service
|
||||||
|
|
||||||
|
assertFileExists $buildFile
|
||||||
|
|
||||||
|
buildFile=$(normalizeStorePaths $buildFile)
|
||||||
|
|
||||||
|
assertFileContent $buildFile ${./build-expected.service}
|
||||||
|
'';
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
{
|
{
|
||||||
podman-configuration = ./configuration.nix;
|
podman-configuration = ./configuration.nix;
|
||||||
podman-container = ./container.nix;
|
podman-container = ./container.nix;
|
||||||
|
podman-build = ./build.nix;
|
||||||
|
podman-image = ./image.nix;
|
||||||
podman-integration = ./integration.nix;
|
podman-integration = ./integration.nix;
|
||||||
podman-manifest = ./manifest.nix;
|
podman-manifest = ./manifest.nix;
|
||||||
podman-network = ./network.nix;
|
podman-network = ./network.nix;
|
||||||
|
podman-volume = ./volume.nix;
|
||||||
}
|
}
|
||||||
|
|
28
tests/modules/services/podman-linux/image-expected.service
Normal file
28
tests/modules/services/podman-linux/image-expected.service
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator
|
||||||
|
#
|
||||||
|
# Automatically generated by home-manager for podman image configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# my-img.image
|
||||||
|
[X-Image]
|
||||||
|
Image=docker.io/alpine:latest
|
||||||
|
TLSVerify=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare
|
||||||
|
RemainAfterExit=yes
|
||||||
|
TimeoutStartSec=300
|
||||||
|
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman image pull --tls-verify docker.io/alpine:latest
|
||||||
|
SyslogIdentifier=%N
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Wants=podman-user-wait-network-online.service
|
||||||
|
After=podman-user-wait-network-online.service
|
||||||
|
Description=Service for image my-img
|
||||||
|
SourcePath=/nix/store/00000000000000000000000000000000-home-image-podman-my-img/quadlets/podman-my-img.image
|
||||||
|
RequiresMountsFor=%t/containers
|
18
tests/modules/services/podman-linux/image.nix
Normal file
18
tests/modules/services/podman-linux/image.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.podman = {
|
||||||
|
enable = true;
|
||||||
|
images = { "my-img" = { image = "docker.io/alpine:latest"; }; };
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
configPath=home-files/.config/systemd/user
|
||||||
|
imageFile=$configPath/podman-my-img-image.service
|
||||||
|
assertFileExists $imageFile
|
||||||
|
|
||||||
|
imageFile=$(normalizeStorePaths $imageFile)
|
||||||
|
|
||||||
|
assertFileContent $imageFile ${./image-expected.service}
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator
|
||||||
|
#
|
||||||
|
# Automatically generated by home-manager for podman build configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# my-bld.build
|
||||||
|
[X-Build]
|
||||||
|
Environment=
|
||||||
|
File=/nix/store/00000000000000000000000000000000-Containerfile
|
||||||
|
ImageTag=homemanager/my-bld
|
||||||
|
Label=nix.home-manager.managed=true
|
||||||
|
TLSVerify=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
RemainAfterExit=yes
|
||||||
|
TimeoutStartSec=300
|
||||||
|
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman build --tls-verify --tag homemanager/my-bld --label nix.home-manager.managed=true --file /nix/store/00000000000000000000000000000000-Containerfile
|
||||||
|
SyslogIdentifier=%N
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Wants=podman-user-wait-network-online.service
|
||||||
|
After=podman-user-wait-network-online.service
|
||||||
|
Description=Service for build my-bld
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
SourcePath=/nix/store/00000000000000000000000000000000-home-build-podman-my-bld/quadlets/podman-my-bld.build
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator
|
||||||
|
#
|
||||||
|
# Automatically generated by home-manager podman container configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# my-container-bld.container
|
||||||
|
[X-Container]
|
||||||
|
ContainerName=my-container-bld
|
||||||
|
Environment=
|
||||||
|
Image=localhost/homemanager/my-bld
|
||||||
|
Label=nix.home-manager.managed=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PATH=/run/wrappers/bin:/run/current-system/sw/bin:/home/hm-user/.nix-profile/bin
|
||||||
|
Restart=always
|
||||||
|
TimeoutStopSec=30
|
||||||
|
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||||||
|
KillMode=mixed
|
||||||
|
ExecStop=/nix/store/00000000000000000000000000000000-podman/bin/podman rm -v -f -i --cidfile=%t/%N.cid
|
||||||
|
ExecStopPost=-/nix/store/00000000000000000000000000000000-podman/bin/podman rm -v -f -i --cidfile=%t/%N.cid
|
||||||
|
Delegate=yes
|
||||||
|
Type=notify
|
||||||
|
NotifyAccess=all
|
||||||
|
SyslogIdentifier=%N
|
||||||
|
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman run --name my-container-bld --cidfile=%t/%N.cid --replace --rm --cgroups=split --sdnotify=conmon -d --label nix.home-manager.managed=true localhost/homemanager/my-bld
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Wants=podman-user-wait-network-online.service
|
||||||
|
After=podman-user-wait-network-online.service
|
||||||
|
After=network.target
|
||||||
|
After=podman-my-bld-build.service
|
||||||
|
Description=Service for container my-container-bld
|
||||||
|
Requires=podman-my-bld-build.service
|
||||||
|
SourcePath=/nix/store/00000000000000000000000000000000-home-container-podman-my-container-bld/quadlets/podman-my-container-bld.container
|
||||||
|
RequiresMountsFor=%t/containers
|
|
@ -11,6 +11,7 @@ Image=docker.io/alpine:latest
|
||||||
Label=nix.home-manager.managed=true
|
Label=nix.home-manager.managed=true
|
||||||
Network=my-net
|
Network=my-net
|
||||||
Network=externalnet
|
Network=externalnet
|
||||||
|
Volume=my-vol:/data
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=default.target
|
WantedBy=default.target
|
||||||
|
@ -28,14 +29,18 @@ Delegate=yes
|
||||||
Type=notify
|
Type=notify
|
||||||
NotifyAccess=all
|
NotifyAccess=all
|
||||||
SyslogIdentifier=%N
|
SyslogIdentifier=%N
|
||||||
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman run --name my-container --cidfile=%t/%N.cid --replace --rm --cgroups=split --network my-net --network externalnet --sdnotify=conmon -d --label nix.home-manager.managed=true docker.io/alpine:latest
|
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman run --name my-container --cidfile=%t/%N.cid --replace --rm --cgroups=split --network my-net --network externalnet --sdnotify=conmon -d -v my-vol:/data --label nix.home-manager.managed=true docker.io/alpine:latest
|
||||||
|
|
||||||
[Unit]
|
[Unit]
|
||||||
Wants=podman-user-wait-network-online.service
|
Wants=podman-user-wait-network-online.service
|
||||||
After=podman-user-wait-network-online.service
|
After=podman-user-wait-network-online.service
|
||||||
After=network.target
|
After=network.target
|
||||||
|
After=podman-my-img-image.service
|
||||||
After=podman-my-net-network.service
|
After=podman-my-net-network.service
|
||||||
|
After=podman-my-vol-volume.service
|
||||||
Description=Service for container my-container
|
Description=Service for container my-container
|
||||||
|
Requires=podman-my-img-image.service
|
||||||
Requires=podman-my-net-network.service
|
Requires=podman-my-net-network.service
|
||||||
|
Requires=podman-my-vol-volume.service
|
||||||
SourcePath=/nix/store/00000000000000000000000000000000-home-container-podman-my-container/quadlets/podman-my-container.container
|
SourcePath=/nix/store/00000000000000000000000000000000-home-container-podman-my-container/quadlets/podman-my-container.container
|
||||||
RequiresMountsFor=%t/containers
|
RequiresMountsFor=%t/containers
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator
|
||||||
|
#
|
||||||
|
# Automatically generated by home-manager for podman image configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# my-img.image
|
||||||
|
[X-Image]
|
||||||
|
Image=docker.io/alpine:latest
|
||||||
|
TLSVerify=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare
|
||||||
|
RemainAfterExit=yes
|
||||||
|
TimeoutStartSec=300
|
||||||
|
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman image pull --tls-verify docker.io/alpine:latest
|
||||||
|
SyslogIdentifier=%N
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Wants=podman-user-wait-network-online.service
|
||||||
|
After=podman-user-wait-network-online.service
|
||||||
|
Description=Service for image my-img
|
||||||
|
SourcePath=/nix/store/00000000000000000000000000000000-home-image-podman-my-img/quadlets/podman-my-img.image
|
||||||
|
RequiresMountsFor=%t/containers
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator
|
||||||
|
#
|
||||||
|
# Automatically generated by home-manager for podman volume configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# my-vol.volume
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PATH=/run/wrappers/bin:/usr/bin:/bin:/usr/sbin:/sbin:/nix/store/00000000000000000000000000000000-shadow/bin:/nix/store/00000000000000000000000000000000-coreutils/bin
|
||||||
|
ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare
|
||||||
|
RemainAfterExit=yes
|
||||||
|
TimeoutStartSec=15
|
||||||
|
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman volume create --ignore --opt copy --opt device=tmpfs --opt type=tmpfs --label nix.home-manager.managed=true --label nix.home-manager.preserve=false my-vol
|
||||||
|
SyslogIdentifier=%N
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Wants=podman-user-wait-network-online.service
|
||||||
|
After=podman-user-wait-network-online.service
|
||||||
|
Description=Service for volume my-vol
|
||||||
|
SourcePath=/nix/store/00000000000000000000000000000000-home-volume-podman-my-vol/quadlets/podman-my-vol.volume
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
|
||||||
|
[X-Volume]
|
||||||
|
Copy=true
|
||||||
|
Device=tmpfs
|
||||||
|
Label=nix.home-manager.managed=true
|
||||||
|
Label=nix.home-manager.preserve=false
|
||||||
|
Type=tmpfs
|
||||||
|
VolumeName=my-vol
|
|
@ -1,29 +1,64 @@
|
||||||
{ ... }:
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
{
|
containerFile = pkgs.writeTextFile {
|
||||||
|
name = "Containerfile";
|
||||||
|
text = ''
|
||||||
|
FROM docker.io/alpine:latest
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in {
|
||||||
services.podman = {
|
services.podman = {
|
||||||
enable = true;
|
enable = true;
|
||||||
containers."my-container" = {
|
builds."my-bld" = { file = "${containerFile}"; };
|
||||||
image = "docker.io/alpine:latest";
|
containers = {
|
||||||
network = [ "my-net" "externalnet" ];
|
"my-container" = {
|
||||||
|
image = "my-img";
|
||||||
|
network = [ "my-net" "externalnet" ];
|
||||||
|
volumes = [ "my-vol:/data" ];
|
||||||
|
};
|
||||||
|
"my-container-bld" = { image = "my-bld"; };
|
||||||
};
|
};
|
||||||
|
images."my-img" = { image = "docker.io/alpine:latest"; };
|
||||||
networks."my-net" = {
|
networks."my-net" = {
|
||||||
gateway = "192.168.123.1";
|
gateway = "192.168.123.1";
|
||||||
subnet = "192.168.123.0/24";
|
subnet = "192.168.123.0/24";
|
||||||
};
|
};
|
||||||
|
volumes."my-vol" = {
|
||||||
|
device = "tmpfs";
|
||||||
|
preserve = false;
|
||||||
|
type = "tmpfs";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
nmt.script = ''
|
nmt.script = ''
|
||||||
configPath=home-files/.config/systemd/user
|
configPath=home-files/.config/systemd/user
|
||||||
|
buildFile=$configPath/podman-my-bld-build.service
|
||||||
containerFile=$configPath/podman-my-container.service
|
containerFile=$configPath/podman-my-container.service
|
||||||
|
containerBldFile=$configPath/podman-my-container-bld.service
|
||||||
|
imageFile=$configPath/podman-my-img-image.service
|
||||||
networkFile=$configPath/podman-my-net-network.service
|
networkFile=$configPath/podman-my-net-network.service
|
||||||
|
volumeFile=$configPath/podman-my-vol-volume.service
|
||||||
|
assertFileExists $buildFile
|
||||||
assertFileExists $containerFile
|
assertFileExists $containerFile
|
||||||
|
assertFileExists $containerBldFile
|
||||||
|
assertFileExists $imageFile
|
||||||
assertFileExists $networkFile
|
assertFileExists $networkFile
|
||||||
|
assertFileExists $volumeFile
|
||||||
|
|
||||||
|
buildFile=$(normalizeStorePaths $buildFile)
|
||||||
containerFile=$(normalizeStorePaths $containerFile)
|
containerFile=$(normalizeStorePaths $containerFile)
|
||||||
|
containerBldFile=$(normalizeStorePaths $containerBldFile)
|
||||||
|
imageFile=$(normalizeStorePaths $imageFile)
|
||||||
networkFile=$(normalizeStorePaths $networkFile)
|
networkFile=$(normalizeStorePaths $networkFile)
|
||||||
|
volumeFile=$(normalizeStorePaths $volumeFile)
|
||||||
|
|
||||||
|
assertFileContent $buildFile ${./integration-build-expected.service}
|
||||||
assertFileContent $containerFile ${./integration-container-expected.service}
|
assertFileContent $containerFile ${./integration-container-expected.service}
|
||||||
|
assertFileContent $containerBldFile ${
|
||||||
|
./integration-container-bld-expected.service
|
||||||
|
}
|
||||||
|
assertFileContent $imageFile ${./integration-image-expected.service}
|
||||||
assertFileContent $networkFile ${./integration-network-expected.service}
|
assertFileContent $networkFile ${./integration-network-expected.service}
|
||||||
|
assertFileContent $volumeFile ${./integration-volume-expected.service}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
36
tests/modules/services/podman-linux/volume-expected.service
Normal file
36
tests/modules/services/podman-linux/volume-expected.service
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# Automatically generated by /nix/store/00000000000000000000000000000000-podman/lib/systemd/user-generators/podman-user-generator
|
||||||
|
#
|
||||||
|
# Automatically generated by home-manager for podman volume configuration
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
#
|
||||||
|
# my-vol.volume
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PATH=/run/wrappers/bin:/usr/bin:/bin:/usr/sbin:/sbin:/nix/store/00000000000000000000000000000000-shadow/bin:/nix/store/00000000000000000000000000000000-coreutils/bin
|
||||||
|
ExecStartPre=/nix/store/00000000000000000000000000000000-await-podman-unshare
|
||||||
|
RemainAfterExit=yes
|
||||||
|
TimeoutStartSec=15
|
||||||
|
ExecStart=/nix/store/00000000000000000000000000000000-podman/bin/podman volume create --ignore --opt copy --opt device=tmpfs --opt type=tmpfs --opt o=uid=1000,gid=1000 --label nix.home-manager.managed=true --label nix.home-manager.preserve=true --module=/etc/nvd.conf my-vol
|
||||||
|
SyslogIdentifier=%N
|
||||||
|
Type=oneshot
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Wants=podman-user-wait-network-online.service
|
||||||
|
After=podman-user-wait-network-online.service
|
||||||
|
Description=Service for volume my-vol
|
||||||
|
SourcePath=/nix/store/00000000000000000000000000000000-home-volume-podman-my-vol/quadlets/podman-my-vol.volume
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
|
||||||
|
[X-Volume]
|
||||||
|
Copy=true
|
||||||
|
Device=tmpfs
|
||||||
|
Group=1000
|
||||||
|
Label=nix.home-manager.managed=true
|
||||||
|
Label=nix.home-manager.preserve=true
|
||||||
|
PodmanArgs=--module=/etc/nvd.conf
|
||||||
|
Type=tmpfs
|
||||||
|
User=1000
|
||||||
|
VolumeName=my-vol
|
35
tests/modules/services/podman-linux/volume.nix
Normal file
35
tests/modules/services/podman-linux/volume.nix
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.podman = {
|
||||||
|
enable = true;
|
||||||
|
volumes = {
|
||||||
|
"my-vol" = {
|
||||||
|
device = "tmpfs";
|
||||||
|
extraConfig = { Volume = { User = 1000; }; };
|
||||||
|
extraPodmanArgs = [ "--module=/etc/nvd.conf" ];
|
||||||
|
group = 1000;
|
||||||
|
type = "tmpfs";
|
||||||
|
};
|
||||||
|
|
||||||
|
"my-vol-2" = {
|
||||||
|
extraConfig = { Volume = { VolumeName = "some-other-volume-name"; }; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test.asserts.assertions.expected = [
|
||||||
|
''
|
||||||
|
In 'my-vol-2' config. Volume.VolumeName: 'some-other-volume-name' does not match expected type: value "my-vol-2" (singular enum)''
|
||||||
|
];
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
configPath=home-files/.config/systemd/user
|
||||||
|
volumeFile=$configPath/podman-my-vol-volume.service
|
||||||
|
assertFileExists $volumeFile
|
||||||
|
|
||||||
|
volumeFile=$(normalizeStorePaths $volumeFile)
|
||||||
|
|
||||||
|
assertFileContent $volumeFile ${./volume-expected.service}
|
||||||
|
'';
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue