Commit 88d736df authored by Lorenz Leutgeb's avatar Lorenz Leutgeb
Browse files

nixos/benchexec: init

parent 0e2c4474
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@
  ./programs/bash/ls-colors.nix
  ./programs/bash/undistract-me.nix
  ./programs/bcc.nix
  ./programs/benchexec.nix
  ./programs/browserpass.nix
  ./programs/calls.nix
  ./programs/captive-browser.nix
+98 −0
Original line number Diff line number Diff line
{ lib
, pkgs
, config
, options
, ...
}:
let
  cfg = config.programs.benchexec;
  opt = options.programs.benchexec;

  filterUsers = x:
    if builtins.isString x then config.users.users ? ${x} else
    if builtins.isInt    x then x                         else
    throw "filterUsers expects string (username) or int (UID)";

  uid = x:
    if builtins.isString x then config.users.users.${x}.uid else
    if builtins.isInt    x then x                           else
    throw "uid expects string (username) or int (UID)";
in
{
  options.programs.benchexec = {
    enable = lib.mkEnableOption "BenchExec";
    package = lib.options.mkPackageOption pkgs "benchexec" { };

    users = lib.options.mkOption {
      type = with lib.types; listOf (either str int);
      description = ''
        Users that intend to use BenchExec.
        Provide usernames of users that are configured via {option}`${options.users.users}` as string,
        and UIDs of "mutable users" as integers.
        Control group delegation will be configured via systemd.
        For more information, see <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#setting-up-cgroups>.
      '';
      default = [ ];
      example = lib.literalExpression ''
        [
          "alice" # username of a user configured via ${options.users.users}
          1007    # UID of a mutable user
        ]
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    assertions = (map
      (user: {
        assertion = config.users.users ? ${user};
        message = ''
          The user '${user}' intends to use BenchExec (via `${opt.users}`), but is not configured via `${options.users.users}`.
        '';
      })
      (builtins.filter builtins.isString cfg.users)
    ) ++ (map
      (id: {
        assertion = config.users.mutableUsers;
        message = ''
          The user with UID '${id}' intends to use BenchExec (via `${opt.users}`), but mutable users are disabled via `${options.users.mutableUsers}`.
        '';
      })
      (builtins.filter builtins.isInt cfg.users)
    ) ++ [
      {
        assertion = config.systemd.enableUnifiedCgroupHierarchy == true;
        message = ''
          The BenchExec module `${opt.enable}` only supports control groups 2 (`${options.systemd.enableUnifiedCgroupHierarchy} = true`).
        '';
      }
    ];

    environment.systemPackages = [ cfg.package ];

    # See <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#setting-up-cgroups>.
    systemd.services = builtins.listToAttrs (map
      (user: {
        name = "user@${builtins.toString (uid user)}";
        value = {
          serviceConfig.Delegate = "yes";
          overrideStrategy = "asDropin";
        };
      })
      (builtins.filter filterUsers cfg.users));

    # See <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#requirements>.
    virtualisation.lxc.lxcfs.enable = lib.mkDefault true;

    # See <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#requirements>.
    programs = {
      cpu-energy-meter.enable = lib.mkDefault true;
      pqos-wrapper.enable = lib.mkDefault true;
    };

    # See <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#kernel-requirements>.
    security.unprivilegedUsernsClone = true;
  };

  meta.maintainers = with lib.maintainers; [ lorenzleutgeb ];
}
+1 −0
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ in {
  bcachefs = handleTestOn ["x86_64-linux" "aarch64-linux"] ./bcachefs.nix {};
  beanstalkd = handleTest ./beanstalkd.nix {};
  bees = handleTest ./bees.nix {};
  benchexec = handleTest ./benchexec.nix {};
  binary-cache = handleTest ./binary-cache.nix {};
  bind = handleTest ./bind.nix {};
  bird = handleTest ./bird.nix {};
+54 −0
Original line number Diff line number Diff line
import ./make-test-python.nix ({ pkgs, lib, ... }:
let
  user = "alice";
in
{
  name = "benchexec";

  nodes.benchexec = {
    imports = [ ./common/user-account.nix ];

    programs.benchexec = {
      enable = true;
      users = [ user ];
    };
  };

  testScript = { ... }:
    let
      runexec = lib.getExe' pkgs.benchexec "runexec";
      echo = builtins.toString pkgs.benchexec;
      test = lib.getExe (pkgs.writeShellApplication rec {
        name = "test";
        meta.mainProgram = name;
        text = "echo '${echo}'";
      });
      wd = "/tmp";
      stdout = "${wd}/runexec.out";
      stderr = "${wd}/runexec.err";
    in
    ''
      start_all()
      machine.wait_for_unit("multi-user.target")
      benchexec.succeed(''''\
          systemd-run \
            --property='StandardOutput=file:${stdout}' \
            --property='StandardError=file:${stderr}' \
            --unit=runexec --wait --user --machine='${user}@' \
            --working-directory ${wd} \
          '${runexec}' \
            --debug \
            --read-only-dir / \
            --hidden-dir /home \
            '${test}' \
      '''')
      benchexec.succeed("grep -s '${echo}' ${wd}/output.log")
      benchexec.succeed("test \"$(grep -Ec '((start|wall|cpu)time|memory)=' ${stdout})\" = 4")
      benchexec.succeed("! grep -E '(WARNING|ERROR)' ${stderr}")
    '';

  interactive.nodes.benchexec.services.kmscon = {
    enable = true;
    fonts = [{ name = "Fira Code"; package = pkgs.fira-code; }];
  };
})