portableService: tooling to create portable service images

see https://systemd.io/PORTABLE_SERVICES/ about the definition of
portable services. this tooling is analogous to the `pkgs.dockerTools.buildImage`
tooling and is called `pkgs.portableService`.

systemd (since version 239) supports a concept of “Portable Services”.
“Portable Services” are a delivery method for system services that uses
two specific features of container management:

* Applications are bundled. I.e. multiple services, their binaries and all
their dependencies are packaged in an image, and are run directly from it.
* Stricter default security policies, i.e. sandboxing of applications.

The primary tool for interacting with Portable Services is portablectl,
and they are managed by the systemd-portabled service.

This function will create a squashfs raw image in `result/$pname_$version.raw`
that has the required files by the portable services spec, and all the
dependencies for the running program in the nix store.

+113
+111
pkgs/build-support/portable-service/default.nix
··· 1 + { pkgs, lib, stdenv }: 2 + /* 3 + Create a systemd portable service image 4 + https://systemd.io/PORTABLE_SERVICES/ 5 + 6 + Example: 7 + pkgs.portableService { 8 + pname = "demo"; 9 + version = "1.0"; 10 + units = [ demo-service demo-socket ]; 11 + } 12 + */ 13 + { 14 + # The name and version of the portable service. The resulting image will be 15 + # created in result/$pname_$version.raw 16 + pname 17 + , version 18 + 19 + # Units is a list of derivations for systemd unit files. Those files will be 20 + # copied to /etc/systemd/system in the resulting image. Note that the unit 21 + # names must be prefixed with the name of the portable service. 22 + , units 23 + 24 + # Basic info about the portable service image, used for the generated 25 + # /etc/os-release 26 + , description ? null 27 + , homepage ? null 28 + 29 + # A list of attribute sets {object, symlink}. Symlinks will be created 30 + # in the root filesystem of the image to objects in the nix store. 31 + , symlinks ? [ ] 32 + 33 + # A list of additional derivations to be included in the image as-is. 34 + , contents ? [ ] 35 + 36 + # mksquashfs options 37 + , squashfsTools ? pkgs.squashfsTools 38 + , squash-compression ? "xz -Xdict-size 100%" 39 + , squash-block-size ? "1M" 40 + }: 41 + 42 + let 43 + filterNull = lib.filterAttrs (_: v: v != null); 44 + envFileGenerator = lib.generators.toKeyValue { }; 45 + 46 + rootFsScaffold = 47 + let 48 + os-release-params = { 49 + PORTABLE_ID = pname; 50 + PORTABLE_PRETTY_NAME = description; 51 + HOME_URL = homepage; 52 + ID = "nixos"; 53 + PRETTY_NAME = "NixOS"; 54 + BUILD_ID = "rolling"; 55 + }; 56 + os-release = pkgs.writeText "os-release" 57 + (envFileGenerator (filterNull os-release-params)); 58 + 59 + in 60 + stdenv.mkDerivation { 61 + pname = "root-fs-scaffold"; 62 + inherit version; 63 + 64 + buildCommand = '' 65 + # scaffold a file system layout 66 + mkdir -p $out/etc/systemd/system $out/proc $out/sys $out/dev $out/run \ 67 + $out/tmp $out/var/tmp $out/var/lib $out/var/cache $out/var/log 68 + 69 + # empty files to mount over with host's version 70 + touch $out/etc/resolv.conf $out/etc/machine-id 71 + 72 + # required for portable services 73 + cp ${os-release} $out/etc/os-release 74 + '' 75 + # units **must** be copied to /etc/systemd/system/ 76 + + (lib.concatMapStringsSep "\n" (u: "cp ${u} $out/etc/systemd/system/${u.name};") units) 77 + + (lib.concatMapStringsSep "\n" 78 + ({ object, symlink }: '' 79 + mkdir -p $(dirname $out/${symlink}); 80 + ln -s ${object} $out/${symlink}; 81 + '') 82 + symlinks) 83 + ; 84 + }; 85 + in 86 + 87 + assert lib.assertMsg (lib.all (u: lib.hasPrefix pname u.name) units) "Unit names must be prefixed with the service name"; 88 + 89 + stdenv.mkDerivation { 90 + pname = "${pname}-img"; 91 + inherit version; 92 + 93 + nativeBuildInputs = [ squashfsTools ]; 94 + closureInfo = pkgs.closureInfo { rootPaths = [ rootFsScaffold ] ++ contents; }; 95 + 96 + buildCommand = '' 97 + mkdir -p nix/store 98 + for i in $(< $closureInfo/store-paths); do 99 + cp -a "$i" "''${i:1}" 100 + done 101 + 102 + mkdir -p $out 103 + # the '.raw' suffix is mandatory by the portable service spec 104 + mksquashfs nix ${rootFsScaffold}/* $out/"${pname}_${version}.raw" \ 105 + -quiet -noappend \ 106 + -exit-on-error \ 107 + -keep-as-directory \ 108 + -all-root -root-mode 755 \ 109 + -b ${squash-block-size} -comp ${squash-compression} 110 + ''; 111 + }
+2
pkgs/top-level/all-packages.nix
··· 17050 17050 }; 17051 17051 })); 17052 17052 17053 + portableService = callPackage ../build-support/portable-service { }; 17054 + 17053 17055 polar = callPackage ../tools/misc/polar { }; 17054 17056 17055 17057 inherit (nodePackages) postcss-cli;