1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
{ 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
# empty files to mount over with host's version
touch $out/etc/resolv.conf $out/etc/machine-id
# 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}
'';
}
|