2024-05-02 00:46:19 +00:00
|
|
|
{
|
|
|
|
pkgs,
|
|
|
|
lib,
|
|
|
|
stdenv,
|
|
|
|
}:
|
|
|
|
/*
|
|
|
|
Create a systemd portable service image
|
|
|
|
https://systemd.io/PORTABLE_SERVICES/
|
|
|
|
|
|
|
|
Example:
|
|
|
|
pkgs.portableService {
|
|
|
|
pname = "demo";
|
|
|
|
version = "1.0";
|
|
|
|
units = [ demo-service demo-socket ];
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
# The name and version of the portable service. The resulting image will be
|
|
|
|
# created in result/$pname_$version.raw
|
|
|
|
pname,
|
|
|
|
version,
|
|
|
|
|
|
|
|
# Units is a list of derivations for systemd unit files. Those files will be
|
|
|
|
# copied to /etc/systemd/system in the resulting image. Note that the unit
|
|
|
|
# names must be prefixed with the name of the portable service.
|
|
|
|
units,
|
|
|
|
|
|
|
|
# Basic info about the portable service image, used for the generated
|
|
|
|
# /etc/os-release
|
|
|
|
description ? null,
|
|
|
|
homepage ? null,
|
|
|
|
|
|
|
|
# A list of attribute sets {object, symlink}. Symlinks will be created
|
|
|
|
# in the root filesystem of the image to objects in the nix store.
|
|
|
|
symlinks ? [ ],
|
|
|
|
|
|
|
|
# A list of additional derivations to be included in the image as-is.
|
|
|
|
contents ? [ ],
|
|
|
|
|
|
|
|
# mksquashfs options
|
|
|
|
squashfsTools ? pkgs.squashfsTools,
|
|
|
|
squash-compression ? "xz -Xdict-size 100%",
|
|
|
|
squash-block-size ? "1M",
|
|
|
|
}:
|
|
|
|
|
|
|
|
let
|
|
|
|
filterNull = lib.filterAttrs (_: v: v != null);
|
|
|
|
envFileGenerator = lib.generators.toKeyValue { };
|
|
|
|
|
|
|
|
rootFsScaffold =
|
|
|
|
let
|
|
|
|
os-release-params = {
|
|
|
|
PORTABLE_ID = pname;
|
|
|
|
PORTABLE_PRETTY_NAME = description;
|
|
|
|
HOME_URL = homepage;
|
|
|
|
ID = "nixos";
|
|
|
|
PRETTY_NAME = "NixOS";
|
|
|
|
BUILD_ID = "rolling";
|
|
|
|
};
|
|
|
|
os-release = pkgs.writeText "os-release" (envFileGenerator (filterNull os-release-params));
|
|
|
|
|
|
|
|
in
|
|
|
|
stdenv.mkDerivation {
|
|
|
|
pname = "root-fs-scaffold";
|
|
|
|
inherit version;
|
|
|
|
|
|
|
|
buildCommand =
|
|
|
|
''
|
|
|
|
# scaffold a file system layout
|
|
|
|
mkdir -p $out/etc/systemd/system $out/proc $out/sys $out/dev $out/run \
|
|
|
|
$out/tmp $out/var/tmp $out/var/lib $out/var/cache $out/var/log
|
2024-06-30 08:16:52 +00:00
|
|
|
|
2024-05-02 00:46:19 +00:00
|
|
|
# empty files to mount over with host's version
|
|
|
|
touch $out/etc/resolv.conf $out/etc/machine-id
|
2024-06-30 08:16:52 +00:00
|
|
|
|
2024-05-02 00:46:19 +00:00
|
|
|
# required for portable services
|
|
|
|
cp ${os-release} $out/etc/os-release
|
|
|
|
''
|
|
|
|
# units **must** be copied to /etc/systemd/system/
|
|
|
|
+ (lib.concatMapStringsSep "\n" (u: "cp ${u} $out/etc/systemd/system/${u.name};") units)
|
|
|
|
+ (lib.concatMapStringsSep "\n" (
|
|
|
|
{ object, symlink }:
|
|
|
|
''
|
|
|
|
mkdir -p $(dirname $out/${symlink});
|
|
|
|
ln -s ${object} $out/${symlink};
|
|
|
|
''
|
|
|
|
) symlinks);
|
|
|
|
};
|
|
|
|
in
|
|
|
|
|
|
|
|
assert lib.assertMsg (lib.all (
|
|
|
|
u: lib.hasPrefix pname u.name
|
|
|
|
) units) "Unit names must be prefixed with the service name";
|
|
|
|
|
|
|
|
stdenv.mkDerivation {
|
|
|
|
pname = "${pname}-img";
|
|
|
|
inherit version;
|
|
|
|
|
|
|
|
nativeBuildInputs = [ squashfsTools ];
|
|
|
|
closureInfo = pkgs.closureInfo { rootPaths = [ rootFsScaffold ] ++ contents; };
|
|
|
|
|
|
|
|
buildCommand = ''
|
|
|
|
mkdir -p nix/store
|
|
|
|
for i in $(< $closureInfo/store-paths); do
|
|
|
|
cp -a "$i" "''${i:1}"
|
|
|
|
done
|
|
|
|
|
|
|
|
mkdir -p $out
|
|
|
|
# the '.raw' suffix is mandatory by the portable service spec
|
|
|
|
mksquashfs nix ${rootFsScaffold}/* $out/"${pname}_${version}.raw" \
|
|
|
|
-quiet -noappend \
|
|
|
|
-exit-on-error \
|
|
|
|
-keep-as-directory \
|
|
|
|
-all-root -root-mode 755 \
|
|
|
|
-b ${squash-block-size} -comp ${squash-compression}
|
|
|
|
'';
|
|
|
|
}
|