query
On this page

portableService

pkgs.portableService

Functor
Docs pulled from | This Revision | about 2 hours ago


Create a systemd portable service image https://systemd.io/PORTABLE_SERVICES/

Examples

pkgs.portableService {
  pname = "demo";
  version = "1.0";
  units = [ demo-service demo-socket ];
}

Noogle detected

This is a Functor

Learn about functors

Implementation

The following is the current implementation of this function.

{
  # 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}
  '';
}